UI: #334 add config page language setting (#374)

* UI: #334 add config page language setting

* temporary remove logout button

* Unify fullscreen view class for dialog expanded and settings view

- Replace dialog-expanded and settings-view with single fullscreen-view class
- Update ResponsiveDialog to use fullscreen-view class
- Update CalendarLayout to use fullscreen-view class for settings view
- Consolidate CSS rules in Menubar.styl to use fullscreen-view
- Update test cases to use new class name

---------

Co-authored-by: Lê Nhân Phụng <lenhanphung@Phung-Mac-M4.local>
This commit is contained in:
lenhanphung
2025-11-28 20:25:06 +07:00
committed by GitHub
parent 6fcf22a1cf
commit 1a85afc57d
15 changed files with 801 additions and 58 deletions
+105
View File
@@ -0,0 +1,105 @@
.main-layout.settings-layout
display flex
flex-direction row
height calc(100vh - 90px)
padding 0 10px 10px 0;
.settings-sidebar
width 350px
height 100%
overflow-y auto
overflow-x hidden
scrollbar-width thin
scrollbar-color transparent transparent
.settings-sidebar::-webkit-scrollbar
width 8px
.settings-sidebar::-webkit-scrollbar-track
background transparent
.settings-sidebar::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
border-radius 4px
opacity 0
transition opacity 0.3s ease
.settings-sidebar:hover::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.5)
opacity 1
.settings-sidebar:hover
scrollbar-color rgba(0, 0, 0, 0.5) transparent
.settings-nav-item
position relative
padding 12px 24px
transition background-color 0.2s ease
cursor pointer
&::before
content ""
position absolute
left 0
top 0
width 0
height 100%
background-color #F67E35
transition width 0.2s ease
&:hover
background-color #f9fafb
&::before
width 4px
.MuiListItemIcon-root
color #F67E35
&.active
&::before
width 4px
.MuiListItemIcon-root
color #F67E35
.settings-content
flex-grow 1
display flex
flex-direction column
height 100%
overflow-y auto
border-radius 16px
background #fff
.settings-content-header
display flex
align-items center
padding 16px 24px
gap 16px
.back-button
.MuiSvgIcon-root
font-size 28px
.settings-content-body
padding 24px
flex-grow 1
.settings-tab-content
text-align left
.settings-content-tabs
.MuiTab-root
color #424244E5
text-transform none
font-weight 600
font-size 24px
.MuiTab-root.Mui-selected
color #424244E5
.MuiTabs-indicator
background-color #F67E35
+155 -2
View File
@@ -1,9 +1,162 @@
import React from "react";
import React, { useState } from "react";
import {
Box,
List,
ListItem,
ListItemIcon,
ListItemText,
Tabs,
Tab,
IconButton,
FormControl,
Select,
MenuItem,
Typography,
} from "@mui/material";
import ArrowBackIcon from "@mui/icons-material/ArrowBack";
import SettingsIcon from "@mui/icons-material/Settings";
import SyncIcon from "@mui/icons-material/Sync";
import { useAppDispatch, useAppSelector } from "../../app/hooks";
import { setView, setLanguage } from "./SettingsSlice";
import { AVAILABLE_LANGUAGES } from "./constants";
import { useI18n } from "cozy-ui/transpiled/react/providers/I18n";
import "./SettingsPage.styl";
type SidebarNavItem = "settings" | "sync";
type SettingsSubTab = "settings" | "notifications";
export default function SettingsPage() {
const dispatch = useAppDispatch();
const { t, lang } = useI18n();
const [activeNavItem, setActiveNavItem] =
useState<SidebarNavItem>("settings");
const [activeSettingsSubTab, setActiveSettingsSubTab] =
useState<SettingsSubTab>("settings");
const handleBackClick = () => {
dispatch(setView("calendar"));
};
const handleNavItemClick = (item: SidebarNavItem) => {
setActiveNavItem(item);
if (item === "settings") {
setActiveSettingsSubTab("settings");
}
};
const handleSettingsSubTabChange = (
_event: React.SyntheticEvent,
newValue: SettingsSubTab
) => {
setActiveSettingsSubTab(newValue);
};
const handleLanguageChange = (event: any) => {
dispatch(setLanguage(event.target.value));
};
return (
<main className="main-layout settings-layout">
<h1>Settings Page</h1>
<Box className="settings-sidebar">
<List>
<ListItem
className={`settings-nav-item ${activeNavItem === "settings" ? "active" : ""}`}
onClick={() => handleNavItemClick("settings")}
sx={{ cursor: "pointer" }}
>
<ListItemIcon>
<SettingsIcon />
</ListItemIcon>
<ListItemText primary={t("settings.title") || "Settings"} />
</ListItem>
{/* <ListItem
className={`settings-nav-item ${activeNavItem === "sync" ? "active" : ""}`}
onClick={() => handleNavItemClick("sync")}
sx={{ cursor: "pointer" }}
>
<ListItemIcon>
<SyncIcon />
</ListItemIcon>
<ListItemText primary={t("settings.sync") || "Sync"} />
</ListItem> */}
</List>
</Box>
<Box className="settings-content">
<Box className="settings-content-header">
<IconButton
onClick={handleBackClick}
aria-label={t("settings.back") || "Back to calendar"}
className="back-button"
>
<ArrowBackIcon />
</IconButton>
{activeNavItem === "settings" && (
<Tabs
value={activeSettingsSubTab}
onChange={handleSettingsSubTabChange}
className="settings-content-tabs"
>
<Tab value="settings" label={t("settings.title") || "Settings"} />
<Tab
value="notifications"
label={t("settings.notifications") || "Notifications"}
/>
</Tabs>
)}
</Box>
<Box className="settings-content-body">
{activeNavItem === "settings" && (
<>
{activeSettingsSubTab === "settings" && (
<Box className="settings-tab-content">
<Typography variant="h6" sx={{ mb: 1 }}>
{t("settings.language") || "Language"}
</Typography>
<Typography
variant="body2"
color="text.secondary"
sx={{ mb: 3 }}
>
{t("settings.languageDescription") ||
"This will be the language used in your Twake Calendar"}
</Typography>
<FormControl size="small" sx={{ minWidth: 500 }}>
<Select
value={lang}
onChange={handleLanguageChange}
variant="outlined"
aria-label={
t("settings.languageSelector") || "Language selector"
}
>
{AVAILABLE_LANGUAGES.map(({ code, label }) => (
<MenuItem key={code} value={code}>
{label}
</MenuItem>
))}
</Select>
</FormControl>
</Box>
)}
{activeSettingsSubTab === "notifications" && (
<Box className="settings-tab-content">
<Typography variant="body1" color="text.secondary">
{t("settings.notifications.empty") ||
"Notifications settings coming soon"}
</Typography>
</Box>
)}
</>
)}
{activeNavItem === "sync" && (
<Box className="settings-tab-content">
<Typography variant="body1" color="text.secondary">
{t("settings.sync.empty") || "Sync settings coming soon"}
</Typography>
</Box>
)}
</Box>
</Box>
</main>
);
}
+6
View File
@@ -0,0 +1,6 @@
export const AVAILABLE_LANGUAGES = [
{ code: "en", label: "English" },
{ code: "fr", label: "Français" },
{ code: "ru", label: "Русский" },
{ code: "vi", label: "Tiếng Việt" },
] as const;