️ Improve keyboard accessibility: content skip

This commit is contained in:
Manuel Cillero 2023-10-22 19:20:34 +02:00
parent d8f0c367de
commit 350829c3c8
6 changed files with 86 additions and 27 deletions

View file

@ -1,8 +1,9 @@
use crate::core::component::{ComponentTrait, Context};
use crate::core::module::ModuleTrait;
use crate::html::{html, Favicon, Markup};
use crate::locale::L10n;
use crate::response::page::Page;
use crate::{config, LOCALES_PAGETOP};
use crate::{concat_string, config};
pub type ThemeRef = &'static dyn ThemeTrait;
@ -11,11 +12,11 @@ pub trait ThemeTrait: ModuleTrait + Send + Sync {
#[rustfmt::skip]
fn regions(&self) -> Vec<(&'static str, L10n)> {
vec![
("header", L10n::t("header", &LOCALES_PAGETOP)),
("pagetop", L10n::t("pagetop", &LOCALES_PAGETOP)),
("content", L10n::t("content", &LOCALES_PAGETOP)),
("sidebar", L10n::t("sidebar", &LOCALES_PAGETOP)),
("footer", L10n::t("footer", &LOCALES_PAGETOP)),
("header", L10n::l("header")),
("pagetop", L10n::l("pagetop")),
("content", L10n::l("content")),
("sidebar", L10n::l("sidebar")),
("footer", L10n::l("footer")),
]
}
@ -28,8 +29,16 @@ pub trait ThemeTrait: ModuleTrait + Send + Sync {
let content = page.prepare_region("content");
let sidebar = page.prepare_region("sidebar");
let footer = page.prepare_region("footer");
let skip_to = concat_string!("#", page.skip_to().get().unwrap_or("content".to_owned()));
html! {
body class=[page.body_classes().get()] {
@if let Some(skip) = L10n::l("skip_to_content").using(page.context().langid()) {
div class="pt-body__skip" {
a href=(skip_to) { (skip) }
}
}
div class="pt-body__wrapper" {
div class="pt-body__regions" {
(header.unwrap_or_default())

View file

@ -3,3 +3,5 @@ pagetop = Page Top
content = Content
sidebar = Sidebar
footer = Footer
skip_to_content = Skip to main content (Press Enter)

View file

@ -3,3 +3,5 @@ pagetop = Superior
content = Contenido
sidebar = Barra lateral
footer = Pie
skip_to_content = Ir al contenido principal (Pulsar Intro)

View file

@ -22,6 +22,7 @@ pub struct Page {
context : Context,
body_classes: OptionClasses,
regions : ComponentsRegions,
skip_to : OptionId,
template : String,
}
@ -35,8 +36,9 @@ impl Page {
properties : Vec::new(),
favicon : None,
context : Context::new(request),
body_classes: OptionClasses::new().with_value(ClassesOp::SetDefault, "body"),
body_classes: OptionClasses::new(),
regions : ComponentsRegions::new(),
skip_to : OptionId::new(),
template : "default".to_owned(),
}
}
@ -91,6 +93,12 @@ impl Page {
self
}
#[fn_builder]
pub fn alter_skip_to(&mut self, id: impl Into<String>) -> &mut Self {
self.skip_to.alter_value(id);
self
}
#[fn_builder]
pub fn alter_template(&mut self, template: &str) -> &mut Self {
self.template = template.to_owned();
@ -127,6 +135,10 @@ impl Page {
&self.body_classes
}
pub fn skip_to(&self) -> &OptionId {
&self.skip_to
}
pub fn template(&self) -> &str {
self.template.as_str()
}

View file

@ -12,9 +12,7 @@
--pt-font-size-xxs: 0.75rem;
--pt-font-weight: 400;
--pt-line-height-base: 1.5;
--pt-color-bg: #fff;
--pt-color: #212529;
--pt-max-width: 80rem;
--pt-max-width: 90rem;
/*
--pt-color-rgb: 33,37,41;
--pt-main--bg-rgb: 255,255,255;
@ -75,11 +73,11 @@
:root {
/*
--pt-gap-0-25: calc(0.25 * var(--pt-gap));
--pt-gap-0-5: calc(0.5 * var(--pt-gap));
*/
--pt-gap-0-5: calc(0.5 * var(--pt-gap));
--pt-gap-0-75: calc(0.75 * var(--pt-gap));
/*
--pt-gap-1-5: calc(1.5 * var(--pt-gap));
/*
--pt-gap-2: calc(2 * var(--pt-gap));
--pt-gap-2-5: calc(2.5 * var(--pt-gap));
--pt-gap-3: calc(3 * var(--pt-gap));
@ -92,19 +90,26 @@
--pt-gap-10: calc(10 * var(--pt-gap));
--pt-gap-11: calc(11 * var(--pt-gap));
--pt-gap-12: calc(12 * var(--pt-gap));
*/
--pt-color--gray-hue: 201;
--pt-color--gray-saturation: 15%;
--pt-color--gray-5: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),5%);
--pt-color--gray-10: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),11%);
--pt-color--gray-20: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),20%);
--pt-color--gray-45: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),44%);
--pt-color--gray-60: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),57%);
--pt-color--gray-65: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),63%);
--pt-color--gray-70: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),72%);
--pt-color--gray-90: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),88%);
--pt-color--gray-95: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),93%);
--pt-color--gray-100: hsl(var(--pt-color--gray-hue),var(--pt-color--gray-saturation),97%);
--pt-color--white: #fff;
--pt-color--bg: var(--pt-color--white);
--pt-color: #212529;
/*
--color--gray-hue: 201;
--color--gray-saturation: 15%;
--color--gray-5: hsl(var(--color--gray-hue),var(--color--gray-saturation),5%);
--color--gray-10: hsl(var(--color--gray-hue),var(--color--gray-saturation),11%);
--color--gray-20: hsl(var(--color--gray-hue),var(--color--gray-saturation),20%);
--color--gray-45: hsl(var(--color--gray-hue),var(--color--gray-saturation),44%);
--color--gray-60: hsl(var(--color--gray-hue),var(--color--gray-saturation),57%);
--color--gray-65: hsl(var(--color--gray-hue),var(--color--gray-saturation),63%);
--color--gray-70: hsl(var(--color--gray-hue),var(--color--gray-saturation),72%);
--color--gray-90: hsl(var(--color--gray-hue),var(--color--gray-saturation),88%);
--color--gray-95: hsl(var(--color--gray-hue),var(--color--gray-saturation),93%);
--color--gray-100: hsl(var(--color--gray-hue),var(--color--gray-saturation),97%);
--color--primary-hue: 202;
--color--primary-saturation: 79%;
--color--primary-lightness: 50;
@ -119,7 +124,8 @@
--color-text-primary-medium: var(--color--primary-40);
--color-text-primary-loud: var(--color--primary-30);
--color--black: #000;
--color--white: #fff;
*/
/*
--color--red: #e33f1e;
--color--gold: #fdca40;
--color--green: #3fa21c;
@ -129,7 +135,7 @@
--pt-border-radius: 0.1875rem;
--pt-menu--color-bg: #fafafa;
--pt-menu--color-bg: var(--pt-color--gray-100);
--pt-menu--color-highlight: #e91e63;
--pt-menu--color-border: rgba(0, 0, 0, 0.1);
--pt-menu--color-shadow: rgba(0, 0, 0, 0.06);

View file

@ -1,3 +1,7 @@
html {
scroll-behavior: smooth;
}
body {
margin: 0;
font-family: var(--pt-font-family);
@ -5,12 +9,36 @@ body {
font-weight: var(--pt-font-weight);
line-height: var(--pt-line-height-base);
color: var(--pt-color);
background-color: var(--pt-color-bg);
background-color: var(--pt-color--bg);
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
.pt-body__skip {
display: flex;
justify-content: center;
}
.pt-body__skip a {
display: block;
padding: var(--pt-gap-0-5) var(--pt-gap-1-5);
color: var(--pt-color--white);
background-color: var(--pt-color--gray-5);
text-decoration: none;
outline: 0;
position: absolute;
transform: translateY(-100%);
transition: all 0.3s ease-in-out;
z-index: 9999;
}
.pt-body__skip a:after {
content: "\0020 ➔";
}
.pt-body__skip a:focus {
transform: translateY(0%);
}
.pt-body__wrapper {
width: 100%;
max-width: var(--pt-max-width);
margin: 0 auto;
}