devextreme-cli 1.11.0-alpha.0 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/package.json +10 -9
  2. package/src/application.js +40 -20
  3. package/src/applications/application.angular.js +11 -3
  4. package/src/applications/application.nextjs.js +231 -0
  5. package/src/applications/application.react.js +16 -6
  6. package/src/applications/application.vue.js +6 -11
  7. package/src/templates/nextjs/application/.env +1 -0
  8. package/src/templates/nextjs/application/devextreme.json +63 -0
  9. package/src/templates/nextjs/application/next.config.mjs +32 -0
  10. package/src/templates/nextjs/application/public/logo192.png +0 -0
  11. package/src/templates/nextjs/application/public/logo512.png +0 -0
  12. package/src/templates/nextjs/application/public/manifest.json +25 -0
  13. package/src/templates/nextjs/application/public/robots.txt +3 -0
  14. package/src/templates/nextjs/application/src/app/actions/auth.ts +76 -0
  15. package/src/templates/nextjs/application/src/app/auth/[type]/page.tsx +49 -0
  16. package/src/templates/nextjs/application/src/app/layout.tsx +17 -0
  17. package/src/templates/nextjs/application/src/app/lib/session.ts +47 -0
  18. package/src/templates/nextjs/application/src/app/pages/layout.tsx +18 -0
  19. package/src/templates/nextjs/application/src/app-info.tsx +5 -0
  20. package/src/templates/nextjs/application/src/app-navigation.tsx +21 -0
  21. package/src/templates/nextjs/application/src/components/change-password-form/ChangePasswordForm.tsx +86 -0
  22. package/src/templates/nextjs/application/src/components/create-account-form/CreateAccountForm.scss +19 -0
  23. package/src/templates/nextjs/application/src/components/create-account-form/CreateAccountForm.tsx +107 -0
  24. package/src/templates/nextjs/application/src/components/footer/Footer.scss +12 -0
  25. package/src/templates/nextjs/application/src/components/footer/Footer.tsx +5 -0
  26. package/src/templates/nextjs/application/src/components/header/Header.scss +40 -0
  27. package/src/templates/nextjs/application/src/components/header/Header.tsx +38 -0
  28. package/src/templates/nextjs/application/src/components/index.tsx +7 -0
  29. package/src/templates/nextjs/application/src/components/login-form/LoginForm.scss +12 -0
  30. package/src/templates/nextjs/application/src/components/login-form/LoginForm.tsx +101 -0
  31. package/src/templates/nextjs/application/src/components/reset-password-form/ResetPasswordForm.scss +12 -0
  32. package/src/templates/nextjs/application/src/components/reset-password-form/ResetPasswordForm.tsx +78 -0
  33. package/src/templates/nextjs/application/src/components/side-navigation-menu/SideNavigationMenu.scss +71 -0
  34. package/src/templates/nextjs/application/src/components/side-navigation-menu/SideNavigationMenu.tsx +88 -0
  35. package/src/templates/nextjs/application/src/components/theme-switcher/ThemeSwitcher.tsx +21 -0
  36. package/src/templates/nextjs/application/src/components/user-panel/UserPanel.scss +51 -0
  37. package/src/templates/nextjs/application/src/components/user-panel/UserPanel.tsx +55 -0
  38. package/src/templates/nextjs/application/src/dx-styles.scss +106 -0
  39. package/src/templates/nextjs/application/src/index.css +12 -0
  40. package/src/templates/nextjs/application/src/layouts/index.tsx +3 -0
  41. package/src/templates/nextjs/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.scss +17 -0
  42. package/src/templates/nextjs/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.tsx +133 -0
  43. package/src/templates/nextjs/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.scss +10 -0
  44. package/src/templates/nextjs/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.tsx +119 -0
  45. package/src/templates/nextjs/application/src/layouts/single-card/single-card.scss +42 -0
  46. package/src/templates/nextjs/application/src/layouts/single-card/single-card.tsx +16 -0
  47. package/src/templates/nextjs/application/src/middleware.ts +46 -0
  48. package/src/templates/nextjs/application/src/theme.tsx +66 -0
  49. package/src/templates/nextjs/application/src/themes/metadata.additional.dark.json +11 -0
  50. package/src/templates/nextjs/application/src/themes/metadata.additional.json +11 -0
  51. package/src/templates/nextjs/application/src/themes/metadata.base.dark.json +8 -0
  52. package/src/templates/nextjs/application/src/themes/metadata.base.json +7 -0
  53. package/src/templates/nextjs/application/src/types.tsx +60 -0
  54. package/src/templates/nextjs/application/src/utils/default-user.tsx +7 -0
  55. package/src/templates/nextjs/application/src/utils/media-query.tsx +56 -0
  56. package/src/templates/nextjs/application/src/variables.scss +53 -0
  57. package/src/templates/nextjs/page/page.scss +0 -0
  58. package/src/templates/nextjs/page/page.tsx +13 -0
  59. package/src/templates/nextjs/sample-pages/home/home.scss +37 -0
  60. package/src/templates/nextjs/sample-pages/home/page.tsx +101 -0
  61. package/src/templates/nextjs/sample-pages/profile/page.tsx +61 -0
  62. package/src/templates/nextjs/sample-pages/profile/profile.scss +19 -0
  63. package/src/templates/nextjs/sample-pages/tasks/page.tsx +112 -0
  64. package/src/templates/nextjs/sample-pages/tasks/tasks.scss +3 -0
  65. package/src/templates/react/application/src/App.tsx +2 -1
  66. package/src/templates/react/application/src/Content.tsx +1 -1
  67. package/src/templates/react/application/src/app-routes.tsx +3 -3
  68. package/src/templates/react/application/src/components/change-password-form/ChangePasswordForm.tsx +1 -1
  69. package/src/templates/react/application/src/components/create-account-form/CreateAccountForm.tsx +1 -1
  70. package/src/templates/react/application/src/components/header/Header.scss +1 -1
  71. package/src/templates/react/application/src/components/login-form/LoginForm.tsx +1 -1
  72. package/src/templates/react/application/src/components/side-navigation-menu/SideNavigationMenu.tsx +2 -2
  73. package/src/templates/react/application/src/components/user-panel/UserPanel.tsx +1 -1
  74. package/src/templates/react/application/src/contexts/auth-hooks.ts +8 -0
  75. package/src/templates/react/application/src/contexts/auth.tsx +7 -5
  76. package/src/templates/react/application/src/contexts/navigation-hooks.ts +22 -0
  77. package/src/templates/react/application/src/contexts/navigation.tsx +3 -17
  78. package/src/templates/react/application/src/dx-styles.scss +3 -3
  79. package/src/templates/react/application/src/layouts/side-nav-inner-toolbar/side-nav-inner-toolbar.tsx +3 -3
  80. package/src/templates/react/application/src/layouts/side-nav-outer-toolbar/side-nav-outer-toolbar.tsx +3 -3
  81. package/src/templates/react/application/src/types.tsx +2 -2
  82. package/src/templates/react/page/page.tsx +1 -1
  83. package/src/templates/react/sample-pages/home/home.tsx +1 -1
  84. package/src/templates/react/sample-pages/index.tsx +3 -3
  85. package/src/templates/react/sample-pages/profile/profile.tsx +1 -1
  86. package/src/templates/react/sample-pages/tasks/tasks.tsx +1 -1
  87. package/src/templates/vue-v3/application/eslint.config.js +32 -0
  88. package/src/templates/vue-v3/application/src/App.vue +1 -1
  89. package/src/templates/vue-v3/application/src/components/header-toolbar.vue +2 -2
  90. package/src/templates/vue-v3/application/src/dx-styles.scss +4 -3
  91. package/src/templates/vue-v3/application/src/layouts/side-nav-inner-toolbar.vue +2 -2
  92. package/src/templates/vue-v3/application/src/layouts/side-nav-outer-toolbar.vue +2 -2
  93. package/src/templates/vue-v3/application/src/main.js +1 -1
  94. package/src/templates/vue-v3/application/src/router.js +5 -5
  95. package/src/utility/latest-versions.js +7 -4
  96. package/src/utility/module.js +13 -5
  97. package/src/utility/prompts/react-app-type.js +17 -0
  98. package/src/utility/run-command.js +10 -2
  99. package/src/utility/template-creator.js +8 -4
  100. package/src/templates/vue-v3/application/vue.config.js +0 -1
