feat(ui): add accessibility foundations to base.html and styles.css
- Add skip-to-content link for keyboard navigation (WCAG 2.4.1) - Add ARIA landmarks: nav aria-label, footer role=contentinfo - Add aria-current="page" on active nav links - Add aria-label to admin dropdown button and mobile menu toggle - Add role="menu" and role="menuitem" to admin dropdown - Add aria-hidden="true" to all decorative Font Awesome icons - Add footer nav element with aria-label for footer links - Add focus-visible outline styles for keyboard navigation (WCAG 2.4.7) - Add sr-only utility class - Add dark mode support for skip-link and focus indicators Co-authored-by: christianlouis <361235+christianlouis@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,62 @@
|
||||
/* frontend/static/styles.css */
|
||||
/* Example overrides or additional styling */
|
||||
|
||||
/* =============================================================
|
||||
ACCESSIBILITY
|
||||
Skip-to-content link, focus indicators, and screen-reader-only
|
||||
utility class following WCAG 2.1 Level AA requirements.
|
||||
============================================================= */
|
||||
|
||||
/* Skip-to-content link: visible only on keyboard focus */
|
||||
.skip-link {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
top: auto;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
z-index: 9999;
|
||||
padding: 0.75rem 1.5rem;
|
||||
background-color: #1d4ed8;
|
||||
color: #ffffff;
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
border-radius: 0 0 0.375rem 0;
|
||||
}
|
||||
.skip-link:focus {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: auto;
|
||||
height: auto;
|
||||
outline: 2px solid #2563eb;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Enhanced focus-visible indicators for keyboard navigation (WCAG 2.4.7) */
|
||||
a:focus-visible,
|
||||
button:focus-visible,
|
||||
input:focus-visible,
|
||||
select:focus-visible,
|
||||
textarea:focus-visible,
|
||||
[tabindex]:focus-visible {
|
||||
outline: 2px solid #2563eb;
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
/* Screen-reader-only utility (visually hidden, accessible to AT) */
|
||||
.sr-only {
|
||||
position: absolute;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
margin: -1px;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
body {
|
||||
/* Your global overrides can go here if needed */
|
||||
}
|
||||
@@ -159,6 +216,20 @@ html.dark code { background-color: #111827; color: #d1d5db; }
|
||||
html.dark #darkModeToggle { color: #fbbf24; }
|
||||
html.dark #darkModeToggle:hover { background-color: #374151; }
|
||||
|
||||
/* ---- Dark-mode skip-link ---- */
|
||||
html.dark .skip-link { background-color: #2563eb; }
|
||||
html.dark .skip-link:focus { outline-color: #60a5fa; }
|
||||
|
||||
/* ---- Dark-mode focus-visible indicators ---- */
|
||||
html.dark a:focus-visible,
|
||||
html.dark button:focus-visible,
|
||||
html.dark input:focus-visible,
|
||||
html.dark select:focus-visible,
|
||||
html.dark textarea:focus-visible,
|
||||
html.dark [tabindex]:focus-visible {
|
||||
outline-color: #60a5fa;
|
||||
}
|
||||
|
||||
/* ---- Scrollbar (WebKit browsers) ---- */
|
||||
html.dark ::-webkit-scrollbar { width: 8px; height: 8px; }
|
||||
html.dark ::-webkit-scrollbar-track { background: #1f2937; }
|
||||
|
||||
@@ -34,8 +34,11 @@
|
||||
</head>
|
||||
|
||||
<body class="bg-gray-50 min-h-screen flex flex-col">
|
||||
<!-- Skip to main content link for keyboard/screen reader users -->
|
||||
<a href="#main-content" class="skip-link">Skip to main content</a>
|
||||
|
||||
<!-- Global Nav -->
|
||||
<nav class="bg-white shadow relative">
|
||||
<nav class="bg-white shadow relative" aria-label="Main navigation">
|
||||
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex justify-between h-16 items-center">
|
||||
|
||||
<!-- Brand + Icon -->
|
||||
@@ -56,10 +59,10 @@
|
||||
<!-- Menu Items - using x-data for mobile menu toggle -->
|
||||
<div x-data="{ mobileMenuOpen: false, adminMenuOpen: false }">
|
||||
<div class="hidden md:flex space-x-4 items-center">
|
||||
<a href="/" class="text-gray-700 hover:text-gray-900">Home</a>
|
||||
<a href="/upload" class="text-gray-700 hover:text-gray-900">Upload</a>
|
||||
<a href="/files" class="text-gray-700 hover:text-gray-900">Files</a>
|
||||
<a href="/search" class="text-gray-700 hover:text-gray-900">Search</a>
|
||||
<a href="/" class="text-gray-700 hover:text-gray-900" {% if request and request.url.path == '/' %}aria-current="page"{% endif %}>Home</a>
|
||||
<a href="/upload" class="text-gray-700 hover:text-gray-900" {% if request and request.url.path == '/upload' %}aria-current="page"{% endif %}>Upload</a>
|
||||
<a href="/files" class="text-gray-700 hover:text-gray-900" {% if request and request.url.path == '/files' %}aria-current="page"{% endif %}>Files</a>
|
||||
<a href="/search" class="text-gray-700 hover:text-gray-900" {% if request and request.url.path == '/search' %}aria-current="page"{% endif %}>Search</a>
|
||||
|
||||
<!-- Admin dropdown (shown only for admin users via JS) -->
|
||||
<div id="adminMenuContainer" class="relative hidden">
|
||||
@@ -69,6 +72,7 @@
|
||||
type="button"
|
||||
class="inline-flex items-center text-gray-700 hover:text-gray-900 focus:outline-none"
|
||||
aria-haspopup="true"
|
||||
aria-label="Admin menu"
|
||||
:aria-expanded="adminMenuOpen"
|
||||
>
|
||||
<i class="fas fa-shield-alt mr-1 text-red-500"></i>
|
||||
@@ -84,19 +88,21 @@
|
||||
x-transition:leave-start="opacity-100 scale-100"
|
||||
x-transition:leave-end="opacity-0 scale-95"
|
||||
class="absolute right-0 mt-2 w-48 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 z-50"
|
||||
role="menu"
|
||||
aria-label="Admin actions"
|
||||
>
|
||||
<div class="py-1">
|
||||
<a href="/settings" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-cog w-4 mr-2 text-gray-500"></i> Settings
|
||||
<a href="/settings" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-cog w-4 mr-2 text-gray-500" aria-hidden="true"></i> Settings
|
||||
</a>
|
||||
<a href="/admin/credentials" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-key w-4 mr-2 text-yellow-500"></i> Credentials
|
||||
<a href="/admin/credentials" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-key w-4 mr-2 text-yellow-500" aria-hidden="true"></i> Credentials
|
||||
</a>
|
||||
<a href="/admin/files" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-folder-open w-4 mr-2 text-gray-500"></i> File Manager
|
||||
<a href="/admin/files" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-folder-open w-4 mr-2 text-gray-500" aria-hidden="true"></i> File Manager
|
||||
</a>
|
||||
<a href="/admin/queue" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-stream w-4 mr-2 text-blue-500"></i> Queue Monitor
|
||||
<a href="/admin/queue" role="menuitem" class="flex items-center px-4 py-2 text-sm text-gray-700 hover:bg-gray-100">
|
||||
<i class="fas fa-stream w-4 mr-2 text-blue-500" aria-hidden="true"></i> Queue Monitor
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -104,10 +110,10 @@
|
||||
|
||||
<!-- Status (de-emphasized) -->
|
||||
<a href="/status" class="text-gray-500 hover:text-gray-700 text-sm" title="System Status">
|
||||
<i class="fas fa-circle-dot mr-0.5"></i> Status
|
||||
<i class="fas fa-circle-dot mr-0.5" aria-hidden="true"></i> Status
|
||||
</a>
|
||||
|
||||
<a href="/about" class="text-gray-700 hover:text-gray-900">About</a>
|
||||
<a href="/about" class="text-gray-700 hover:text-gray-900" {% if request and request.url.path == '/about' %}aria-current="page"{% endif %}>About</a>
|
||||
|
||||
<!-- Dark mode toggle (desktop) -->
|
||||
<button
|
||||
@@ -131,6 +137,7 @@
|
||||
type="button"
|
||||
class="md:hidden inline-flex items-center justify-center p-3 rounded-md text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500"
|
||||
style="min-height:44px;min-width:44px;"
|
||||
aria-label="Toggle navigation menu"
|
||||
:aria-expanded="mobileMenuOpen"
|
||||
>
|
||||
<span class="sr-only">Open main menu</span>
|
||||
@@ -160,26 +167,26 @@
|
||||
<div id="mobileAdminSection" class="hidden">
|
||||
<div class="border-t border-gray-200 mt-1 pt-1">
|
||||
<p class="px-3 py-1 text-xs font-semibold text-red-600 uppercase tracking-wider flex items-center">
|
||||
<i class="fas fa-shield-alt mr-1"></i> Admin
|
||||
<i class="fas fa-shield-alt mr-1" aria-hidden="true"></i> Admin
|
||||
</p>
|
||||
<a href="/settings" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-cog mr-2 text-gray-400"></i> Settings
|
||||
<i class="fas fa-cog mr-2 text-gray-400" aria-hidden="true"></i> Settings
|
||||
</a>
|
||||
<a href="/admin/credentials" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-key mr-2 text-yellow-400"></i> Credentials
|
||||
<i class="fas fa-key mr-2 text-yellow-400" aria-hidden="true"></i> Credentials
|
||||
</a>
|
||||
<a href="/admin/files" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-folder-open mr-2 text-gray-400"></i> File Manager
|
||||
<i class="fas fa-folder-open mr-2 text-gray-400" aria-hidden="true"></i> File Manager
|
||||
</a>
|
||||
<a href="/admin/queue" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">
|
||||
<i class="fas fa-stream mr-2 text-blue-400"></i> Queue Monitor
|
||||
<i class="fas fa-stream mr-2 text-blue-400" aria-hidden="true"></i> Queue Monitor
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Status (de-emphasized) in mobile -->
|
||||
<a href="/status" class="block px-3 py-3 rounded-md text-sm font-medium text-gray-400 hover:text-gray-600 hover:bg-gray-50">
|
||||
<i class="fas fa-circle-dot mr-1"></i> Status
|
||||
<i class="fas fa-circle-dot mr-1" aria-hidden="true"></i> Status
|
||||
</a>
|
||||
|
||||
<a href="/about" class="block px-3 py-3 rounded-md text-base font-medium text-gray-700 hover:text-gray-900 hover:bg-gray-50">About</a>
|
||||
@@ -207,20 +214,22 @@
|
||||
</nav>
|
||||
|
||||
<!-- Main Content -->
|
||||
<main class="flex-grow">
|
||||
<main id="main-content" class="flex-grow">
|
||||
{% block content %}{% endblock %}
|
||||
</main>
|
||||
|
||||
<!-- Footer -->
|
||||
<footer class="bg-white shadow">
|
||||
<footer class="bg-white shadow" role="contentinfo">
|
||||
<div class="max-w-7xl mx-auto px-4 py-4 text-center text-gray-600">
|
||||
DocuElevate 2025 -
|
||||
<nav aria-label="Footer navigation" class="inline">
|
||||
<a href="/privacy" class="text-blue-500 hover:underline">Privacy</a> -
|
||||
<a href="/imprint" class="text-blue-500 hover:underline">Imprint</a> -
|
||||
<a href="/terms" class="text-blue-500 hover:underline">Terms</a> -
|
||||
<a href="/cookies" class="text-blue-500 hover:underline">Cookies</a> -
|
||||
<a href="/license" class="text-blue-500 hover:underline">License</a> -
|
||||
<a href="/attribution" class="text-blue-500 hover:underline">Attributions</a> -
|
||||
<a href="/attribution" class="text-blue-500 hover:underline">Attributions</a>
|
||||
</nav> -
|
||||
<span class="text-xs">Version {{ app_version|default(version, true) }}</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
Reference in New Issue
Block a user