fix(quick-260921-bi2): a11y - Modul-Bereich (Kategorie-Seiten, Cert-Manager)
useButtonType: alle Aktions-Buttons in Cert-Manager-Tabs (kein Formular in diesen Dateien) erhalten type="button". noSvgWithoutTitle: Modul-Icons neben dem Modulnamen, Leer- und Nicht- gefunden-Zustaende neben ihrer Ueberschrift werden dekorativ (aria-hidden="true"); die Augen-Icons im Passwortfeld sind bereits ueber das aria-label des umschliessenden Buttons benannt. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -40,6 +40,7 @@ export function ModuleShell({ category, moduleSlug }: ModuleShellProps) {
|
|||||||
<div className="flex flex-col items-center justify-center py-16 text-center">
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
||||||
<div className="rounded-lg bg-muted p-4 mb-4">
|
<div className="rounded-lg bg-muted p-4 mb-4">
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="48"
|
width="48"
|
||||||
height="48"
|
height="48"
|
||||||
@@ -81,6 +82,7 @@ export function ModuleShell({ category, moduleSlug }: ModuleShellProps) {
|
|||||||
className="inline-flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
|
className="inline-flex items-center gap-1.5 text-sm font-medium text-muted-foreground hover:text-foreground transition-colors"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16"
|
width="16"
|
||||||
height="16"
|
height="16"
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ function ModuleIcon({ icon }: { icon?: string }) {
|
|||||||
if (icon === 'Globe') {
|
if (icon === 'Globe') {
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
@@ -44,6 +45,7 @@ function ModuleIcon({ icon }: { icon?: string }) {
|
|||||||
// Default puzzle-piece icon for generic modules
|
// Default puzzle-piece icon for generic modules
|
||||||
return (
|
return (
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="24"
|
width="24"
|
||||||
height="24"
|
height="24"
|
||||||
|
|||||||
@@ -121,6 +121,7 @@ export default function CategoryPage() {
|
|||||||
<div className="flex flex-col items-center justify-center py-16 text-center">
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
||||||
<div className="rounded-lg bg-muted p-4 mb-4">
|
<div className="rounded-lg bg-muted p-4 mb-4">
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="48"
|
width="48"
|
||||||
height="48"
|
height="48"
|
||||||
|
|||||||
@@ -73,6 +73,7 @@ export function ConvertTab({ file, pemText, password, onTargetFormatChange }: Co
|
|||||||
|
|
||||||
{/* Primary action button */}
|
{/* Primary action button */}
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={handleConvert}
|
onClick={handleConvert}
|
||||||
disabled={loading || !canConvert}
|
disabled={loading || !canConvert}
|
||||||
className="bg-primary text-primary-foreground px-4 py-2 rounded text-sm font-medium disabled:opacity-50 hover:opacity-90 transition-opacity"
|
className="bg-primary text-primary-foreground px-4 py-2 rounded text-sm font-medium disabled:opacity-50 hover:opacity-90 transition-opacity"
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ export function InspectTab({ file, pemText, password }: InspectTabProps) {
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
{/* Primary action button */}
|
{/* Primary action button */}
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={handleInspect}
|
onClick={handleInspect}
|
||||||
disabled={loading || !canInspect}
|
disabled={loading || !canInspect}
|
||||||
className="bg-primary text-primary-foreground px-4 py-2 rounded text-sm font-medium disabled:opacity-50 hover:opacity-90 transition-opacity"
|
className="bg-primary text-primary-foreground px-4 py-2 rounded text-sm font-medium disabled:opacity-50 hover:opacity-90 transition-opacity"
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ export function PasswordField({ value, onChange, show }: PasswordFieldProps) {
|
|||||||
{revealed ? (
|
{revealed ? (
|
||||||
/* Eye-off inline SVG */
|
/* Eye-off inline SVG */
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16"
|
width="16"
|
||||||
height="16"
|
height="16"
|
||||||
@@ -55,6 +56,7 @@ export function PasswordField({ value, onChange, show }: PasswordFieldProps) {
|
|||||||
) : (
|
) : (
|
||||||
/* Eye inline SVG */
|
/* Eye inline SVG */
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="16"
|
width="16"
|
||||||
height="16"
|
height="16"
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ export function SplitTab({ file, pemText: _pemText, password: _password }: Split
|
|||||||
<div className="space-y-4">
|
<div className="space-y-4">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={handleSplit}
|
onClick={handleSplit}
|
||||||
disabled={loading || !file}
|
disabled={loading || !file}
|
||||||
className="bg-primary text-primary-foreground px-4 py-2 rounded text-sm font-medium disabled:opacity-50 hover:opacity-90 transition-opacity"
|
className="bg-primary text-primary-foreground px-4 py-2 rounded text-sm font-medium disabled:opacity-50 hover:opacity-90 transition-opacity"
|
||||||
@@ -79,6 +80,7 @@ export function SplitTab({ file, pemText: _pemText, password: _password }: Split
|
|||||||
|
|
||||||
{result && result.certs.length > 1 && (
|
{result && result.certs.length > 1 && (
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() => downloadAllAsZip(result.certs)}
|
onClick={() => downloadAllAsZip(result.certs)}
|
||||||
className="border border-border px-4 py-2 rounded text-sm font-medium hover:bg-secondary transition-colors"
|
className="border border-border px-4 py-2 rounded text-sm font-medium hover:bg-secondary transition-colors"
|
||||||
>
|
>
|
||||||
@@ -117,6 +119,7 @@ export function SplitTab({ file, pemText: _pemText, password: _password }: Split
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
type="button"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
downloadBase64(cert.filename, cert.content, 'application/x-pem-file')
|
downloadBase64(cert.filename, cert.content, 'application/x-pem-file')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ export function ModuleAccessDenied({ title, body, backToDashboard }: ModuleAcces
|
|||||||
<div className="flex flex-col items-center justify-center py-16 text-center">
|
<div className="flex flex-col items-center justify-center py-16 text-center">
|
||||||
<div className="rounded-lg bg-muted p-4 mb-4">
|
<div className="rounded-lg bg-muted p-4 mb-4">
|
||||||
<svg
|
<svg
|
||||||
|
aria-hidden="true"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width="48"
|
width="48"
|
||||||
height="48"
|
height="48"
|
||||||
|
|||||||
Reference in New Issue
Block a user