Skip to content

Commit 4ca5cf9

Browse files
remake user panel menu
fix left side menu theme mode while change window width
1 parent 0a6da3b commit 4ca5cf9

File tree

25 files changed

+285
-354
lines changed

25 files changed

+285
-354
lines changed

packages/devextreme-cli/src/templates/react/application/src/components/header/Header.tsx

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,23 +30,13 @@ export default function Header({ menuToggleEnabled, title, toggleMenu }<%=#isTyp
3030
>
3131
<ThemeSwitcher />
3232
</Item>
33-
<Item
34-
location={'after'}
35-
locateInMenu={'auto'}
36-
menuItemTemplate={'userPanelTemplate'}
37-
>
38-
<Button
39-
className={'user-button authorization'}
40-
width={210}
41-
height={'100%'}
42-
stylingMode={'text'}
43-
>
44-
<UserPanel menuMode={'context'} />
45-
</Button>
33+
<Item location='after' locateInMenu='auto' menuItemTemplate='userPanelTemplate'>
34+
<UserPanel menuMode='context' />
4635
</Item>
47-
<Template name={'userPanelTemplate'}>
48-
<UserPanel menuMode={'list'} />
36+
<Template name='userPanelTemplate'>
37+
<UserPanel menuMode='list' />
4938
</Template>
39+
5040
</Toolbar>
5141
</header>
5242
)}

