acessibility
This commit is contained in:
@@ -1,15 +1,17 @@
|
||||
<script lang="ts">
|
||||
import { mapState, UMD_LOCATIONS } from '$lib/states/map.svelte';
|
||||
|
||||
import { themeState } from '$lib/states/theme.svelte';
|
||||
|
||||
let { showDropdown = true } = $props<{ showDropdown?: boolean }>();
|
||||
|
||||
const legendItems = [
|
||||
{ label: 'Harmful (80+ dB)', color: '#f38ba8' },
|
||||
{ label: 'Disruptive (65-79 dB)', color: '#fab387' },
|
||||
{ label: 'Manageable (55-64 dB)', color: '#f9e2af' },
|
||||
{ label: 'Great (40-54 dB)', color: '#94e2d5' },
|
||||
{ label: 'Ideal (0-39 dB)', color: '#89b4fa' }
|
||||
];
|
||||
const legendItems = $derived([
|
||||
{ label: 'Harmful (80+ dB)', color: themeState.isColorBlindFriendly ? '#e66100' : '#f38ba8' },
|
||||
{ label: 'Disruptive (65-79 dB)', color: themeState.isColorBlindFriendly ? '#ffb000' : '#fab387' },
|
||||
{ label: 'Manageable (55-64 dB)', color: themeState.isColorBlindFriendly ? '#f0e442' : '#f9e2af' },
|
||||
{ label: 'Great (40-54 dB)', color: themeState.isColorBlindFriendly ? '#56b4e9' : '#94e2d5' },
|
||||
{ label: 'Ideal (0-39 dB)', color: themeState.isColorBlindFriendly ? '#0072b2' : '#89b4fa' }
|
||||
]);
|
||||
</script>
|
||||
|
||||
<div class="absolute top-6 right-6 md:right-8 z-20 flex flex-col gap-3 items-end">
|
||||
|
||||
@@ -12,7 +12,7 @@ export const UMD_LOCATIONS: StudyLocation[] = [
|
||||
{ id: 'mckeldin', name: 'McKeldin Library', hasFloors: true, floors: ['Floor 1', 'Floor 2', 'Floor 3', 'Floor 4', 'Floor 5', 'Floor 6', 'Floor 7'], lng: -76.94494907523277, lat: 38.986021017749366 },
|
||||
{ id: 'hornbake', name: 'Hornbake Library', hasFloors: false, lng: -76.94161787005467, lat: 38.988233373664826 },
|
||||
{ id: 'stem', name: 'STEM Library', hasFloors: false, lng: -76.93942003731279, lat: 38.988991437126195 },
|
||||
{ id: 'clarice', name: 'Clarice Library', hasFloors: false, lng: -76.94967344225785, lat: 38.99029330703877 },
|
||||
{ id: 'clarice', name: 'Clarice Library', hasFloors: false, lng: -76.9500912552473, lat: 38.990547823732285 },
|
||||
{ id: 'yahentamitsi', name: 'Yahentamitsi', hasFloors: false, lng: -76.9448027183373, lat: 38.99108961575231 },
|
||||
{ id: 'iribe', name: 'Iribe', hasFloors: false, lng: -76.93643838603555, lat: 38.98933701397555 },
|
||||
{ id: 'reckord', name: 'Reckord Armory', hasFloors: false, lng: -76.93897470250619, lat: 38.98609556181066 },
|
||||
|
||||
@@ -2,15 +2,61 @@ import { browser } from '$app/environment';
|
||||
|
||||
class ThemeState {
|
||||
isLight = $state(false);
|
||||
isHighContrast = $state(false);
|
||||
isColorBlindFriendly = $state(false);
|
||||
|
||||
constructor() {
|
||||
if (browser) {
|
||||
this.isLight = localStorage.getItem('theme') === 'light';
|
||||
this.isHighContrast = localStorage.getItem('highContrast') === 'true';
|
||||
this.isColorBlindFriendly = localStorage.getItem('colorBlind') === 'true';
|
||||
this.updateDOM();
|
||||
}
|
||||
}
|
||||
|
||||
toggle() {
|
||||
this.isLight = !this.isLight;
|
||||
if (browser) {
|
||||
localStorage.setItem('theme', this.isLight ? 'light' : 'dark');
|
||||
this.updateDOM();
|
||||
}
|
||||
}
|
||||
|
||||
toggleHighContrast() {
|
||||
this.isHighContrast = !this.isHighContrast;
|
||||
if (browser) {
|
||||
localStorage.setItem('highContrast', this.isHighContrast ? 'true' : 'false');
|
||||
this.updateDOM();
|
||||
}
|
||||
}
|
||||
|
||||
toggleColorBlind() {
|
||||
this.isColorBlindFriendly = !this.isColorBlindFriendly;
|
||||
if (browser) {
|
||||
localStorage.setItem('colorBlind', this.isColorBlindFriendly ? 'true' : 'false');
|
||||
this.updateDOM();
|
||||
}
|
||||
}
|
||||
|
||||
private updateDOM() {
|
||||
if (browser) {
|
||||
if (this.isLight) {
|
||||
document.documentElement.classList.add('light-theme');
|
||||
} else {
|
||||
document.documentElement.classList.remove('light-theme');
|
||||
}
|
||||
|
||||
if (this.isHighContrast) {
|
||||
document.documentElement.classList.add('high-contrast');
|
||||
} else {
|
||||
document.documentElement.classList.remove('high-contrast');
|
||||
}
|
||||
|
||||
if (this.isColorBlindFriendly) {
|
||||
document.documentElement.classList.add('color-blind');
|
||||
} else {
|
||||
document.documentElement.classList.remove('color-blind');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +43,26 @@
|
||||
color: #585b70 !important;
|
||||
}
|
||||
|
||||
.light-theme .border-white {
|
||||
/* Color Blind (Protanopia/Deuteranopia safe swaps) */
|
||||
:root.color-blind {
|
||||
--color-neon-primary: #ffb86c;
|
||||
--color-neon-blue: #8be9fd;
|
||||
}
|
||||
|
||||
/* High Contrast: Pitch black backgrounds and pure white texts */
|
||||
:root.high-contrast {
|
||||
--color-crust: #000000;
|
||||
--color-mantle: #0a0a0a;
|
||||
--color-base: #111111;
|
||||
}
|
||||
|
||||
:root.light-theme.high-contrast {
|
||||
--color-crust: #ffffff;
|
||||
--color-mantle: #f4f4f4;
|
||||
--color-base: #ebebeb;
|
||||
}
|
||||
|
||||
.light-theme border-white {
|
||||
border-color: rgba(88, 91, 112, 0.1);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,15 @@
|
||||
|
||||
<svelte:head>
|
||||
<title>EchoNode | Settings</title>
|
||||
<script>
|
||||
window.googleTranslateElementInit = function() {
|
||||
new window.google.translate.TranslateElement({
|
||||
pageLanguage: 'en',
|
||||
layout: window.google.translate.TranslateElement.InlineLayout.SIMPLE
|
||||
}, 'google_translate_element');
|
||||
};
|
||||
</script>
|
||||
<script src="https://translate.google.com/translate_a/element.js?cb=googleTranslateElementInit" async defer></script>
|
||||
</svelte:head>
|
||||
|
||||
<div class="relative w-full h-full bg-crust border-l border-white/5 p-6 md:p-12 overflow-y-auto duration-500 transition-colors">
|
||||
@@ -27,12 +36,15 @@
|
||||
<section class="glass-panel p-6 md:p-8 rounded-2xl border-white/10 shadow-xl">
|
||||
<h2 class="font-display text-xl text-white mb-6 flex items-center gap-2 border-b border-white/10 pb-3">
|
||||
<Icon icon="mdi:palette-outline" class="text-neon-blue" />
|
||||
Appearance
|
||||
Appearance and Accesibility
|
||||
</h2>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between p-4 md:p-6 bg-mantle/40 rounded-xl border border-white/5 hover:border-white/10 transition-colors gap-4">
|
||||
<div class="pr-4">
|
||||
<h3 class="font-display font-medium text-white text-lg">Light / Dark Mode</h3>
|
||||
<h3 class="font-display font-medium text-white text-lg flex items-center gap-2">
|
||||
<Icon icon="mdi:theme-light-dark" class="text-neon-primary" />
|
||||
Light / Dark Mode
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<button onclick={handleLightModeClick} class="shrink-0 px-5 py-2.5 bg-surface0 rounded-xl border border-white/10 hover:border-yellow-400/50 hover:text-yellow-400 hover:bg-surface1 transition-all flex items-center justify-center gap-2 font-medium">
|
||||
@@ -40,6 +52,44 @@
|
||||
{themeState.isLight ? "Enable Dark Mode" : "Enable Light Mode"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between p-4 md:p-6 bg-mantle/40 rounded-xl border border-white/5 hover:border-white/10 transition-colors gap-4 mt-4">
|
||||
<div class="pr-4">
|
||||
<h3 class="font-display font-medium text-white text-lg flex items-center gap-2">
|
||||
<Icon icon="mdi:contrast-circle" class="text-neon-primary" />
|
||||
High Contrast Mode
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<button onclick={() => themeState.toggleHighContrast()} class="shrink-0 px-5 py-2.5 bg-surface0 rounded-xl border border-white/10 hover:border-white/20 transition-all flex items-center justify-center gap-2 font-medium">
|
||||
<Icon icon={themeState.isHighContrast ? "mdi:toggle-switch" : "mdi:toggle-switch-off-outline"} class="text-2xl {themeState.isHighContrast ? 'text-neon-primary' : 'text-slate-400'}" />
|
||||
{themeState.isHighContrast ? "Enabled" : "Disabled"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between p-4 md:p-6 bg-mantle/40 rounded-xl border border-white/5 hover:border-white/10 transition-colors gap-4 mt-4">
|
||||
<div class="pr-4">
|
||||
<h3 class="font-display font-medium text-white text-lg flex items-center gap-2">
|
||||
<Icon icon="mdi:eye-outline" class="text-neon-primary" />
|
||||
Color Blind Friendly
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<button onclick={() => themeState.toggleColorBlind()} class="shrink-0 px-5 py-2.5 bg-surface0 rounded-xl border border-white/10 hover:border-white/20 transition-all flex items-center justify-center gap-2 font-medium">
|
||||
<Icon icon={themeState.isColorBlindFriendly ? "mdi:toggle-switch" : "mdi:toggle-switch-off-outline"} class="text-2xl {themeState.isColorBlindFriendly ? 'text-neon-primary' : 'text-slate-400'}" />
|
||||
{themeState.isColorBlindFriendly ? "Enabled" : "Disabled"}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col md:flex-row md:items-center justify-between p-4 md:p-6 bg-mantle/40 rounded-xl border border-white/5 hover:border-white/10 transition-colors gap-4 mt-4">
|
||||
<div class="pr-4">
|
||||
<h3 class="font-display font-medium text-white text-lg flex items-center gap-2"><Icon icon="mdi:translate" class="text-neon-primary" /> Global Translation</h3>
|
||||
</div>
|
||||
|
||||
<div class="shrink-0 p-2 bg-surface0 border border-white/10 rounded-xl overflow-hidden min-h-[44px] flex items-center justify-center">
|
||||
<div id="google_translate_element" class="scale-90 origin-right"></div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user