fix(quick-260921-bi2): a11y - Dashboard-Widgets und Portal-Startseite

useButtonType: "Widget hinzufuegen"-, Bearbeiten-Modus- und Katalog-Buttons
(kein Formular in diesen Dateien) erhalten type="button".

noSvgWithoutTitle: Widget-Icons in der Katalog-Kachel (immer neben dem
Widget-Namen) und Buttons mit bestehendem aria-label/title werden dekorativ
(aria-hidden="true"); der bislang unbeschriftete Such-Button im Such-Widget
erhaelt aria-label={t('search.searchButton')} (neuer Schluessel, siehe
vorherige i18n-Festschreibung).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
2026-09-21 09:21:34 +02:00
parent 278aedb201
commit 969fd01f5c
7 changed files with 20 additions and 0 deletions
@@ -19,6 +19,7 @@ export function EditModeToggle({ isEditMode, onToggle }: EditModeToggleProps) {
return (
<button
type="button"
onClick={onToggle}
className={`inline-flex items-center justify-center rounded-md p-2 shadow-lg transition-colors ${
isEditMode
@@ -32,6 +33,7 @@ export function EditModeToggle({ isEditMode, onToggle }: EditModeToggleProps) {
{isEditMode ? (
// Checkmark icon
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
@@ -47,6 +49,7 @@ export function EditModeToggle({ isEditMode, onToggle }: EditModeToggleProps) {
) : (
// Pencil icon
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
@@ -76,11 +76,13 @@ export function WidgetCatalogModal({
{t('catalogTitle')}
</h2>
<button
type="button"
onClick={onClose}
className="rounded-md p-1 text-muted-foreground transition-colors hover:bg-muted hover:text-foreground"
aria-label="Close"
>
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
@@ -105,6 +107,7 @@ export function WidgetCatalogModal({
return (
<button
key={type}
type="button"
onClick={() => {
onAddWidget(type);
onClose();
@@ -90,6 +90,7 @@ function PlaceholderWidget({ config }: WidgetProps) {
function ClockIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -110,6 +111,7 @@ function ClockIcon({ className }: { className?: string }) {
function SearchIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -130,6 +132,7 @@ function SearchIcon({ className }: { className?: string }) {
function CalendarIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -152,6 +155,7 @@ function CalendarIcon({ className }: { className?: string }) {
function NoteIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -175,6 +179,7 @@ function NoteIcon({ className }: { className?: string }) {
function CalculatorIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -203,6 +208,7 @@ function CalculatorIcon({ className }: { className?: string }) {
function FavoritesIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -222,6 +228,7 @@ function FavoritesIcon({ className }: { className?: string }) {
function StopwatchIcon({ className }: { className?: string }) {
return (
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
@@ -157,11 +157,13 @@ export function NoteWidget({ instanceId, config }: WidgetProps) {
/>
)}
<button
type="button"
onClick={() => setIsEditing((v) => !v)}
className={`flex h-6 w-6 shrink-0 items-center justify-center rounded transition-colors hover:bg-muted ${isEditing ? 'text-destructive' : 'text-muted-foreground'}`}
title={isEditing ? t('note.viewMode') : t('note.editMode')}
>
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
@@ -116,8 +116,10 @@ export function SearchWidget({ instanceId, config }: WidgetProps) {
type="button"
className="flex h-8 shrink-0 items-center justify-center rounded bg-primary px-3 text-sm font-medium text-primary-foreground transition-colors hover:bg-primary/90"
onClick={handleSearch}
aria-label={t('search.searchButton')}
>
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
@@ -78,6 +78,7 @@ export function WidgetWrapper({ widget, isEditMode, onRemove }: WidgetWrapperPro
data-no-drag=""
>
<svg
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
width="12"
height="12"