packages/devextreme-cli/src/templates/react/application/src/components/side-navigation-menu/SideNavigationMenu.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1-
import React, { useEffect, useRef, useCallback, useMemo } from 'react';
1+
import React, { useEffect, useRef, useCallback, useMemo, useContext } from 'react';
22
import { TreeView<%=#isTypeScript%>, TreeViewRef<%=/isTypeScript%> } from 'devextreme-react/tree-view';
3+
import * as events from 'devextreme/events';
34
import { navigation } from '../../app-navigation';
45
import { useNavigation } from '../../contexts/navigation';
56
import { useScreenSize } from '../../utils/media-query';
67
import './SideNavigationMenu.scss';
78
<%=#isTypeScript%>import type { SideNavigationMenuProps } from '../../types';<%=/isTypeScript%>
89

9-
import * as events from 'devextreme/events';
10+
import { ThemeContext } from '../../theme';
1011

1112
export default function SideNavigationMenu(props<%=#isTypeScript%>: React.PropsWithChildren<SideNavigationMenuProps><%=/isTypeScript%>) {
1213
const {
@@ -17,6 +18,7 @@ export default function SideNavigationMenu(props<%=#isTypeScript%>: React.PropsW
1718
onMenuReady
1819
} = props;
1920

21+
const theme = useContext(ThemeContext);
2022
const { isLarge } = useScreenSize();
2123
function normalizePath () {
2224
return navigation.map((item) => (
@@ -64,7 +66,7 @@ export default function SideNavigationMenu(props<%=#isTypeScript%>: React.PropsW
6466

6567
return (
6668
<div
67-
className={'dx-swatch-additional side-navigation-menu'}
69+
className={`dx-swatch-additional${theme.isDark() ? '-dark' : ''} side-navigation-menu`}
6870
ref={getWrapperRef}
6971
>
7072
{children}

packages/devextreme-cli/src/templates/react/application/src/components/theme-switcher/ThemeSwitcher.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
import React, { useCallback } from 'react';
1+
import React, { useCallback, useContext } from 'react';
22
import Button from 'devextreme-react/button';
3-
import {useThemeContext} from '../../theme';
3+
import { ThemeContext } from '../../theme';
44

55
export const ThemeSwitcher = () => {
6-
const themeContext = useThemeContext();
6+
const themeContext = useContext(ThemeContext);
77

88
const onButtonClick = useCallback(() => {
99
themeContext?.switchTheme();
Lines changed: 40 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,66 +1,51 @@
1-
@import "../../themes/generated/variables.base.scss";
1+
.app .header-toolbar .user-panel .user-button.dx-dropdownbutton img.dx-icon {
2+
height: 100%;
3+
width: auto;
24

3-
.user-info {
5+
.dx-theme-generic & {
6+
max-height: 32px;
7+
}
8+
}
9+
10+
.user-panel {
411
display: flex;
5-
align-items: center;
12+
flex-direction: column;
13+
14+
.user-button.dx-dropdownbutton {
15+
margin-left: 5px;
16+
17+
img.dx-icon {
18+
border-radius: 50%;
19+
margin: 0;
20+
width: auto;
21+
aspect-ratio: 1 / 1;
22+
box-sizing: border-box;
23+
border: 1px solid var(--dx-color-border);
24+
object-fit: cover;
25+
object-position: top;
26+
background: rgb(255, 255, 255);
27+
background-clip: padding-box;
28+
}
629

7-
.dx-toolbar-menu-section & {
8-
padding: 10px 6px;
9-
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
10-
}
1130

12-
.image-container {
13-
overflow: hidden;
14-
border-radius: 50%;
15-
height: 30px;
16-
width: 30px;
17-
margin: 0 4px;
18-
border: 1px solid rgba(0, 0, 0, 0.1);
19-
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
2031

21-
.user-image {
22-
width: 100%;
23-
height: 100%;
24-
background: url("https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png")
25-
no-repeat #fff;
26-
background-size: cover;
27-
}
28-
}
32+
.dx-buttongroup {
33+
vertical-align: middle;
2934

30-
.user-name {
31-
font-size: 14px;
32-
color: var(--base-text-color);
33-
margin: 0 9px;
34-
}
35-
}
35+
.dx-button.dx-button-has-icon:not(.dx-button-has-text) {
36+
.dx-button-content {
37+
padding: 0;
38+
}
3639

37-
.user-panel {
38-
.dx-list-item .dx-icon {
39-
vertical-align: middle;
40-
color: $base-text-color;
41-
margin-right: 16px;
42-
}
43-
.dx-rtl .dx-list-item .dx-icon {
44-
margin-right: 0;
45-
margin-left: 16px;
46-
}
47-
}
40+
&.dx-state-hover,
41+
&.dx-state-focused {
42+
background-color: transparent;
4843

49-
.dx-context-menu.user-menu.dx-menu-base {
50-
&.dx-rtl {
51-
.dx-submenu .dx-menu-items-container .dx-icon {
52-
margin-left: 16px;
44+
img.dx-icon {
45+
border-color: var(--dx-color-primary);
46+
}
47+
}
48+
}
5349
}
5450
}
55-
.dx-submenu .dx-menu-items-container .dx-icon {
56-
margin-right: 16px;
57-
}
58-
.dx-menu-item .dx-menu-item-content {
59-
padding: 3px 15px 4px;
60-
}
61-
}
62-
63-
.dx-theme-generic .user-menu .dx-menu-item-content .dx-menu-item-text {
64-
padding-left: 4px;
65-
padding-right: 4px;
6651
}
Lines changed: 22 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import React, { useMemo, useCallback } from 'react';
22
import { useNavigate } from "react-router-dom";
3-
import ContextMenu, { Position } from 'devextreme-react/context-menu';
3+
import DropDownButton from 'devextreme-react/drop-down-button';
44
import List from 'devextreme-react/list';
55
import { useAuth } from '../../contexts/auth';
66
import './UserPanel.scss';
77
<%=#isTypeScript%>import type { UserPanelProps } from '../../types';<%=/isTypeScript%>
88

99
export default function UserPanel({ menuMode }<%=#isTypeScript%>: UserPanelProps<%=/isTypeScript%>) {
10-
const { user, signOut } = useAuth();
10+
const { signOut } = useAuth();
1111
const navigate = useNavigate();
1212

1313
const navigateToProfile = useCallback(() => {
1414
navigate("/profile");
1515
}, [navigate]);
16+
1617
const menuItems = useMemo(() => ([
1718
{
1819
text: 'Profile',
@@ -25,34 +26,29 @@ export default function UserPanel({ menuMode }<%=#isTypeScript%>: UserPanelProps
2526
onClick: signOut
2627
}
2728
]), [navigateToProfile, signOut]);
28-
return (
29-
<div className={'user-panel'}>
30-
<div className={'user-info'}>
31-
<div className={'image-container'}>
32-
<div
33-
style={{
34-
background: `url(${user<%=#isTypeScript%>!<%=/isTypeScript%>.avatarUrl}) no-repeat #fff`,
35-
backgroundSize: 'cover'
36-
}}
37-
className={'user-image'} />
38-
</div>
39-
<div className={'user-name'}>{user<%=#isTypeScript%>!<%=/isTypeScript%>.email}</div>
40-
</div>
4129

30+
const dropDownButtonAttributes = {
31+
class: 'user-button'
32+
};
33+
34+
const buttonDropDownOptions = {
35+
width: '150px'
36+
};
37+
38+
return (
39+
<div className='user-panel'>
4240
{menuMode === 'context' && (
43-
<ContextMenu
44-
items={menuItems}
45-
target={'.user-button'}
46-
showEvent={'dxclick'}
47-
width={210}
48-
cssClass={'user-menu'}
49-
>
50-
<Position my={{ x: 'center', y: 'top' }} at={{ x: 'center', y: 'bottom' }} />
51-
</ContextMenu>
41+
<DropDownButton stylingMode='text'
42+
icon='https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png'
43+
showArrowIcon={false}
44+
elementAttr={dropDownButtonAttributes}
45+
dropDownOptions={buttonDropDownOptions}
46+
items={menuItems}>
47+
</DropDownButton>
5248
)}
5349
{menuMode === 'list' && (
54-
<List className={'dx-toolbar-menu-action'} items={menuItems} />
50+
<List items={menuItems} />
5551
)}
5652
</div>
5753
);
58-
}
54+
};

packages/devextreme-cli/src/templates/react/application/src/dx-styles.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ body {
88
}
99

1010
.dx-viewport {
11+
.dx-popup-wrapper {
12+
z-index: 1510 !important;
13+
}
14+
1115
#root {
1216
height: 100%;
1317
}
@@ -17,6 +21,7 @@ body {
1721
}
1822

1923
.app {
24+
background-color: var(--base-bg-darken-5);
2025
display: flex;
2126
height: 100%;
2227
width: 100%;
Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
1+
import React, { useCallback, useMemo, useState } from 'react';
22

33
const themes = ['light', 'dark'];
44
const themeClassNamePrefix = 'dx-swatch-';
5+
let currentTheme = getNextTheme();
56

6-
function getNextTheme(theme?) {
7+
function getNextTheme(theme = null) {
78
return themes[themes.indexOf(theme) + 1] || themes[0];
89
}
910

1011
function getCurrentTheme() {
11-
return getNextTheme();
12+
return currentTheme;
1213
}
1314

14-
function toggleTheme(currentTheme) {
15-
const prevTheme = currentTheme;
15+
function toggleTheme(prevTheme) {
1616
const isCurrentThemeDark = prevTheme === 'dark';
1717

18-
const newTheme = getNextTheme(currentTheme);
18+
const newTheme = getNextTheme(prevTheme);
1919

2020
document.body.classList.replace(
2121
themeClassNamePrefix + prevTheme,
@@ -30,18 +30,24 @@ function toggleTheme(currentTheme) {
3030
.querySelector(`.${additionalClassName}`)?.classList
3131
.replace(additionalClassName, additionalClassNamePrefix + (isCurrentThemeDark ? '' : '-dark'));
3232

33+
currentTheme = newTheme;
34+
3335
return newTheme;
3436
}
3537

3638
export function useThemeContext() {
3739
const [theme, setTheme] = useState(getCurrentTheme());
3840
const switchTheme = useCallback(() => setTheme((currentTheme) => toggleTheme(currentTheme)), []);
3941

42+
const isDark = useCallback(()<%=#isTypeScript%>: boolean<%=/isTypeScript%> => {
43+
return currentTheme === 'dark';
44+
}, []);
45+
4046
if (!document.body.className.includes(themeClassNamePrefix)) {
4147
document.body.classList.add(themeClassNamePrefix + theme);
4248
}
4349

44-
return useMemo(()=> ({ theme, switchTheme }), [theme]);
50+
return useMemo(()=> ({ theme, switchTheme, isDark }), [theme]);
4551
}
4652

4753
export const ThemeContext = React.createContext(null);

packages/devextreme-cli/src/templates/react/application/src/themes/theme-service.js

Lines changed: 0 additions & 37 deletions
This file was deleted.

0 commit comments

Comments
 (0)