ham3d / index.html
ham3dco's picture
Add 2 files
cfb66e7 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accessibility Widget</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#3b82f6',
secondary: '#1e40af',
dark: '#1e293b',
light: '#f8fafc',
highcontrast: {
text: '#000000',
bg: '#FFFFFF',
accent: '#FF0000'
}
},
fontFamily: {
dyslexic: ['OpenDyslexic', 'Comic Sans MS', 'sans-serif']
}
}
}
}
</script>
<style>
/* Custom styles for accessibility features */
.dyslexic-font {
font-family: 'Comic Sans MS', sans-serif !important;
}
.high-contrast {
background-color: #FFFFFF !important;
color: #000000 !important;
border-color: #000000 !important;
}
.high-contrast * {
background-color: #FFFFFF !important;
color: #000000 !important;
border-color: #000000 !important;
}
.high-contrast-accent {
color: #FF0000 !important;
}
.large-cursor * {
cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Ccircle cx='16' cy='16' r='12' fill='none' stroke='%23000' stroke-width='2'/%3E%3Ccircle cx='16' cy='16' r='2' fill='%23000'/%3E%3C/svg%3E") 16 16, pointer !important;
}
.reduced-motion * {
transition: none !important;
animation: none !important;
}
.highlight-text p, .highlight-text a {
background-color: rgba(255, 255, 0, 0.3) !important;
padding: 2px 4px !important;
border-radius: 2px !important;
}
/* Keyframes for widget button pulse */
@keyframes pulse {
0% { transform: scale(1); }
50% { transform: scale(1.1); }
100% { transform: scale(1); }
}
.pulse-animation {
animation: pulse 2s infinite;
}
/* Transition for panel */
.accessibility-panel {
transition: all 0.3s ease;
}
/* Focus styles */
:focus-visible {
outline: 3px solid #3b82f6 !important;
outline-offset: 2px !important;
}
.high-contrast :focus-visible {
outline: 3px solid #FF0000 !important;
}
</style>
</head>
<body class="bg-gray-50 text-gray-900 min-h-screen transition-colors duration-300">
<!-- Skip to content link (hidden until focused) -->
<a href="#main-content" class="sr-only focus:not-sr-only focus:fixed focus:top-4 focus:left-4 focus:bg-white focus:text-black focus:px-4 focus:py-2 focus:z-50 focus:rounded focus:font-bold">
Skip to content
</a>
<!-- Main content area -->
<main id="main-content" class="container mx-auto px-4 py-8">
<h1 class="text-3xl font-bold mb-6">Website Content</h1>
<article class="prose max-w-none">
<p class="mb-4">This is a demonstration of the accessibility widget functionality. The widget provides various tools to make the website more accessible to all users.</p>
<h2 class="text-2xl font-semibold mt-6 mb-4">About Accessibility</h2>
<p class="mb-4">Web accessibility means that websites, tools, and technologies are designed and developed so that people with disabilities can use them. More specifically, people can:</p>
<ul class="list-disc pl-6 mb-4">
<li class="mb-2">Perceive, understand, navigate, and interact with the web</li>
<li class="mb-2">Contribute to the web</li>
<li class="mb-2">Have equal access and equal opportunity to information</li>
</ul>
<h2 class="text-2xl font-semibold mt-6 mb-4">Why It Matters</h2>
<p class="mb-4">Accessibility is essential for developers and organizations that want to create high-quality websites and web tools, and not exclude people from using their products and services.</p>
<p class="mb-4">Try out the accessibility widget by clicking the button in the bottom right corner of the screen. You can adjust text size, contrast, and other settings to suit your needs.</p>
<h3 class="text-xl font-semibold mt-6 mb-4">Sample Interactive Elements</h3>
<button class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded mr-4 mb-4 transition-colors">
Example Button
</button>
<a href="#" class="text-blue-600 hover:text-blue-800 underline mr-4 mb-4 inline-block">Example Link</a>
<input type="text" placeholder="Example input" class="border px-3 py-2 rounded mb-4">
</article>
</main>
<!-- Accessibility Widget -->
<div class="fixed bottom-6 right-6 z-40">
<!-- Toggle Button -->
<button id="accessibility-toggle"
aria-label="Open accessibility panel"
aria-expanded="false"
class="bg-blue-600 text-white w-14 h-14 rounded-full shadow-lg flex items-center justify-center hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500 pulse-animation transition-all">
<i class="fas fa-universal-access text-2xl"></i>
</button>
<!-- Panel -->
<div id="accessibility-panel"
role="dialog"
aria-labelledby="accessibility-panel-title"
aria-modal="true"
class="accessibility-panel hidden bg-white rounded-lg shadow-xl w-80 max-h-[90vh] overflow-y-auto absolute bottom-20 right-0 border border-gray-200">
<div class="p-4">
<div class="flex justify-between items-center mb-4">
<h2 id="accessibility-panel-title" class="text-xl font-bold">Accessibility Settings</h2>
<button id="close-panel" aria-label="Close accessibility panel" class="text-gray-500 hover:text-gray-700">
<i class="fas fa-times"></i>
</button>
</div>
<div class="space-y-6">
<!-- Text Size -->
<section>
<h3 class="font-semibold mb-2">Text Size</h3>
<div class="flex items-center space-x-2">
<button id="decrease-text" aria-label="Decrease text size" class="bg-gray-200 hover:bg-gray-300 rounded-full w-8 h-8 flex items-center justify-center">
<i class="fas fa-minus"></i>
</button>
<div class="flex-1 bg-gray-100 rounded-full h-2">
<div id="text-size-indicator" class="bg-blue-500 h-2 rounded-full w-1/2"></div>
</div>
<button id="increase-text" aria-label="Increase text size" class="bg-gray-200 hover:bg-gray-300 rounded-full w-8 h-8 flex items-center justify-center">
<i class="fas fa-plus"></i>
</button>
</div>
</section>
<!-- Font Style -->
<section>
<h3 class="font-semibold mb-2">Font Style</h3>
<button id="toggle-dyslexic" aria-pressed="false" class="flex items-center space-x-2 px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded">
<i class="fas fa-font"></i>
<span>Dyslexia-Friendly Font</span>
<span id="dyslexic-status" class="ml-auto text-sm text-gray-500">Off</span>
</button>
</section>
<!-- Color Contrast -->
<section>
<h3 class="font-semibold mb-2">Color & Contrast</h3>
<div class="space-y-2">
<button id="toggle-contrast" aria-pressed="false" class="w-full flex items-center space-x-2 px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded">
<i class="fas fa-adjust"></i>
<span>High Contrast Mode</span>
<span id="contrast-status" class="ml-auto text-sm text-gray-500">Off</span>
</button>
</div>
</section>
<!-- Visual Aids -->
<section>
<h3 class="font-semibold mb-2">Visual Aids</h3>
<div class="space-y-2">
<button id="toggle-cursor" aria-pressed="false" class="w-full flex items-center space-x-2 px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded">
<i class="fas fa-mouse-pointer"></i>
<span>Large Cursor</span>
<span id="cursor-status" class="ml-auto text-sm text-gray-500">Off</span>
</button>
<button id="toggle-highlight" aria-pressed="false" class="w-full flex items-center space-x-2 px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded">
<i class="fas fa-highlighter"></i>
<span>Text Highlighting</span>
<span id="highlight-status" class="ml-auto text-sm text-gray-500">Off</span>
</button>
</div>
</section>
<!-- Motion -->
<section>
<h3 class="font-semibold mb-2">Motion</h3>
<button id="toggle-motion" aria-pressed="false" class="w-full flex items-center space-x-2 px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded">
<i class="fas fa-running"></i>
<span>Reduce Motion</span>
<span id="motion-status" class="ml-auto text-sm text-gray-500">Off</span>
</button>
</section>
<!-- Screen Reader Helper -->
<section>
<h3 class="font-semibold mb-2">Screen Reader</h3>
<button id="screen-reader-helper" class="w-full flex items-center space-x-2 px-3 py-2 bg-blue-100 hover:bg-blue-200 rounded text-blue-800">
<i class="fas fa-assistive-listening-systems"></i>
<span>Read Important Content</span>
</button>
</section>
<!-- Reset & Close -->
<section class="pt-2 border-t border-gray-200">
<div class="flex space-x-2">
<button id="reset-settings" class="flex-1 px-3 py-2 bg-gray-100 hover:bg-gray-200 rounded">
Reset Settings
</button>
</div>
</section>
</div>
</div>
</div>
</div>
<!-- ARIA Live Region for screen reader announcements -->
<div id="aria-live-region" aria-live="polite" class="sr-only"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
// DOM Elements
const toggleBtn = document.getElementById('accessibility-toggle');
const panel = document.getElementById('accessibility-panel');
const closeBtn = document.getElementById('close-panel');
const increaseTextBtn = document.getElementById('increase-text');
const decreaseTextBtn = document.getElementById('decrease-text');
const textSizeIndicator = document.getElementById('text-size-indicator');
const toggleDyslexicBtn = document.getElementById('toggle-dyslexic');
const dyslexicStatus = document.getElementById('dyslexic-status');
const toggleContrastBtn = document.getElementById('toggle-contrast');
const contrastStatus = document.getElementById('contrast-status');
const toggleCursorBtn = document.getElementById('toggle-cursor');
const cursorStatus = document.getElementById('cursor-status');
const toggleHighlightBtn = document.getElementById('toggle-highlight');
const highlightStatus = document.getElementById('highlight-status');
const toggleMotionBtn = document.getElementById('toggle-motion');
const motionStatus = document.getElementById('motion-status');
const screenReaderHelper = document.getElementById('screen-reader-helper');
const resetBtn = document.getElementById('reset-settings');
const ariaLiveRegion = document.getElementById('aria-live-region');
// State variables
let textSize = 1; // 1 is default (100%), range 0.8 to 1.6
let isDyslexicFont = false;
let isHighContrast = false;
let isLargeCursor = false;
let isHighlightText = false;
let isReducedMotion = false;
let isPanelOpen = false;
// Initialize from localStorage
function loadSettings() {
// Text size
const savedTextSize = localStorage.getItem('accessibilityTextSize');
if (savedTextSize) {
textSize = parseFloat(savedTextSize);
updateTextSize();
}
// Dyslexic font
if (localStorage.getItem('accessibilityDyslexicFont') === 'true') {
isDyslexicFont = true;
document.documentElement.classList.add('dyslexic-font');
dyslexicStatus.textContent = 'On';
toggleDyslexicBtn.setAttribute('aria-pressed', 'true');
}
// High contrast
if (localStorage.getItem('accessibilityHighContrast') === 'true') {
isHighContrast = true;
document.documentElement.classList.add('high-contrast');
contrastStatus.textContent = 'On';
toggleContrastBtn.setAttribute('aria-pressed', 'true');
}
// Large cursor
if (localStorage.getItem('accessibilityLargeCursor') === 'true') {
isLargeCursor = true;
document.documentElement.classList.add('large-cursor');
cursorStatus.textContent = 'On';
toggleCursorBtn.setAttribute('aria-pressed', 'true');
}
// Text highlighting
if (localStorage.getItem('accessibilityHighlightText') === 'true') {
isHighlightText = true;
document.documentElement.classList.add('highlight-text');
highlightStatus.textContent = 'On';
toggleHighlightBtn.setAttribute('aria-pressed', 'true');
}
// Reduced motion
if (localStorage.getItem('accessibilityReducedMotion') === 'true') {
isReducedMotion = true;
document.documentElement.classList.add('reduced-motion');
motionStatus.textContent = 'On';
toggleMotionBtn.setAttribute('aria-pressed', 'true');
}
}
// Update text size
function updateTextSize() {
document.documentElement.style.fontSize = `${textSize * 100}%`;
const percentage = ((textSize - 0.8) / 0.8) * 100;
textSizeIndicator.style.width = `${percentage}%`;
localStorage.setItem('accessibilityTextSize', textSize.toString());
}
// Toggle panel
function togglePanel() {
isPanelOpen = !isPanelOpen;
if (isPanelOpen) {
panel.classList.remove('hidden');
toggleBtn.setAttribute('aria-expanded', 'true');
toggleBtn.classList.remove('pulse-animation');
// Focus first interactive element in panel
setTimeout(() => closeBtn.focus(), 100);
} else {
panel.classList.add('hidden');
toggleBtn.setAttribute('aria-expanded', 'false');
toggleBtn.classList.add('pulse-animation');
}
}
// Announce to screen readers
function announce(message) {
ariaLiveRegion.textContent = message;
// Clear after a short delay so the same message can be announced again
setTimeout(() => {
ariaLiveRegion.textContent = '';
}, 1000);
}
// Event Listeners
toggleBtn.addEventListener('click', togglePanel);
closeBtn.addEventListener('click', togglePanel);
// Increase text size
increaseTextBtn.addEventListener('click', () => {
if (textSize < 1.6) {
textSize += 0.1;
textSize = Math.round(textSize * 10) / 10; // Fix floating point precision
updateTextSize();
announce(`Text size increased to ${Math.round(textSize * 100)}%`);
}
});
// Decrease text size
decreaseTextBtn.addEventListener('click', () => {
if (textSize > 0.8) {
textSize -= 0.1;
textSize = Math.round(textSize * 10) / 10; // Fix floating point precision
updateTextSize();
announce(`Text size decreased to ${Math.round(textSize * 100)}%`);
}
});
// Toggle dyslexic font
toggleDyslexicBtn.addEventListener('click', () => {
isDyslexicFont = !isDyslexicFont;
if (isDyslexicFont) {
document.documentElement.classList.add('dyslexic-font');
dyslexicStatus.textContent = 'On';
toggleDyslexicBtn.setAttribute('aria-pressed', 'true');
localStorage.setItem('accessibilityDyslexicFont', 'true');
announce('Dyslexia-friendly font enabled');
} else {
document.documentElement.classList.remove('dyslexic-font');
dyslexicStatus.textContent = 'Off';
toggleDyslexicBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityDyslexicFont', 'false');
announce('Dyslexia-friendly font disabled');
}
});
// Toggle high contrast
toggleContrastBtn.addEventListener('click', () => {
isHighContrast = !isHighContrast;
if (isHighContrast) {
document.documentElement.classList.add('high-contrast');
contrastStatus.textContent = 'On';
toggleContrastBtn.setAttribute('aria-pressed', 'true');
localStorage.setItem('accessibilityHighContrast', 'true');
announce('High contrast mode enabled');
} else {
document.documentElement.classList.remove('high-contrast');
contrastStatus.textContent = 'Off';
toggleContrastBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityHighContrast', 'false');
announce('High contrast mode disabled');
}
});
// Toggle large cursor
toggleCursorBtn.addEventListener('click', () => {
isLargeCursor = !isLargeCursor;
if (isLargeCursor) {
document.documentElement.classList.add('large-cursor');
cursorStatus.textContent = 'On';
toggleCursorBtn.setAttribute('aria-pressed', 'true');
localStorage.setItem('accessibilityLargeCursor', 'true');
announce('Large cursor enabled');
} else {
document.documentElement.classList.remove('large-cursor');
cursorStatus.textContent = 'Off';
toggleCursorBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityLargeCursor', 'false');
announce('Large cursor disabled');
}
});
// Toggle text highlighting
toggleHighlightBtn.addEventListener('click', () => {
isHighlightText = !isHighlightText;
if (isHighlightText) {
document.documentElement.classList.add('highlight-text');
highlightStatus.textContent = 'On';
toggleHighlightBtn.setAttribute('aria-pressed', 'true');
localStorage.setItem('accessibilityHighlightText', 'true');
announce('Text highlighting enabled');
} else {
document.documentElement.classList.remove('highlight-text');
highlightStatus.textContent = 'Off';
toggleHighlightBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityHighlightText', 'false');
announce('Text highlighting disabled');
}
});
// Toggle reduced motion
toggleMotionBtn.addEventListener('click', () => {
isReducedMotion = !isReducedMotion;
if (isReducedMotion) {
document.documentElement.classList.add('reduced-motion');
motionStatus.textContent = 'On';
toggleMotionBtn.setAttribute('aria-pressed', 'true');
localStorage.setItem('accessibilityReducedMotion', 'true');
announce('Reduced motion enabled');
} else {
document.documentElement.classList.remove('reduced-motion');
motionStatus.textContent = 'Off';
toggleMotionBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityReducedMotion', 'false');
announce('Reduced motion disabled');
}
});
// Screen reader helper
screenReaderHelper.addEventListener('click', () => {
const importantContent = document.querySelector('main').textContent.substring(0, 200) + '...';
announce(`Important content: ${importantContent}`);
});
// Reset settings
resetBtn.addEventListener('click', () => {
// Reset text size
textSize = 1;
updateTextSize();
// Reset dyslexic font
if (isDyslexicFont) {
document.documentElement.classList.remove('dyslexic-font');
dyslexicStatus.textContent = 'Off';
toggleDyslexicBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityDyslexicFont', 'false');
isDyslexicFont = false;
}
// Reset high contrast
if (isHighContrast) {
document.documentElement.classList.remove('high-contrast');
contrastStatus.textContent = 'Off';
toggleContrastBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityHighContrast', 'false');
isHighContrast = false;
}
// Reset large cursor
if (isLargeCursor) {
document.documentElement.classList.remove('large-cursor');
cursorStatus.textContent = 'Off';
toggleCursorBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityLargeCursor', 'false');
isLargeCursor = false;
}
// Reset text highlighting
if (isHighlightText) {
document.documentElement.classList.remove('highlight-text');
highlightStatus.textContent = 'Off';
toggleHighlightBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityHighlightText', 'false');
isHighlightText = false;
}
// Reset reduced motion
if (isReducedMotion) {
document.documentElement.classList.remove('reduced-motion');
motionStatus.textContent = 'Off';
toggleMotionBtn.setAttribute('aria-pressed', 'false');
localStorage.setItem('accessibilityReducedMotion', 'false');
isReducedMotion = false;
}
announce('All accessibility settings have been reset to default');
});
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
// Alt + A to toggle panel
if (e.altKey && e.key.toLowerCase() === 'a') {
e.preventDefault();
togglePanel();
}
// Trap focus inside panel when open
if (isPanelOpen && e.key === 'Tab') {
const focusableElements = panel.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const firstElement = focusableElements[0];
const lastElement = focusableElements[focusableElements.length - 1];
if (e.shiftKey) {
if (document.activeElement === firstElement) {
lastElement.focus();
e.preventDefault();
}
} else {
if (document.activeElement === lastElement) {
firstElement.focus();
e.preventDefault();
}
}
}
// Escape to close panel
if (isPanelOpen && e.key === 'Escape') {
togglePanel();
toggleBtn.focus();
}
});
// Close panel when clicking outside
document.addEventListener('click', (e) => {
if (isPanelOpen && !panel.contains(e.target) && e.target !== toggleBtn) {
togglePanel();
}
});
// Initialize
loadSettings();
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=ham3dco/ham3d" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>