Skip to content

Commit

Permalink
main: several fixes (a11y-manager, rules, CSS, checkboxes, etc.)
Browse files Browse the repository at this point in the history
  • Loading branch information
KaiPUecker committed May 17, 2024
1 parent b2b5cc0 commit 48bc8f8
Show file tree
Hide file tree
Showing 12 changed files with 118 additions and 75 deletions.
21 changes: 16 additions & 5 deletions src/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,14 @@
:root {
--font-family-base: "Camingo", Arial, Helvetica, sans-serif;
--font-family-title: "Oswald", Arial, Helvetica, sans-serif;
--ally-rule-lineheight: 32px;
--lineheight-ally-rule: 32px;
--color-primary-hsl: 0deg 100% 47.5%;
--color-background-hsl: 0deg 100% 100%;
--color-primary: hsl(var(--color-primary-hsl));
--color-background: hsl(var(--color-background-hsl));
--color-negative: hsl(0deg 65% 50%);
--color-positive: hsl(120deg 65% 50%);
--shadow-default: 0 5px 10px -5px hsl(0deg 0% 0% / 0.25);
}

* {
Expand All @@ -41,6 +46,12 @@ button.link {
cursor: pointer;
}

code {
background: var(--color-background);
padding: 2px 4px;
border-radius: 6px;
}

/**
* A11y-rules.
*
Expand All @@ -54,8 +65,8 @@ button.link {
top: 50%;
right: 0;
transform: translateY(-50%);
width: var(--ally-rule-lineheight);
height: var(--ally-rule-lineheight);
width: var(--lineheight-ally-rule);
height: var(--lineheight-ally-rule);
display: inline-flex;
justify-content: center;
align-items: center;
Expand All @@ -64,9 +75,9 @@ button.link {
}
*:has(> .--a11yRuleLinked.--a11yFailed)::after {
content: "👎";
background-color: var(--color-primary);
background-color: var(--color-negative);
}
*:has(> .--a11yRuleLinked.--a11ySuccess)::after {
content: "👍";
background-color: hsl(120deg 100% 50%);
background-color: var(--color-positive);
}
4 changes: 2 additions & 2 deletions src/lib/components/a11y-list-view.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

<style>
section {
---ally-rule-lineheight: 2.5em;
---lineheight-ally-rule: 2.5em;
box-sizing: border-box;
background-color: hsl(0deg 0% 0% / .05);
border-radius: 5px;
Expand Down Expand Up @@ -86,7 +86,7 @@
& > * {
position: relative;
height: var(---ally-rule-lineheight);
height: var(---lineheight-ally-rule);
}
}
&:has(h2 > input[type=checkbox]:checked) {
Expand Down
17 changes: 3 additions & 14 deletions src/lib/components/checkbox.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@
<script lang="ts">
import SvelteMarkdown from 'svelte-markdown';
import { linkA11yRule } from '$lib/helpers/a11y-manager.js';
import { onMount, createEventDispatcher } from 'svelte';
import { createEventDispatcher } from 'svelte';
export let label: string = '';
export let value: boolean = false;
export let id: string = '';
export let rule: string = '';
const dispatch = createEventDispatcher();
let elmCheckbox;
// dispatch native change-Event because we are custom in here
function handleChange() {
value = !value;
dispatch('change', { checked: value });
}
onMount(() => linkA11yRule(elmCheckbox));
</script>

<div class="flex items-start gap-2">
<input bind:this={elmCheckbox} {id} type="checkbox" class="mt-1 h-4 w-4 shrink-0" bind:checked={value} on:click={handleChange} />
<input {id} data-rule={rule} use:linkA11yRule type="checkbox" class="mt-1 h-4 w-4 shrink-0" bind:checked={value} on:click={handleChange} />
<div class="flex gap-1">
<label for={id} class="flex gap-1">
{#if label}
Expand All @@ -34,11 +31,3 @@
<slot name="show-code" />
</div>
</div>

<style>
:global(code) {
background: #f3f3f3;
padding: 2px 4px;
border-radius: 6px;
}
</style>
7 changes: 7 additions & 0 deletions src/lib/components/show-code.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
showCode: boolean = false;
$: showPlayground = showCode;
function onGlobalClick(event) {
if (event?.target === elmDialog) {
elmDialog?.close();
}
}
</script>

<button class="link" on:click={_ => elmDialog?.showModal()}>{!showPlayground ? 'Show' : 'Hide'} Code</button>
Expand All @@ -19,6 +25,7 @@
</playground-ide>
<button />
</dialog>
<svelte:window on:click={onGlobalClick} />

<style>
playground-ide {
Expand Down
5 changes: 2 additions & 3 deletions src/lib/components/stored-checkbox.svelte
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
<script lang="ts">
import Checkbox from './checkbox.svelte';
import StoredInput from './stored-input.svelte';
import {randomId} from "$lib/helpers/random-id";
export let key: string = '';
export let label: string = '';
export let id: string = randomId();
export let id: string = crypto.randomUUID();
</script>

<StoredInput {key} let:value let:handleChange>
<Checkbox id="checkbox-{id}" {value} on:change={handleChange} {label}>
<Checkbox id="checkbox-{id}" rule={key} {value} on:change={handleChange} {label}>
<slot />
<div slot="show-code">
<slot name="show-code" />
Expand Down
4 changes: 2 additions & 2 deletions src/lib/components/tooltip.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
font: inherit;
font-size: 1.25em;
font-weight: bold;
background-color: white;
background-color: var(--color-background);
border-radius: 50%;
display: inline-flex;
width: 16px;
Expand Down Expand Up @@ -57,7 +57,7 @@
padding: .25em;
border-radius: 5px;
white-space: nowrap;
box-shadow: 0 5px 10px -5px hsl(0deg 0% 0% / .25);
box-shadow: var(--shadow-default);
}
&::after {
content: '';
Expand Down
69 changes: 27 additions & 42 deletions src/lib/helpers/a11y-manager.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
import htmlLangSet from './a11y-rules/html-lang-set';
import onlyOneH1 from './a11y-rules/only-one-h1';
import imageHasAlt from './a11y-rules/image-has-alt';
import inputLinkedToLabels from './a11y-rules/input-linked-to-labels';

/**
* Defines the ruleset. Each rule uses a key, which is related to the 'id'-attribute
* used in the a11y-page (like <input id="foo"> ==> rule 'foo').
Expand All @@ -12,49 +17,16 @@ const a11yRuleset = {
groups: {
Allgemein: {},
Markup: {
htmlLangSet: {
description: "`<html />` hat korrektes lang-attribut",
isActive: false,
test: (dom) =>
dom?.querySelector("html")?.getAttribute("lang") !== undefined,
},
htmlLangSet,
},
Content: {
onlyOneH1: {
description: "Es gibt nur eine `<h1 />` pro Seite",
isActive: false,
test: (dom) => Array.from(dom?.querySelectorAll("h1")).length <= 1,
},
onlyOneH1,
},
Bilder: {
imageHasAlt: {
description: "Alle `<img />-Elemente` haben ein Alt-Attribut",
isActive: false,
test: (dom) =>
Array.from(dom?.querySelectorAll("img")).filter(
(img) => img.getAttribute("alt") === undefined,
).length === 0,
},
imageHasAlt,
},
Formulare: {
inputLinkedToLabels: {
description: "Alle Inputs sind mit entsprechenden Label verbunden",
isActive: false,
test: (dom) => {
const inputs = Array.from(dom?.querySelectorAll("input"));
const labels = Array.from(dom?.querySelectorAll("label"));
const nonLinkedInput = inputs.find((input) => {
const inputId = input.getAttribute("id");
const matchingLabel = labels.find(
(label) => label.getAttribute("for") === inputId,
);

return inputId === undefined || matchingLabel === undefined;
});

return nonLinkedInput === undefined;
},
},
inputLinkedToLabels,
},
Mobile: {},
Tastatur: {},
Expand Down Expand Up @@ -84,20 +56,33 @@ Array.from(Object.keys(a11yRuleset.groups)).forEach(
*/
export function testA11yRules() {
if (a11yDomContext) {
const
mainStyle = 'font-weight: bold; font-size: 1.25em;',
ruleStyle = 'color: hsl(0deg 0% 50%);',
resultPositiveStyle = 'font-weight: bold; border-bottom: 2px solid hsl(120deg 100% 50%); font-style: italics;',
resultNegativeStyle = 'font-weight: bold; border-bottom: 2px solid hsl(0deg 100% 50%); font-style: italics;';

console.group(`%cRun all A11y-rules on content:`, mainStyle, a11yDomContext);

Object.keys(flatA11yRuleset).forEach((ruleId) => {
const rule = flatA11yRuleset[ruleId];

rule.linked?.classList.remove("--a11ySuccess");
rule.linked?.classList.remove("--a11yFailed");

if (rule?.isActive) {
console.group(`%cCheck A11y-rule '${ruleId}'...`, ruleStyle, rule);
let ruleResult = rule.test(a11yDomContext);
console.debug(`%cResult = ${ruleResult}`, ruleResult ? resultPositiveStyle : resultNegativeStyle);
console.groupEnd();

rule.linked?.classList.add(
ruleResult ? "--a11ySuccess" : "--a11yFailed",
);
}
});

console.groupEnd();
}
}

Expand All @@ -119,20 +104,20 @@ export function watchedA11yContent(dom) {
* @returns object
*/
export function linkA11yRule(node) {
if (node && node.id && flatA11yRuleset[node.id]) {
if (node && node.dataset?.rule && flatA11yRuleset[node.dataset.rule]) {
// Due to the reactivity of svelte a simple 'change'-listener
// doesn't help here, unfortunately 'MutationObserver' won't
// work either (at least in the developemt enviroment as we
// run a NodeJS), so the simpliest solution for now is a
// setInterval (w/o extra dependencies).
setInterval(() => {
if (node.checked !== flatA11yRuleset[node.id].isActive) {
flatA11yRuleset[node.id].isActive = node.checked;
if (node.checked !== flatA11yRuleset[node.dataset.rule].isActive) {
flatA11yRuleset[node.dataset.rule].isActive = node.checked;
testA11yRules();
}
}, 100);
flatA11yRuleset[node.id].linked = node;
flatA11yRuleset[node.id].isActive = node.checked;
flatA11yRuleset[node.dataset.rule].linked = node;
flatA11yRuleset[node.dataset.rule].isActive = node.checked;
node.classList.add("--a11yRuleLinked");
}
return {
Expand Down
13 changes: 13 additions & 0 deletions src/lib/helpers/a11y-rules/html-lang-set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default {
description: "`<html />` hat korrektes lang-attribut",
isActive: false,
test: (dom) => {
let node = dom?.querySelector('html');
let attr = node?.getAttribute('lang');

console.debug('node:', node);
console.debug('attr:', attr);

return attr !== undefined && attr !== null;
}
};
13 changes: 13 additions & 0 deletions src/lib/helpers/a11y-rules/image-has-alt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export default {
description: "Alle `<img />-Elemente` haben ein Alt-Attribut",
isActive: false,
test: (dom) => {
let nodes = Array.from(dom?.querySelectorAll("img"));
let nodesWithoutAlt = nodes.filter((img) => img.getAttribute("alt") === undefined);

console.debug('nodes:', nodes);
console.debug('nodesWithoutAlt:', nodesWithoutAlt);

return nodesWithoutAlt.length === 0;
}
}
22 changes: 22 additions & 0 deletions src/lib/helpers/a11y-rules/input-linked-to-labels.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export default {
description: "Alle Inputs sind mit entsprechenden Label verbunden",
isActive: false,
test: (dom) => {
let inputs = Array.from(dom?.querySelectorAll("input"));
let labels = Array.from(dom?.querySelectorAll("label"));
let nonLinkedInput = inputs.find((input) => {
let inputId = input.getAttribute("id");
let matchingLabel = labels.find(
(label) => label.getAttribute("for") === inputId,
);

return inputId === undefined || matchingLabel === undefined;
});

console.debug('inputs:', inputs);
console.debug('labels:', labels);
console.debug('nonLinkedInput:', nonLinkedInput);

return nonLinkedInput === undefined;
}
}
11 changes: 11 additions & 0 deletions src/lib/helpers/a11y-rules/only-one-h1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export default {
description: "Es gibt nur eine `<h1 />` pro Seite",
isActive: false,
test: (dom) => {
let nodes = Array.from(dom?.querySelectorAll("h1"));

console.debug('nodes:', nodes);

return nodes.length <= 1;
}
}
7 changes: 0 additions & 7 deletions src/lib/helpers/random-id.js

This file was deleted.

0 comments on commit 48bc8f8

Please sign in to comment.