fix(andreknie.de): close accessibility and performance review gaps

This commit is contained in:
2026-07-29 00:05:18 +02:00
parent 88bd952a60
commit c4b5aa40ab
19 changed files with 198 additions and 58 deletions
@@ -24,10 +24,13 @@ export default function ArticleSingle() {
}
if (!post.body) {
const loadFailed = post.detailError
return (
<main className="page-container app-container" style={{ textAlign: 'center', paddingTop: '150px' }}>
<SEOHead title={post.title} description={post.excerpt || post.title} url={`/artikel/${post.slug}`} type="article" />
<p role="status" aria-live="polite">Artikel wird geladen </p>
<p role={loadFailed ? 'alert' : 'status'} aria-live={loadFailed ? 'assertive' : 'polite'}>
{loadFailed ? 'Der Artikel konnte nicht geladen werden.' : 'Artikel wird geladen …'}
</p>
</main>
)
}
@@ -45,6 +45,7 @@ export default function Articles() {
<input
type="text"
placeholder="Artikel durchsuchen..."
aria-label="Artikel durchsuchen"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
style={{
@@ -36,6 +36,7 @@ export default function Kniepunkt() {
<input
type="text"
placeholder="Kniepunkte durchsuchen..."
aria-label="Kniepunkte durchsuchen"
value={searchQuery}
onChange={(e) => setSearchQuery(e.target.value)}
style={{
@@ -22,11 +22,14 @@ export default function KniepunktIssue() {
}
if (!issue.body) {
const loadFailed = issue.detailError
return (
<main style={{ paddingTop: '120px', minHeight: '100vh' }}>
<SEOHead title={issue.title} description={issue.summary || issue.title} url={`/kniepunkt/${issue.slug}`} type="article" image={issue.image} />
<div className="app-container" style={{ textAlign: 'center' }}>
<p role="status" aria-live="polite">Kniepunkt-Ausgabe wird geladen </p>
<p role={loadFailed ? 'alert' : 'status'} aria-live={loadFailed ? 'assertive' : 'polite'}>
{loadFailed ? 'Die Kniepunkt-Ausgabe konnte nicht geladen werden.' : 'Kniepunkt-Ausgabe wird geladen …'}
</p>
</div>
</main>
)
@@ -31,7 +31,7 @@ function ResourceRequestForm({ resource, onCancel }) {
return (
<div className="glass-panel" style={{ padding: '24px', marginTop: '24px' }}>
{success ? (
<p style={{ margin: 0, color: 'var(--text-primary)' }}>
<p role="status" aria-live="polite" style={{ margin: 0, color: 'var(--text-primary)' }}>
Danke! Wir prüfen die Anfrage und melden uns bei dir.
</p>
) : (
@@ -41,7 +41,7 @@ function ResourceRequestForm({ resource, onCancel }) {
Wir prüfen die Anfrage. Bei positiver Prüfung verschickt André ein aktuelles Profil persönlich.
</p>
<div aria-hidden="true" style={{ position: 'absolute', left: '-9999px', width: '1px', height: '1px', overflow: 'hidden' }}>
<div hidden>
<label htmlFor="resource-company-website">Firmen-Website (bitte leer lassen)</label>
<input id="resource-company-website" name="company_website" tabIndex={-1} autoComplete="off" value={form.company_website} onChange={updateField} />
</div>
@@ -49,18 +49,18 @@ function ResourceRequestForm({ resource, onCancel }) {
<input type="hidden" name="resource_id" value={resourceId} />
<label htmlFor="resource-name">Name</label>
<input id="resource-name" name="name" value={form.name} onChange={updateField} style={inputStyle} autoComplete="name" aria-invalid={Boolean(errors.name)} />
{errors.name && <p role="alert" style={{ color: '#ff4444', margin: '4px 0 12px' }}>{errors.name}</p>}
<input id="resource-name" name="name" value={form.name} onChange={updateField} style={inputStyle} autoComplete="name" aria-invalid={Boolean(errors.name)} aria-describedby={errors.name ? 'resource-name-error' : undefined} />
{errors.name && <p id="resource-name-error" role="alert" style={{ color: '#ff4444', margin: '4px 0 12px' }}>{errors.name}</p>}
<label htmlFor="resource-email">E-Mail</label>
<input id="resource-email" name="email" type="email" value={form.email} onChange={updateField} style={inputStyle} autoComplete="email" aria-invalid={Boolean(errors.email)} />
{errors.email && <p role="alert" style={{ color: '#ff4444', margin: '4px 0 12px' }}>{errors.email}</p>}
<input id="resource-email" name="email" type="email" value={form.email} onChange={updateField} style={inputStyle} autoComplete="email" aria-invalid={Boolean(errors.email)} aria-describedby={errors.email ? 'resource-email-error' : undefined} />
{errors.email && <p id="resource-email-error" role="alert" style={{ color: '#ff4444', margin: '4px 0 12px' }}>{errors.email}</p>}
<label htmlFor="resource-company">Unternehmen</label>
<input id="resource-company" name="company" value={form.company} onChange={updateField} style={inputStyle} autoComplete="organization" aria-invalid={Boolean(errors.company)} />
{errors.company && <p role="alert" style={{ color: '#ff4444', margin: '4px 0 12px' }}>{errors.company}</p>}
<input id="resource-company" name="company" value={form.company} onChange={updateField} style={inputStyle} autoComplete="organization" aria-invalid={Boolean(errors.company)} aria-describedby={errors.company ? 'resource-company-error' : undefined} />
{errors.company && <p id="resource-company-error" role="alert" style={{ color: '#ff4444', margin: '4px 0 12px' }}>{errors.company}</p>}
{serverError && <p role="alert" style={{ color: '#ff4444' }}>{serverError}</p>}
{serverError && <p role="alert" aria-live="assertive" style={{ color: '#ff4444' }}>{serverError}</p>}
{errors.resource_id && <p role="alert" style={{ color: '#ff4444' }}>{errors.resource_id}</p>}
<div style={{ display: 'flex', gap: '12px', marginTop: '20px', flexWrap: 'wrap' }}>