feat: Complete mobile UX/UI overhaul
Major improvements: - New CSS design system with custom properties (tokens) - Consistent spacing scale (4px base) - Touch-friendly sizing (44px min targets) - Improved Carousel with better touch handling and rubber-band effect - Enhanced FilterControls (auto-collapse on mobile) - Better stat card styling with change indicators - Refined chart cards and toggle switches - Smoother transitions and micro-interactions - Better RTL support - Print styles - Responsive breakpoints for tablet (1024px), mobile (768px), and small mobile (375px) - Cleaner typography hierarchy - Subtle shadows and depth Components updated: - App.css: Complete rewrite with design tokens - Carousel.jsx: Better touch gestures with velocity detection - StatCard.jsx: Improved change indicator styling - FilterControls.jsx: Auto-collapse on mobile - EmptyState.jsx: Better accessibility - ChartExport.js: Cleaned up unused imports
This commit is contained in:
82
src/contexts/LanguageContext.js
Normal file
82
src/contexts/LanguageContext.js
Normal file
@@ -0,0 +1,82 @@
|
||||
import React, { createContext, useContext, useState, useEffect, useCallback } from 'react';
|
||||
import en from '../locales/en.json';
|
||||
import ar from '../locales/ar.json';
|
||||
|
||||
const translations = { en, ar };
|
||||
|
||||
const LanguageContext = createContext();
|
||||
|
||||
export function LanguageProvider({ children }) {
|
||||
const [lang, setLang] = useState(() => {
|
||||
// Check localStorage first, then browser preference
|
||||
const saved = localStorage.getItem('hihala-lang');
|
||||
if (saved && translations[saved]) return saved;
|
||||
|
||||
// Check browser language
|
||||
const browserLang = navigator.language?.split('-')[0];
|
||||
if (browserLang === 'ar') return 'ar';
|
||||
return 'en';
|
||||
});
|
||||
|
||||
const dir = lang === 'ar' ? 'rtl' : 'ltr';
|
||||
|
||||
// Apply direction to document
|
||||
useEffect(() => {
|
||||
document.documentElement.dir = dir;
|
||||
document.documentElement.lang = lang;
|
||||
localStorage.setItem('hihala-lang', lang);
|
||||
}, [lang, dir]);
|
||||
|
||||
// Translation function with dot notation support
|
||||
const t = useCallback((key, fallback) => {
|
||||
const keys = key.split('.');
|
||||
let value = translations[lang];
|
||||
|
||||
for (const k of keys) {
|
||||
if (value && typeof value === 'object' && k in value) {
|
||||
value = value[k];
|
||||
} else {
|
||||
// Try English fallback
|
||||
value = translations.en;
|
||||
for (const ek of keys) {
|
||||
if (value && typeof value === 'object' && ek in value) {
|
||||
value = value[ek];
|
||||
} else {
|
||||
return fallback || key;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return typeof value === 'string' ? value : (fallback || key);
|
||||
}, [lang]);
|
||||
|
||||
// Switch language
|
||||
const switchLanguage = useCallback(() => {
|
||||
setLang(prev => prev === 'en' ? 'ar' : 'en');
|
||||
}, []);
|
||||
|
||||
// Set specific language
|
||||
const setLanguage = useCallback((newLang) => {
|
||||
if (translations[newLang]) {
|
||||
setLang(newLang);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<LanguageContext.Provider value={{ lang, dir, t, switchLanguage, setLanguage }}>
|
||||
{children}
|
||||
</LanguageContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export function useLanguage() {
|
||||
const context = useContext(LanguageContext);
|
||||
if (!context) {
|
||||
throw new Error('useLanguage must be used within a LanguageProvider');
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
export default LanguageContext;
|
||||
Reference in New Issue
Block a user