Initial commit
This commit is contained in:
266
components/phases/AtlantisAccessibilityControls.tsx
Normal file
266
components/phases/AtlantisAccessibilityControls.tsx
Normal file
@@ -0,0 +1,266 @@
|
||||
'use client';
|
||||
|
||||
import React, { useState, useContext, useEffect } from 'react';
|
||||
import { Panel } from 'primereact/panel';
|
||||
import { InputSwitch } from 'primereact/inputswitch';
|
||||
import { Slider } from 'primereact/slider';
|
||||
import { Dropdown } from 'primereact/dropdown';
|
||||
import { Button } from 'primereact/button';
|
||||
import { Message } from 'primereact/message';
|
||||
import { LayoutContext } from '../../layout/context/layoutcontext';
|
||||
|
||||
interface AtlantisAccessibilityControlsProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
interface AccessibilitySettings {
|
||||
fontSize: number;
|
||||
highContrast: boolean;
|
||||
reduceMotion: boolean;
|
||||
screenReader: boolean;
|
||||
keyboardNav: boolean;
|
||||
}
|
||||
|
||||
const AtlantisAccessibilityControls: React.FC<AtlantisAccessibilityControlsProps> = ({
|
||||
className = ''
|
||||
}) => {
|
||||
const { layoutConfig, setLayoutConfig } = useContext(LayoutContext);
|
||||
const [settings, setSettings] = useState<AccessibilitySettings>({
|
||||
fontSize: 14,
|
||||
highContrast: false,
|
||||
reduceMotion: false,
|
||||
screenReader: false,
|
||||
keyboardNav: true
|
||||
});
|
||||
|
||||
// Options de thème pour l'accessibilité
|
||||
const contrastThemes = [
|
||||
{ label: 'Thème normal', value: 'magenta' },
|
||||
{ label: 'Contraste élevé - Bleu', value: 'blue' },
|
||||
{ label: 'Contraste élevé - Sombre', value: 'dark' }
|
||||
];
|
||||
|
||||
// Appliquer les paramètres d'accessibilité
|
||||
useEffect(() => {
|
||||
// Appliquer la taille de police via scale Atlantis
|
||||
setLayoutConfig(prev => ({
|
||||
...prev,
|
||||
scale: settings.fontSize
|
||||
}));
|
||||
|
||||
// Appliquer le thème de contraste
|
||||
if (settings.highContrast) {
|
||||
setLayoutConfig(prev => ({
|
||||
...prev,
|
||||
theme: 'blue', // Thème avec meilleur contraste
|
||||
colorScheme: 'dark'
|
||||
}));
|
||||
}
|
||||
|
||||
// Classes CSS pour les animations
|
||||
const rootElement = document.documentElement;
|
||||
if (settings.reduceMotion) {
|
||||
rootElement.style.setProperty('--transition-duration', '0ms');
|
||||
} else {
|
||||
rootElement.style.removeProperty('--transition-duration');
|
||||
}
|
||||
|
||||
// Annoncer les changements pour les lecteurs d'écran
|
||||
if (settings.screenReader) {
|
||||
announceChange('Paramètres d\'accessibilité mis à jour');
|
||||
}
|
||||
|
||||
}, [settings, setLayoutConfig]);
|
||||
|
||||
// Fonction d'annonce pour lecteurs d'écran
|
||||
const announceChange = (message: string) => {
|
||||
const announcement = document.createElement('div');
|
||||
announcement.setAttribute('aria-live', 'polite');
|
||||
announcement.setAttribute('aria-atomic', 'true');
|
||||
announcement.className = 'sr-only';
|
||||
announcement.textContent = message;
|
||||
document.body.appendChild(announcement);
|
||||
setTimeout(() => document.body.removeChild(announcement), 1000);
|
||||
};
|
||||
|
||||
const updateSetting = (key: keyof AccessibilitySettings, value: any) => {
|
||||
setSettings(prev => ({ ...prev, [key]: value }));
|
||||
};
|
||||
|
||||
const resetToDefaults = () => {
|
||||
setSettings({
|
||||
fontSize: 14,
|
||||
highContrast: false,
|
||||
reduceMotion: false,
|
||||
screenReader: false,
|
||||
keyboardNav: true
|
||||
});
|
||||
|
||||
setLayoutConfig(prev => ({
|
||||
...prev,
|
||||
scale: 14,
|
||||
theme: 'magenta',
|
||||
colorScheme: 'dark'
|
||||
}));
|
||||
|
||||
announceChange('Paramètres d\'accessibilité réinitialisés');
|
||||
};
|
||||
|
||||
return (
|
||||
<Panel
|
||||
header="Paramètres d'accessibilité"
|
||||
toggleable
|
||||
collapsed
|
||||
className={`card ${className}`}
|
||||
pt={{
|
||||
header: { className: 'surface-100' },
|
||||
content: { className: 'surface-50' }
|
||||
}}
|
||||
>
|
||||
<div className="grid">
|
||||
{/* Taille de police */}
|
||||
<div className="col-12 md:col-6">
|
||||
<div className="field">
|
||||
<label htmlFor="fontSize" className="font-semibold text-color">
|
||||
Taille de police: {settings.fontSize}px
|
||||
</label>
|
||||
<Slider
|
||||
id="fontSize"
|
||||
value={settings.fontSize}
|
||||
onChange={(e) => updateSetting('fontSize', e.value)}
|
||||
min={12}
|
||||
max={20}
|
||||
step={1}
|
||||
className="w-full mt-2"
|
||||
/>
|
||||
<div className="flex justify-content-between text-xs text-color-secondary mt-1">
|
||||
<span>Petit</span>
|
||||
<span>Normal</span>
|
||||
<span>Grand</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Contraste élevé */}
|
||||
<div className="col-12 md:col-6">
|
||||
<div className="field">
|
||||
<label htmlFor="highContrast" className="font-semibold text-color">
|
||||
Mode contraste élevé
|
||||
</label>
|
||||
<div className="flex align-items-center gap-2 mt-2">
|
||||
<InputSwitch
|
||||
id="highContrast"
|
||||
checked={settings.highContrast}
|
||||
onChange={(e) => updateSetting('highContrast', e.value)}
|
||||
/>
|
||||
<span className="text-sm text-color-secondary">
|
||||
{settings.highContrast ? 'Activé' : 'Désactivé'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Réduction des animations */}
|
||||
<div className="col-12 md:col-6">
|
||||
<div className="field">
|
||||
<label htmlFor="reduceMotion" className="font-semibold text-color">
|
||||
Réduire les animations
|
||||
</label>
|
||||
<div className="flex align-items-center gap-2 mt-2">
|
||||
<InputSwitch
|
||||
id="reduceMotion"
|
||||
checked={settings.reduceMotion}
|
||||
onChange={(e) => updateSetting('reduceMotion', e.value)}
|
||||
/>
|
||||
<span className="text-sm text-color-secondary">
|
||||
Pour les utilisateurs sensibles au mouvement
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Mode lecteur d'écran */}
|
||||
<div className="col-12 md:col-6">
|
||||
<div className="field">
|
||||
<label htmlFor="screenReader" className="font-semibold text-color">
|
||||
Mode lecteur d'écran
|
||||
</label>
|
||||
<div className="flex align-items-center gap-2 mt-2">
|
||||
<InputSwitch
|
||||
id="screenReader"
|
||||
checked={settings.screenReader}
|
||||
onChange={(e) => updateSetting('screenReader', e.value)}
|
||||
/>
|
||||
<span className="text-sm text-color-secondary">
|
||||
Annonces vocales activées
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Informations et aide */}
|
||||
<div className="mt-4">
|
||||
<Message
|
||||
severity="info"
|
||||
text="Ces paramètres améliorent l'accessibilité selon vos besoins"
|
||||
className="w-full"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Raccourcis clavier */}
|
||||
<div className="card mt-3">
|
||||
<h6 className="mt-0 mb-3 text-color">Raccourcis clavier disponibles</h6>
|
||||
<div className="grid text-sm">
|
||||
<div className="col-12 md:col-6">
|
||||
<div className="flex align-items-center gap-2 mb-2">
|
||||
<kbd className="bg-surface-200 text-color px-2 py-1 border-round text-xs">Tab</kbd>
|
||||
<span className="text-color-secondary">Naviguer entre les éléments</span>
|
||||
</div>
|
||||
<div className="flex align-items-center gap-2 mb-2">
|
||||
<kbd className="bg-surface-200 text-color px-2 py-1 border-round text-xs">Entrée</kbd>
|
||||
<span className="text-color-secondary">Activer un élément</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-12 md:col-6">
|
||||
<div className="flex align-items-center gap-2 mb-2">
|
||||
<kbd className="bg-surface-200 text-color px-2 py-1 border-round text-xs">Échap</kbd>
|
||||
<span className="text-color-secondary">Fermer un dialogue</span>
|
||||
</div>
|
||||
<div className="flex align-items-center gap-2 mb-2">
|
||||
<kbd className="bg-surface-200 text-color px-2 py-1 border-round text-xs">↑↓</kbd>
|
||||
<span className="text-color-secondary">Naviguer dans les listes</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex justify-content-between align-items-center mt-4">
|
||||
<Button
|
||||
label="Réinitialiser"
|
||||
icon="pi pi-refresh"
|
||||
className="p-button-outlined"
|
||||
onClick={resetToDefaults}
|
||||
/>
|
||||
|
||||
<div className="flex align-items-center gap-2">
|
||||
<i className="pi pi-info-circle text-primary" />
|
||||
<span className="text-sm text-color-secondary">
|
||||
Paramètres sauvegardés automatiquement
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Région pour les annonces lecteurs d'écran */}
|
||||
<div
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
className="sr-only"
|
||||
id="accessibility-announcements"
|
||||
/>
|
||||
</Panel>
|
||||
);
|
||||
};
|
||||
|
||||
export default AtlantisAccessibilityControls;
|
||||
Reference in New Issue
Block a user