adding localization for identity component

This commit is contained in:
Roland Osborne 2024-02-14 23:25:11 -08:00
parent 696dace1bb
commit a6970986d1
8 changed files with 119 additions and 76 deletions

View File

@ -62,7 +62,7 @@ export const DarkTheme = {
headerArea: '#111111',
footerArea: '#111111',
itemArea: '#222222',
hoverArea: '#444444',
hoverArea: '#2f2f2f',
selectedArea: '#333333',
enabledArea: '#448866',
disabledArea: '#888888',

View File

@ -0,0 +1,26 @@
export const en = {
code: 'en',
account: 'Account',
contacts: 'Contacts',
logout: 'Logout',
confirmLogout: 'Are you sure you want to logout?',
contactsUpdated: 'Updated contact status',
disconnected: 'Disconnected from server',
allDevices: 'Logout of all devices',
ok: 'OK',
cancel: 'Cancel',
};
export const fr = {
code: 'fr',
account: 'Compte',
contacts: 'Contacts',
logout: 'Déconnexion',
confirmLogout: 'Êtes-vous sûr de vouloir vous déconnecter?',
contactsUpdated: 'Vos contacts ont changer',
disconnected: 'Déconnecté du serveur',
allDevices: 'Déconnexion de tous les appareils',
ok: 'OK',
cancel: 'Annuler',
};

View File

@ -1,5 +1,6 @@
import { useEffect, useState } from 'react';
import { LightTheme, DarkTheme } from 'constants/Colors';
import { en, fr } from 'constants/Strings';
export function useSettingsContext() {
@ -7,8 +8,11 @@ export function useSettingsContext() {
display: null,
width: null,
height: null,
darkTheme: DarkTheme,
lightTheme: LightTheme,
theme: null,
colors: {},
menuStyle: {},
language: 'en',
strings: en,
});
const SMALL_MEDIUM = 650;
@ -44,13 +48,26 @@ export function useSettingsContext() {
const scheme = localStorage.getItem('color_scheme');
if (scheme === 'dark') {
updateState({ darkTheme: DarkTheme, lightTheme: DarkTheme });
updateState({ theme: scheme, colors: DarkTheme, menuStyle: { backgroundColor: DarkTheme.headerArea, color: DarkTheme.mainText } });
}
else if (scheme === 'light') {
updateState({ darkTheme: LightTheme, lightTheme: LightTheme });
updateState({ theme: scheme, colors: LightTheme, menuStyle: { backgroundColor: LightTheme.headerArea, color: LightTheme.mainText } })
}
else {
updateState({ darkTheme: DarkTheme, lightTheme: LightTheme });
if(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
updateState({ theme: null, colors: DarkTheme, menuStyle: { backgroundColor: DarkTheme.headerArea, color: DarkTheme.mainText } });
}
else {
updateState({ theme: null, colors: LightTheme, menuStyle: { backgroundColor: LightTheme.headerArea, color: LightTheme.mainText } });
}
}
const language = localStorage.getItem('language');
if (language && language.startsWith('fr')) {
updateState({ language: 'fr', strings: fr });
}
else {
updateState({ language: 'en', strings: en });
}
return () => {
@ -61,18 +78,32 @@ export function useSettingsContext() {
}, []);
const actions = {
setDarkTheme() {
setDarkTheme: () => {
localStorage.setItem('color_scheme', 'dark');
updateState({ darkTheme: DarkTheme, lightTheme: DarkTheme });
updateState({ theme: 'dark', colors: DarkTheme, menuStyle: { backgroundColor: DarkTheme.headerArea, color: DarkTheme.mainText } });
},
setLightTheme() {
setLightTheme : () => {
localStorage.setItem('color_scheme', 'light');
updateState({ darkTheme: LightTheme, lightTheme: LightTheme });
updateState({ theme: 'light', colors: LightTheme, menuStyle: { backgroundColor: LightTheme.headerArea, color: LightTheme.mainText } });
},
steDefaultTheme() {
setDefaultTheme: () => {
localStorage.clearItem('color_scheme');
updateState({ darkTheme: DarkTheme, lightTheme: LightTheme });
}
if(window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
updateState({ theme: null, colors: DarkTheme, menuStyle: { backgroundColor: DarkTheme.headerArea, color: DarkTheme.mainText } });
}
else {
updateState({ theme: null, colors: LightTheme, menuStyle: { backgroundColor: LightTheme.headerArea, color: LightTheme.mainText } });
}
},
setLanguage: (code: string) => {
localStorage.setItem('language', code);
if (code && code.startsWith('fr')) {
updateState({ language: 'fr', strings: fr });
}
else {
updateState({ language: 'en', strings: en });
}
},
}
return { state, actions }

View File

@ -14,6 +14,14 @@
padding-bottom: 16px !important;
}
.ant-switch {
background: #888888 !important;
}
.ant-switch-checked {
background: #448866 !important;
}
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',

View File

@ -159,7 +159,7 @@ export function Session() {
}
return (
<ThemeProvider theme={{ light: settings.state.lightTheme, dark: settings.state.darkTheme }}>
<ThemeProvider theme={settings.state.colors}>
<SessionWrapper>
{ (state.display === 'xlarge') && (
<div class="desktop-layout noselect">

View File

@ -13,30 +13,32 @@ export function Identity({ openAccount, openCards, cardUpdated }) {
const logout = () => {
modal.confirm({
title: 'Are you sure you want to logout?',
title: <span style={state.menuStyle}>{state.strings.confirmLogout}</span>,
icon: <LogoutOutlined />,
content: <LogoutContent onClick={(e) => e.stopPropagation()}>
<span className="logoutMode">Logout of All Devices </span>
<Switch onChange={(e) => {all.current = e}} size="small" />
<span className="logoutMode">{ state.strings.allDevices }</span>
<Switch onChange={(e) => all.current = e} size="small" />
</LogoutContent>,
bodyStyle: { padding: 16 },
bodyStyle: { padding: 16, ...state.menuStyle },
okText: state.strings.ok,
onOk() {
actions.logout(all.current);
},
cancelText: state.strings.cancel,
onCancel() {},
});
}
const menu = (
<Menu>
<Menu.Item key="0">
<div onClick={openAccount}>Account</div>
<Menu style={state.menuStyle}>
<Menu.Item style={state.menuStyle} key="0">
<div onClick={openAccount}>{ state.strings.account }</div>
</Menu.Item>
<Menu.Item key="1">
<div onClick={openCards}>Contacts</div>
<Menu.Item style={state.menuStyle} key="1">
<div onClick={openCards}>{ state.strings.contacts }</div>
</Menu.Item>
<Menu.Item key="2">
<div onClick={logout}>Logout</div>
<Menu.Item style={state.menuStyle} key="2">
<div onClick={logout}>{ state.strings.logout }</div>
</Menu.Item>
</Menu>
);
@ -48,12 +50,12 @@ export function Identity({ openAccount, openCards, cardUpdated }) {
{ state.init && (
<Logo url={state.url} width={40} height={40} radius={4} />
)}
<div class="label">
<div class="name">{state.name}</div>
<div class="handle">
<div class="notice">
<div className="label">
<div className="name">{state.name}</div>
<div className="handle">
<div className="notice">
{ state.status !== 'connected' && (
<Tooltip placement="right" title="disconnected from server">
<Tooltip placement="right" title={state.strings.disconnected}>
<ErrorNotice>
<ExclamationCircleOutlined />
</ErrorNotice>
@ -61,9 +63,9 @@ export function Identity({ openAccount, openCards, cardUpdated }) {
)}
</div>
<div>{state.handle}</div>
<div class="notice">
<div className="notice">
{ cardUpdated && (
<Tooltip placement="right" title="contacts have updated">
<Tooltip placement="right" title={state.strings.contactsUpdated}>
<InfoNotice>
<InfoCircleOutlined />
</InfoNotice>
@ -72,7 +74,7 @@ export function Identity({ openAccount, openCards, cardUpdated }) {
</div>
</div>
</div>
<div class="drop">
<div className="drop">
<DownOutlined />
</div>
</IdentityWrapper>

View File

@ -1,5 +1,4 @@
import styled from 'styled-components';
import { Colors } from 'constants/Colors';
export const IdentityWrapper = styled.div`
width: 100%;
@ -9,26 +8,14 @@ export const IdentityWrapper = styled.div`
align-items: center;
padding-left: 16px;
padding-right: 16px;
@media (prefers-color-scheme: light) {
background-color: ${props => props.theme.light.headerArea};
border-bottom: 1px solid ${props => props.theme.light.sectionLine};
color: ${props => props.theme.light.mainText};
}
@media (prefers-color-scheme: dark) {
background-color: ${props => props.theme.dark.headerArea};
border-bottom: 1px solid ${props => props.theme.dark.sectionLine};
color: ${props => props.theme.dark.mainText};
}
background-color: ${props => props.theme.headerArea};
border-bottom: 1px solid ${props => props.theme.sectionLine};
color: ${props => props.theme.mainText};
flex-shrink: 0;
&:hover {
cursor: pointer;
@media (prefers-color-scheme: light) {
background-color: ${props => props.theme.light.hoverArea};
}
@media (prefers-color-scheme: dark) {
background-color: ${props => props.theme.dark.hoverArea};
}
background-color: ${props => props.theme.hoverArea};
.drop {
font-weight: bold;
@ -39,14 +26,8 @@ export const IdentityWrapper = styled.div`
padding-left: 4px;
padding-right: 4px;
border-radius: 8px;
@media (prefers-color-scheme: light) {
border: 1px solid ${props => props.theme.light.sectionLine};
color: ${props => props.theme.light.mainText};
}
@media (prefers-color-scheme: dark) {
border: 1px solid ${props => props.theme.dark.sectionLine};
color: ${props => props.theme.dark.mainText};
}
border: 1px solid ${props => props.theme.sectionLine};
color: ${props => props.theme.mainText};
}
.label {
@ -88,30 +69,15 @@ export const LogoutContent = styled.div`
.logoutMode {
padding-right: 8px;
@media (prefers-color-scheme: light) {
color: ${props => props.theme.light.mainText};
}
@media (prefers-color-scheme: dark) {
color: ${props => props.theme.dark.mainText};
}
color: ${props => props.theme.mainText};
}
`
export const ErrorNotice = styled.div`
@media (prefers-color-scheme: light) {
color: ${props => props.theme.light.alertText};
}
@media (prefers-color-scheme: dark) {
color: ${props => props.theme.dark.alertText};
}
color: ${props => props.theme.alertText};
`
export const InfoNotice = styled.div`
@media (prefers-color-scheme: light) {
color: ${props => props.theme.light.linkText};
}
@media (prefers-color-scheme: dark) {
color: ${props => props.theme.dark.linkText};
}
color: ${props => props.theme.linkText};
`

View File

@ -1,6 +1,7 @@
import { useState, useEffect, useContext } from 'react';
import { ProfileContext } from 'context/ProfileContext';
import { AppContext } from 'context/AppContext';
import { SettingsContext } from 'context/SettingsContext';
export function useIdentity() {
@ -10,10 +11,14 @@ export function useIdentity() {
handle: null,
status: null,
init: false,
strings: {},
colors: {},
menuStyle: {},
});
const app = useContext(AppContext);
const profile = useContext(ProfileContext);
const settings = useContext(SettingsContext);
const updateState = (value) => {
setState((s) => ({ ...s, ...value }));
@ -32,6 +37,11 @@ export function useIdentity() {
updateState({ status });
}, [app.state]);
useEffect(() => {
const { colors, strings, menuStyle } = settings.state;
updateState({ colors, strings, menuStyle });
}, [settings.state]);
const actions = {
logout: (all) => {
app.actions.logout(all);