@@ -0,0 +1,101 @@
1
+ 'use client'
2
+ import <%=#isTypeScript%>React, <%=/isTypeScript%>{ useState, useRef, useCallback } from 'react';
3
+ import { useRouter } from 'next/navigation';
4
+ import Link from 'next/link';
5
+ import Form, {
6
+ Item,
7
+ Label,
8
+ ButtonItem,
9
+ ButtonOptions,
10
+ RequiredRule,
11
+ EmailRule
12
+ } from 'devextreme-react/form';
13
+ import LoadIndicator from 'devextreme-react/load-indicator';
14
+ import Button from 'devextreme-react/button';
15
+ import notify from 'devextreme/ui/notify';
16
+ import { signIn } from '@/app/actions/auth';
17
+
18
+ import './LoginForm.scss';
19
+
20
+ export default function LoginForm() {
21
+ const router = useRouter();
22
+ const [loading, setLoading] = useState(false);
23
+ const formData = useRef({ email: '', password: '' });
24
+
25
+ const onSubmit = useCallback(async (e<%=#isTypeScript%>: React.FormEvent<HTMLFormElement><%=/isTypeScript%>) => {
26
+ e.preventDefault();
27
+ const { email, password } = formData.current;
28
+ setLoading(true);
29
+
30
+ const result = await signIn(email, password);
31
+ if (!result.isOk) {
32
+ setLoading(false);
33
+ notify(result.message, 'error', 2000);
34
+ } else {
35
+ router.push('/');
36
+ }
37
+ }, [router]);
38
+
39
+ const onCreateAccountClick = useCallback(() => {
40
+ router.push('/auth/create-account');
41
+ }, [router]);
42
+
43
+ return (
44
+ <form className={'login-form'} onSubmit={onSubmit}>
45
+ <Form formData={formData.current} disabled={loading}>
46
+ <Item
47
+ dataField={'email'}
48
+ editorType={'dxTextBox'}
49
+ editorOptions={emailEditorOptions}
50
+ >
51
+ <RequiredRule message="Email is required" />
52
+ <EmailRule message="Email is invalid" />
53
+ <Label visible={false} />
54
+ </Item>
55
+ <Item
56
+ dataField={'password'}
57
+ editorType={'dxTextBox'}
58
+ editorOptions={passwordEditorOptions}
59
+ >
60
+ <RequiredRule message="Password is required" />
61
+ <Label visible={false} />
62
+ </Item>
63
+ <Item
64
+ dataField={'rememberMe'}
65
+ editorType={'dxCheckBox'}
66
+ editorOptions={rememberMeEditorOptions}
67
+ >
68
+ <Label visible={false} />
69
+ </Item>
70
+ <ButtonItem>
71
+ <ButtonOptions
72
+ width={'100%'}
73
+ type={'default'}
74
+ useSubmitBehavior={true}
75
+ >
76
+ <span className="dx-button-text">
77
+ {
78
+ loading
79
+ ? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
80
+ : 'Sign In'
81
+ }
82
+ </span>
83
+ </ButtonOptions>
84
+ </ButtonItem>
85
+ </Form>
86
+ <div className={'link'}>
87
+ <Link href={'/auth/reset-password'}>Forgot password?</Link>
88
+ </div>
89
+ <Button
90
+ text={'Create an account'}
91
+ stylingMode={ 'outlined' }
92
+ width={'100%'}
93
+ onClick={onCreateAccountClick}
94
+ />
95
+ </form>
96
+ );
97
+ }
98
+
99
+ const emailEditorOptions = { stylingMode: 'filled', placeholder: 'Email', mode: 'email' };
100
+ const passwordEditorOptions = { stylingMode: 'filled', placeholder: 'Password', mode: 'password' };
101
+ const rememberMeEditorOptions = { text: 'Remember me', elementAttr: { class: 'form-text' } };
@@ -0,0 +1,12 @@
1
+ .reset-password-form {
2
+ .submit-button {
3
+ margin-top: 18px;
4
+ }
5
+
6
+ .login-link {
7
+ color: var(--base-accent);
8
+ font-size: 12px;
9
+ text-align: center;
10
+ margin-top: 6px;
11
+ }
12
+ }
@@ -0,0 +1,78 @@
1
+ 'use client'
2
+ import <%=#isTypeScript%>React, <%=/isTypeScript%>{ useState, useRef, useCallback } from 'react';
3
+ import { useRouter } from 'next/navigation';
4
+ import Link from 'next/link';
5
+ import Form, {
6
+ Item,
7
+ Label,
8
+ ButtonItem,
9
+ ButtonOptions,
10
+ RequiredRule,
11
+ EmailRule
12
+ } from 'devextreme-react/form';
13
+ import LoadIndicator from 'devextreme-react/load-indicator';
14
+ import notify from 'devextreme/ui/notify';
15
+ import { resetPassword } from '@/app/actions/auth';
16
+ import './ResetPasswordForm.scss';
17
+
18
+ const notificationText = 'We\'ve sent a link to reset your password. Check your inbox.';
19
+
20
+ export default function ResetPasswordForm() {
21
+ const router = useRouter();
22
+ const [loading, setLoading] = useState(false);
23
+ const formData = useRef({ email: '', password: '' });
24
+
25
+ const onSubmit = useCallback(async (e<%=#isTypeScript%>: React.FormEvent<HTMLFormElement><%=/isTypeScript%>) => {
26
+ e.preventDefault();
27
+ const { email } = formData.current;
28
+ setLoading(true);
29
+
30
+ const result = await resetPassword(email);
31
+ setLoading(false);
32
+
33
+ if (result.isOk) {
34
+ router.push('/login');
35
+ notify(notificationText, 'success', 2500);
36
+ } else {
37
+ notify(result.message, 'error', 2000);
38
+ }
39
+ }, [router]);
40
+
41
+ return (
42
+ <form className={'reset-password-form'} onSubmit={onSubmit}>
43
+ <Form formData={formData.current} disabled={loading}>
44
+ <Item
45
+ dataField={'email'}
46
+ editorType={'dxTextBox'}
47
+ editorOptions={emailEditorOptions}
48
+ >
49
+ <RequiredRule message="Email is required" />
50
+ <EmailRule message="Email is invalid" />
51
+ <Label visible={false} />
52
+ </Item>
53
+ <ButtonItem>
54
+ <ButtonOptions
55
+ elementAttr={submitButtonAttributes}
56
+ width={'100%'}
57
+ type={'default'}
58
+ useSubmitBehavior={true}
59
+ >
60
+ <span className="dx-button-text">
61
+ {
62
+ loading
63
+ ? <LoadIndicator width={'24px'} height={'24px'} visible={true} />
64
+ : 'Reset my password'
65
+ }
66
+ </span>
67
+ </ButtonOptions>
68
+ </ButtonItem>
69
+ </Form>
70
+ <div className={'login-link'}>
71
+ Return to <Link href={'/login'}>Sign In</Link>
72
+ </div>
73
+ </form>
74
+ );
75
+ }
76
+
77
+ const emailEditorOptions = { stylingMode: 'filled', placeholder: 'Email', mode: 'email' };
78
+ const submitButtonAttributes = { class: 'submit-button' };
@@ -0,0 +1,71 @@
1
+ @use "../../dx-styles" as *;
2
+
3
+ .dx-swatch-additional, .dx-swatch-additional-dark {
4
+ &.side-navigation-menu {
5
+ display: flex;
6
+ flex-direction: column;
7
+ min-height: 100%;
8
+ height: 100%;
9
+ width: 250px !important;
10
+ background-color: var(--base-bg);
11
+
12
+ .menu-container {
13
+ min-height: 100%;
14
+ display: flex;
15
+ flex: 1;
16
+
17
+ .dx-treeview {
18
+ // ## Long text positioning
19
+ white-space: nowrap;
20
+ // ##
21
+
22
+ .dx-treeview-node-container:empty {
23
+ display: none;
24
+ }
25
+
26
+ // ## Icon width customization
27
+ .dx-treeview-item {
28
+ padding-left: 0;
29
+ border-radius: 0;
30
+ flex-direction: row-reverse;
31
+
32
+ .dx-icon {
33
+ width: $side-panel-min-width !important;
34
+ margin: 0 !important;
35
+ }
36
+ }
37
+
38
+ // ##
39
+
40
+ // ## Arrow customization
41
+ .dx-treeview-node {
42
+ padding: 0 0 !important;
43
+ }
44
+
45
+ .dx-treeview-toggle-item-visibility {
46
+ right: 10px;
47
+ left: auto;
48
+ }
49
+
50
+ .dx-rtl .dx-treeview-toggle-item-visibility {
51
+ left: 10px;
52
+ right: auto;
53
+ }
54
+ // ##
55
+
56
+ // ## Item levels customization
57
+ .dx-treeview-node {
58
+ &[aria-level="1"] {
59
+ font-weight: bold;
60
+ }
61
+
62
+ &[aria-level="2"] .dx-treeview-item-content {
63
+ font-weight: normal;
64
+ padding: 0 $side-panel-min-width;
65
+ }
66
+ }
67
+ // ##
68
+ }
69
+ }
70
+ }
71
+ }
@@ -0,0 +1,88 @@
1
+ 'use client'
2
+ import React, { useEffect, useRef, useCallback, useMemo, useContext } from 'react';
3
+ import { TreeView<%=#isTypeScript%>, TreeViewRef<%=/isTypeScript%> } from 'devextreme-react/tree-view';
4
+ import * as events from 'devextreme-react/common/core/events';
5
+ import { navigation } from '@/app-navigation';
6
+ import { usePathname } from 'next/navigation';
7
+ import { useScreenSize } from '@/utils/media-query';
8
+ import './SideNavigationMenu.scss';
9
+ <%=#isTypeScript%>import type { SideNavigationMenuProps } from '@/types';
10
+ <%=/isTypeScript%>import { ThemeContext } from '@/theme';
11
+
12
+ export default function SideNavigationMenu(props<%=#isTypeScript%>: React.PropsWithChildren<SideNavigationMenuProps><%=/isTypeScript%>) {
13
+ const {
14
+ children,
15
+ selectedItemChanged,
16
+ openMenu,
17
+ compactMode,
18
+ onMenuReady
19
+ } = props;
20
+
21
+ const theme = useContext(ThemeContext);
22
+ const { isLarge } = useScreenSize();
23
+ function normalizePath () {
24
+ return navigation.map((item) => (
25
+ { ...item, expanded: isLarge, path: item.path && !(/^\//.test(item.path)) ? `/${item.path}` : item.path }
26
+ ))
27
+ }
28
+
29
+ const items = useMemo(
30
+ normalizePath,
31
+ // eslint-disable-next-line react-hooks/exhaustive-deps
32
+ []
33
+ );
34
+
35
+ const pathname = usePathname();
36
+
37
+ const treeViewRef = useRef<%=#isTypeScript%><TreeViewRef><%=/isTypeScript%>(null);
38
+ const wrapperRef = useRef<%=#isTypeScript%><HTMLDivElement><%=/isTypeScript%>(null);
39
+ const getWrapperRef = useCallback((element<%=#isTypeScript%>: HTMLDivElement<%=/isTypeScript%>) => {
40
+ const prevElement = wrapperRef.current;
41
+ if (prevElement) {
42
+ events.off(prevElement, 'dxclick');
43
+ }
44
+
45
+ wrapperRef.current = element;
46
+ events.on(element, 'dxclick', (e<%=#isTypeScript%>: React.PointerEvent<%=/isTypeScript%>) => {
47
+ openMenu(e);
48
+ });
49
+ }, [openMenu]);
50
+
51
+ useEffect(() => {
52
+ const treeView = treeViewRef.current && treeViewRef.current.instance();
53
+ if (!treeView) {
54
+ return;
55
+ }
56
+
57
+ if (pathname !== undefined) {
58
+ treeView.selectItem(pathname);
59
+ treeView.expandItem(pathname);
60
+ }
61
+
62
+ if (compactMode) {
63
+ treeView.collapseAll();
64
+ }
65
+ }, [pathname, compactMode]);
66
+
67
+ return (
68
+ <div
69
+ className={`dx-swatch-additional${theme?.isDark() ? '-dark' : ''} side-navigation-menu`}
70
+ ref={getWrapperRef}
71
+ >
72
+ {children}
73
+ <div className={'menu-container'}>
74
+ <TreeView
75
+ ref={treeViewRef}
76
+ items={items}
77
+ keyExpr={'path'}
78
+ selectionMode={'single'}
79
+ focusStateEnabled={false}
80
+ expandEvent={'click'}
81
+ onItemClick={selectedItemChanged}
82
+ onContentReady={onMenuReady}
83
+ width={'100%'}
84
+ />
85
+ </div>
86
+ </div>
87
+ );
88
+ }
@@ -0,0 +1,21 @@
1
+ 'use client'
2
+ import { useCallback, useContext } from 'react';
3
+ import Button from 'devextreme-react/button';
4
+ import { ThemeContext } from '@/theme';
5
+
6
+ export const ThemeSwitcher = () => {
7
+ const themeContext = useContext(ThemeContext);
8
+
9
+ const onButtonClick = useCallback(() => {
10
+ themeContext?.switchTheme();
11
+ }, [themeContext]);
12
+
13
+ return <div>
14
+ <Button
15
+ className='theme-button'
16
+ stylingMode='text'
17
+ icon={`${themeContext?.theme === 'dark' ? 'sun' : 'moon'}`}
18
+ onClick={onButtonClick}
19
+ />
20
+ </div>;
21
+ };
@@ -0,0 +1,51 @@
1
+ .app .header-toolbar .user-panel .user-button.dx-dropdownbutton img.dx-icon {
2
+ height: 100%;
3
+ width: auto;
4
+
5
+ .dx-theme-generic & {
6
+ max-height: 32px;
7
+ }
8
+ }
9
+
10
+ .user-panel {
11
+ display: flex;
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
+ }
29
+
30
+
31
+
32
+ .dx-buttongroup {
33
+ vertical-align: middle;
34
+
35
+ .dx-button.dx-button-has-icon:not(.dx-button-has-text) {
36
+ .dx-button-content {
37
+ padding: 0;
38
+ }
39
+
40
+ &.dx-state-hover,
41
+ &.dx-state-focused {
42
+ background-color: transparent;
43
+
44
+ img.dx-icon {
45
+ border-color: var(--dx-color-primary);
46
+ }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
@@ -0,0 +1,55 @@
1
+ 'use client'
2
+ import { useMemo, useCallback } from 'react';
3
+ import { useRouter } from 'next/navigation';
4
+ import DropDownButton from 'devextreme-react/drop-down-button';
5
+ import List from 'devextreme-react/list';
6
+ import { signOut } from '@/app/actions/auth';
7
+ import './UserPanel.scss';
8
+ <%=#isTypeScript%>import type { UserPanelProps } from '@/types';<%=/isTypeScript%>
9
+
10
+ export default function UserPanel({ menuMode }<%=#isTypeScript%>: UserPanelProps<%=/isTypeScript%>) {
11
+ const router = useRouter();
12
+
13
+ const navigateToProfile = useCallback(() => {
14
+ router.push("/pages/profile");
15
+ }, [router]);
16
+
17
+ const menuItems = useMemo(() => ([
18
+ {
19
+ text: 'Profile',
20
+ icon: 'user',
21
+ onClick: navigateToProfile
22
+ },
23
+ {
24
+ text: 'Logout',
25
+ icon: 'runner',
26
+ onClick: signOut
27
+ }
28
+ ]), [navigateToProfile]);
29
+
30
+ const dropDownButtonAttributes = {
31
+ class: 'user-button'
32
+ };
33
+
34
+ const buttonDropDownOptions = {
35
+ width: '150px'
36
+ };
37
+
38
+ return (
39
+ <div className='user-panel'>
40
+ {menuMode === 'context' && (
41
+ <DropDownButton
42
+ stylingMode='text'
43
+ icon='https://js.devexpress.com/Demos/WidgetsGallery/JSDemos/images/employees/06.png'
44
+ showArrowIcon={false}
45
+ elementAttr={dropDownButtonAttributes}
46
+ dropDownOptions={buttonDropDownOptions}
47
+ items={menuItems}>
48
+ </DropDownButton>
49
+ )}
50
+ {menuMode === 'list' && (
51
+ <List items={menuItems} />
52
+ )}
53
+ </div>
54
+ );
55
+ }
@@ -0,0 +1,106 @@
1
+ @use "variables.scss" as *;
2
+
3
+ $side-panel-min-width: 60px;
4
+
5
+ html,
6
+ body {
7
+ margin: 0;
8
+ min-height: 100%;
9
+ height: 100%;
10
+ }
11
+
12
+ .dx-viewport {
13
+ .dx-popup-wrapper {
14
+ z-index: 1510 !important;
15
+ }
16
+
17
+ #root {
18
+ height: 100%;
19
+ }
20
+
21
+ * {
22
+ box-sizing: border-box;
23
+ }
24
+
25
+ .app {
26
+ background-color: var(--base-bg-darken-5);
27
+ display: flex;
28
+ height: 100%;
29
+ width: 100%;
30
+ min-width: 320px;
31
+ }
32
+
33
+ .content {
34
+ line-height: 1.5;
35
+ flex-grow: 1;
36
+ padding: 20px 40px;
37
+
38
+ h2 {
39
+ font-size: 32px;
40
+ margin: 0;
41
+ line-height: 40px;
42
+ }
43
+ }
44
+
45
+ @media (max-width: 599.99px) {
46
+ :not(.dx-card).content {
47
+ padding: 20px;
48
+ }
49
+ }
50
+
51
+ .container {
52
+ height: 100%;
53
+ flex-direction: column;
54
+ display: flex;
55
+ }
56
+
57
+ .layout-body {
58
+ flex: 1;
59
+ min-height: 0;
60
+ }
61
+
62
+ .side-nav-outer-toolbar .dx-drawer {
63
+ height: calc(100% - 56px)
64
+ }
65
+
66
+ .content-block {
67
+ margin-top: 20px;
68
+ }
69
+
70
+ .responsive-paddings {
71
+ padding: 20px;
72
+
73
+ @media (min-width: 1280px) {
74
+ padding: 40px;
75
+ }
76
+ }
77
+
78
+ .dx-card.wide-card {
79
+ border-radius: 0;
80
+ margin-left: 0;
81
+ margin-right: 0;
82
+ border-right: 0;
83
+ border-left: 0;
84
+ }
85
+
86
+ .with-footer > .dx-scrollable-wrapper >
87
+ .dx-scrollable-container > .dx-scrollable-content {
88
+ height: 100%;
89
+
90
+ & > .dx-scrollview-content {
91
+ display: flex;
92
+ flex-direction: column;
93
+ min-height: 100%;
94
+ }
95
+ }
96
+
97
+ }
98
+
99
+ .dx-theme-fluent {
100
+ .dx-drawer-wrapper {
101
+ .dx-drawer-panel-content,
102
+ .dx-overlay-content {
103
+ box-shadow: 0 4px 4px 0 var(--shadow-color-first), 0 1px 2px 0 var(--shadow-color-second);
104
+ }
105
+ }
106
+ }
@@ -0,0 +1,12 @@
1
+ body {
2
+ margin: 0;
3
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
4
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
5
+ sans-serif;
6
+ -moz-osx-font-smoothing: grayscale;
7
+ }
8
+
9
+ code {
10
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
11
+ monospace;
12
+ }
@@ -0,0 +1,3 @@
1
+ export { default as SideNavOuterToolbar } from './side-nav-outer-toolbar/side-nav-outer-toolbar';
2
+ export { default as SideNavInnerToolbar } from './side-nav-inner-toolbar/side-nav-inner-toolbar';
3
+ export { default as SingleCard } from './single-card/single-card';
@@ -0,0 +1,17 @@
1
+ .side-nav-inner-toolbar {
2
+ width: 100%;
3
+ }
4
+
5
+ #navigation-header {
6
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
7
+ background-color: var(--base-bg);
8
+
9
+ @media (max-width: 599.99px) {
10
+ padding-left: 20px;
11
+ }
12
+
13
+ .dx-theme-generic & {
14
+ padding-top: 10px;
15
+ padding-bottom: 10px;
16
+ }
17
+ }