form error style

This commit is contained in:
Hannaeko 2025-06-18 22:45:40 +01:00
parent a4e0c9a244
commit 3751827779
6 changed files with 97 additions and 14 deletions

View file

@ -206,9 +206,46 @@ textarea {
.form-input { .form-input {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: .5rem;
flex-grow: 1;
margin-top: 1rem; margin-top: 1rem;
label {
margin-bottom: .5rem;
}
.error {
background-color: #a20000;
color: #fff;
margin: 0;
margin-top: .15rem;
padding: .25rem;
display: inline-block;
}
.error::before {
content: '';
width: 1em;
height: 1em;
background-color: #fff;
mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='white' class='bi bi-exclamation-triangle' viewBox='0 0 16 16'><path d='M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.15.15 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.2.2 0 0 1-.054.06.1.1 0 0 1-.066.017H1.146a.1.1 0 0 1-.066-.017.2.2 0 0 1-.054-.06.18.18 0 0 1 .002-.183L7.884 2.073a.15.15 0 0 1 .054-.057m1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767z'/><path d='M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0M7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0z'/></svg>");
display: inline-block;
mask-repeat: no-repeat;
mask-position: center;
mask-size: cover;
margin-right: .25rem;
margin-bottom: -.05em;
}
.help {
margin: 0;
margin-bottom: .15rem;
font-style: oblique;
}
input,
textarea {
padding: .25rem;
margin: 0;
}
} }
.form-row { .form-row {
@ -220,6 +257,7 @@ textarea {
.form-input { .form-input {
margin-top: 0; margin-top: 0;
flex: 1;
} }
} }

View file

@ -43,11 +43,18 @@ record-input-name =
button-create-record-next-step = Next step button-create-record-next-step = Next step
record-input-ttl =
.input-label = Duration in cache (TTL), in seconds
.help = Optional, default to 1 hour (3600 secondes)
.error-input-type_error = The duration in cache must be a positif integer number.
.error-record-parse-number = The duration in cache must be a positif integer number.
record-input-addresses = record-input-addresses =
.input-label = IP address #{ $index } .input-label = IP address #{ $index }
.error-record-parse-ip = Unexpected IP address format. The IP address .error-record-parse-ip = Unexpected IP address format. The IP address
should be either an IPv4 address, like <code>198.51.100.3</code>, or an IPv6 should be either an IPv4 address, like <code>198.51.100.3</code>, or an IPv6
address, like <code>2001:db8:cafe:bc68::2</code>. address, like <code>2001:db8:cafe:bc68::2</code>.
.error-input-missing_value = At least one IP addresses is required.
button-add-address = Add an other address button-add-address = Add an other address

View file

@ -11,14 +11,14 @@ zone-content-section-mail-header = Courriel
zone-content-section-services-header = Services zone-content-section-services-header = Services
zone-content-section-general-header = Général zone-content-section-general-header = Général
zone-content-record-type-address = zone-content-record-type-addresses =
.type-name = Adresses IP .type-name = Adresses IP
zone-content-record-type-mailserver = zone-content-record-type-mailservers =
.type-name = Serveurs de courriel .type-name = Serveurs de courriel
.data-preference = Préférence : { $preference } .data-preference = Préférence : { $preference }
zone-content-record-type-nameserver = zone-content-record-type-nameservers =
.type-name = Serveurs de noms .type-name = Serveurs de noms
zone-content-record-type-service = zone-content-record-type-service =
@ -43,11 +43,18 @@ record-input-name =
button-create-record-next-step = Étape suivante button-create-record-next-step = Étape suivante
record-input-ttl =
.input-label = Durée dans le cache (TTL), en seconde
.help = Optionnel, 1 heure par défaut (3600 secondes)
.error-input-type_error = La durée dans le cache doit être un nombre entier positif.
.error-record-parse-number = La durée dans le cache doit être un nombre entier positif.
record-input-addresses = record-input-addresses =
.input-label = Adresse IP #{ $index } .input-label = Adresse IP #{ $index }
.error-record-parse-ip = Format dadresse IP inconnu. Ladresse IP doit être .error-record-parse-ip = Format dadresse IP inconnu. Ladresse IP doit être
soit une adresse IPv4, comme <code>198.51.100.3</code>, soit une adresse IPv6, soit une adresse IPv4, comme <code>198.51.100.3</code>, soit une adresse IPv6,
comme <code>2001:db8:cafe:bc68::2</code>. comme <code>2001:db8:cafe:bc68::2</code>.
.error-input-missing_value = Au moins une adresse IP est requise.
button-add-address = Ajouter une autre adresse button-add-address = Ajouter une autre adresse

View file

@ -171,6 +171,7 @@ pub struct ExtractLanguageService<S> {
impl<S> ExtractLanguageService<S> { impl<S> ExtractLanguageService<S> {
// https://httpwg.org/specs/rfc9110.html#field.accept-language // https://httpwg.org/specs/rfc9110.html#field.accept-language
// TODO: Test language selection for compound locales (eg. fr-FR)
pub fn language_from_header(&self, headers: &axum::http::HeaderMap) -> LanguageIdentifier { pub fn language_from_header(&self, headers: &axum::http::HeaderMap) -> LanguageIdentifier {
let lang_preferences = headers let lang_preferences = headers
.get("Accept-Language") .get("Accept-Language")

View file

@ -5,10 +5,10 @@
{% block main %} {% block main %}
<h1>{{ tr(msg="record-creation-process-heading", zone=current_zone, lang=lang) }}</h1> <h1>{{ tr(msg="record-creation-process-heading", zone=current_zone, lang=lang) }}</h1>
<!-- {{ errors | json_encode(pretty=true) }} -->
{% set domain_error = errors | get(key="/name", default="") %} {% set domain_error = errors | get(key="/name", default="") %}
{{ domain_error | json_encode(pretty=true) }}
{% if not new_record_name or (new_record_name and domain_error) %} {% if not new_record_name or (new_record_name and domain_error) %}
{% include "pages/new_record/choose_name.html" %} {% include "pages/new_record/choose_name.html" %}
{% elif not config and not rtype %} {% elif not config and not rtype %}

View file

@ -7,11 +7,33 @@
<input name="addresses[_exist]" type="hidden" value="true"> <input name="addresses[_exist]" type="hidden" value="true">
{% set ttl_error = errors | get(key="/addresses/ttl", default="") %}
<div class="form-input"> <div class="form-input">
<label for="addresses-ttl">Duration in cache (TTL) (optional, default to 1 hour)</label> <label for="addresses-ttl">
<input id="addresses-ttl" name="addresses[ttl]" type="text"> {{ tr(msg="record-input-ttl", attr="input-label", lang=lang) }}
</label>
<p class="help" id="ttl-help">
{{ tr(msg="record-input-ttl", attr="help", lang=lang) }}
</p>
<input
type="text"
inputmode="numeric"
name="addresses[ttl]"
id="addresses-ttl"
aria-describedby="ttl-help{% if ttl_error %} ttl-error{% endif %}"
value="{{ input_data.addresses.ttl | default(value="") }}"
>
{% if ttl_error %}
<p class="error" id="ttl-error">
{{ tr(
msg="record-input-ttl",
attr="error-" ~ ttl_error.code | replace(from=":", to="-"),
lang=lang) }}
</p>
{% endif %}
</div> </div>
{% set global_address_error = errors | get(key="/addresses/data", default="") %}
{% for address in input_data.addresses.data.addresses | default(value=[""]) %} {% for address in input_data.addresses.data.addresses | default(value=[""]) %}
{% set address_error = errors | get(key="/addresses/data/addresses/" ~ loop.index0 ~ "/address", default="") %} {% set address_error = errors | get(key="/addresses/data/addresses/" ~ loop.index0 ~ "/address", default="") %}
<div class="form-input" data-new-item-template="address"> <div class="form-input" data-new-item-template="address">
@ -30,15 +52,23 @@
data-new-item-template-attr="name id" data-new-item-template-attr="name id"
data-template-name="addresses[data][addresses][{i}][address]" data-template-name="addresses[data][addresses][{i}][address]"
data-template-id="address-{i}" data-template-id="address-{i}"
{% if domain_error %}aria-invalid="true"{% endif %} aria-describedby="{% if address_error %}address-{{ loop.index0 }}-error{% endif %}"
{% if address_error %}aria-invalid="true"{% endif %}
value="{{ address.address | default(value="") }}" value="{{ address.address | default(value="") }}"
> >
{% if address_error %} {% if global_address_error or address_error %}
<p class="error" id="address-{{ loop.index0 }}-error" data-new-item-skip> <p class="error" id="address-{{ loop.index0 }}-error" data-new-item-skip>
{{ tr( {% if global_address_error %}
msg="record-input-addresses", {{ tr(
attr="error-" ~ address_error.code | replace(from=":", to="-"), msg="record-input-addresses",
lang=lang) }} attr="error-" ~ global_address_error.code | replace(from=":", to="-"),
lang=lang) }}
{% else %}
{{ tr(
msg="record-input-addresses",
attr="error-" ~ address_error.code | replace(from=":", to="-"),
lang=lang) }}
{% endif %}
</p> </p>
{% endif %} {% endif %}
</div> </div>