@gm-pc/react 1.7.3 → 1.8.2-alpha.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gm-pc/react",
3
- "version": "1.7.3",
3
+ "version": "1.8.2-alpha.0",
4
4
  "description": "观麦前端基础组件库",
5
5
  "author": "liyatang <liyatang@qq.com>",
6
6
  "homepage": "https://github.com/gmfe/gm-pc#readme",
@@ -24,7 +24,7 @@
24
24
  "dependencies": {
25
25
  "@gm-common/hooks": "^2.10.0",
26
26
  "@gm-common/tool": "^2.10.0",
27
- "@gm-pc/locales": "^1.7.3",
27
+ "@gm-pc/locales": "^1.8.2-alpha.0",
28
28
  "big.js": "^6.0.1",
29
29
  "classnames": "^2.2.5",
30
30
  "lodash": "^4.17.19",
@@ -46,5 +46,5 @@
46
46
  "react-dom": "^16.14.0",
47
47
  "react-window": "^1.8.5"
48
48
  },
49
- "gitHead": "67caf496a31288b7c0217aa3447ac5077f14385f"
49
+ "gitHead": "e76d58dfbce746845287f32e3bc2e859fba52aff"
50
50
  }
@@ -10,10 +10,13 @@ const Nav: FC<NavProps> = ({
10
10
  data,
11
11
  selected,
12
12
  onSelect,
13
+ onPushCreate,
13
14
  showActive,
14
15
  other,
15
16
  className,
16
17
  style,
18
+ footerImage,
19
+ footerConfig,
17
20
  ...rest
18
21
  }) => {
19
22
  // 根据鼠标点到导航栏右边的线距离,判断移动方向
@@ -83,10 +86,25 @@ const Nav: FC<NavProps> = ({
83
86
  data={one}
84
87
  selected={selected}
85
88
  onSelect={onSelect}
89
+ onPushCreate={onPushCreate}
86
90
  />
87
91
  ))}
88
92
  {other}
89
93
  </Flex>
94
+ <div className='gm-nav-footer-iot'>
95
+ {footerConfig?.map((item) => (
96
+ <NavItem
97
+ key={item.link}
98
+ showSub={hoverLink === item.link}
99
+ onMouseMove={handleMouseMove}
100
+ data={item}
101
+ selected={selected}
102
+ onSelect={onSelect}
103
+ onPushCreate={onPushCreate}
104
+ footerImage={footerImage}
105
+ />
106
+ ))}
107
+ </div>
90
108
  <div id='gmNavPopupContainer' />
91
109
  </Flex>
92
110
  )
@@ -19,7 +19,9 @@ const NavItem: FC<NavItemProps> = ({
19
19
  selected,
20
20
  onSelect,
21
21
  onMouseMove,
22
+ onPushCreate,
22
23
  showSub,
24
+ footerImage,
23
25
  }) => {
24
26
  const ref = useRef<HTMLDivElement>(null)
25
27
  const [rect, setRect] = useState<DOMRect | null>(null)
@@ -54,15 +56,22 @@ const NavItem: FC<NavItemProps> = ({
54
56
 
55
57
  return (
56
58
  <div ref={ref} className={classNames('gm-nav-one-box', { active, hover: !!rect })}>
57
- <A
58
- href={link}
59
- className='gm-nav-one'
60
- onClick={handleClick}
61
- onMouseMove={(e) => onMouseMove(e, link)}
62
- >
63
- <span className='gm-nav-one-icon'>{iconE}</span>
64
- <span className='gm-nav-one-text'>{name}</span>
65
- </A>
59
+ {footerImage ? (
60
+ <A href={link} onClick={handleClick} onMouseMove={(e) => onMouseMove(e, link)}>
61
+ {footerImage}
62
+ </A>
63
+ ) : (
64
+ <A
65
+ href={link}
66
+ className='gm-nav-one'
67
+ onClick={handleClick}
68
+ onMouseMove={(e) => onMouseMove(e, link)}
69
+ >
70
+ <span className='gm-nav-one-icon'>{iconE}</span>
71
+ <span className='gm-nav-one-text'>{name}</span>
72
+ </A>
73
+ )}
74
+
66
75
  {sub && <div className='gm-nav-one-triangle' />}
67
76
  {sub && (
68
77
  <Portal>
@@ -72,6 +81,7 @@ const NavItem: FC<NavItemProps> = ({
72
81
  data={sub}
73
82
  selected={selected}
74
83
  onSelect={handleSelect}
84
+ onPushCreate={(data) => onPushCreate(data)}
75
85
  />
76
86
  )}
77
87
  </Portal>
@@ -1,10 +1,16 @@
1
- import React, { FC, useLayoutEffect, useRef, useState } from 'react'
1
+ import React, { FC, MouseEventHandler, useLayoutEffect, useRef, useState } from 'react'
2
2
  import { PopupProps } from './types'
3
3
  import classNames from 'classnames'
4
4
  import { Flex } from '../flex'
5
5
  import A from './a'
6
6
 
7
- const Popup: FC<PopupProps> = ({ parentRect, data, selected, onSelect }) => {
7
+ const Popup: FC<PopupProps> = ({
8
+ parentRect,
9
+ data,
10
+ selected,
11
+ onSelect,
12
+ onPushCreate,
13
+ }) => {
8
14
  const refDom = useRef<HTMLDivElement>(null)
9
15
  const [marginTop, setMarginTop] = useState(0)
10
16
 
@@ -16,31 +22,72 @@ const Popup: FC<PopupProps> = ({ parentRect, data, selected, onSelect }) => {
16
22
  }
17
23
  }, [parentRect])
18
24
 
25
+ /**
26
+ * 在 对应的 div 设置了 最大宽度 900 px
27
+ * @description UI 图是超过五个换行, 现在无论多少模块都在一行, 根据UI图对宽度进行处理
28
+ * @param number 二级菜单的个数
29
+ * @returns popup 的宽度
30
+ */
31
+ const setPopupWidth = (number: number): string => {
32
+ // 只有一个的基本宽度, 根据 UI图, 一个三级路由占据的 宽度 + 左右margin
33
+ const baseWidth = 212
34
+ // 有多个模块 半句的最大宽段, 超出 900 换行
35
+ const maxWidth = baseWidth + (number - 1) * 172
36
+ return maxWidth + 'px'
37
+ }
38
+
39
+ const handleMouseEnter: MouseEventHandler<HTMLDivElement> = (e) => {
40
+ e.currentTarget.classList.add('gm-nav-three-wrap-bg')
41
+ }
42
+
43
+ const handleMouseLeave: MouseEventHandler<HTMLDivElement> = (e) => {
44
+ e.currentTarget.classList.remove('gm-nav-three-wrap-bg')
45
+ }
46
+
19
47
  return (
20
48
  <div
21
49
  ref={refDom}
22
50
  className='gm-nav-popup'
23
- style={{ marginTop: `${marginTop}px`, top: parentRect.top }}
51
+ style={{
52
+ marginTop: `${marginTop}px`,
53
+ top: parentRect.top,
54
+ width: `${setPopupWidth(data.length)}`,
55
+ maxWidth: '900px',
56
+ }}
24
57
  >
25
- <Flex>
58
+ <Flex wrap>
26
59
  {data.map((v, i) => (
27
60
  <div key={i} className='gm-nav-two' style={v.style}>
28
61
  {!!v.name && <div className='gm-nav-two-title'>{v.name}</div>}
29
62
  <div>
30
63
  {v.sub.map((s, si) => (
31
- <A
32
- key={si}
33
- href={s.link}
34
- className={classNames('gm-nav-three', {
64
+ <div
65
+ className={classNames('gm-nav-three-wrap', {
35
66
  active: selected.startsWith(s.link),
36
67
  })}
37
- onClick={(event) => {
38
- event.preventDefault()
39
- onSelect(s)
40
- }}
68
+ key={si}
69
+ onMouseEnter={handleMouseEnter}
70
+ onMouseLeave={handleMouseLeave}
41
71
  >
42
- {s.name}
43
- </A>
72
+ <A
73
+ key={si}
74
+ href={s.link}
75
+ className='gm-nav-three'
76
+ onClick={(event) => {
77
+ event.preventDefault()
78
+ onSelect(s)
79
+ }}
80
+ >
81
+ {s.name}
82
+ </A>
83
+ {s.toCreate && (
84
+ <span
85
+ className='gm-nav-three-create'
86
+ title={s.toCreate.tip}
87
+ onClick={() => onPushCreate(s)}
88
+ />
89
+ )}
90
+ </div>
44
91
  ))}
45
92
  </div>
46
93
  </div>
@@ -1,19 +1,23 @@
1
+ :root {
2
+ --gm-nav-popup-item-color: #454545;
3
+ --gm-nav-popup-item-hover-color: #0363ff;
4
+ --gm-nav-background-color: #282c36;
5
+ }
6
+
1
7
  .gm-nav {
2
- width: var(--gm-nav-size-width);
8
+ width: 136px;
3
9
  height: 100vh;
4
- background: #243351;
10
+ background: var(--gm-nav-background-color);
5
11
 
6
12
  .gm-nav-logo {
7
- text-align: center;
8
- height: 60px;
9
13
  display: flex;
10
14
  align-content: center;
11
15
  justify-content: center;
16
+ height: 64px;
17
+ text-align: center;
12
18
  cursor: pointer;
13
-
14
- &:hover {
15
- background: #17233d;
16
- }
19
+ background-color: #fff;
20
+ box-shadow: inset -1px 0 0 0 #e8ecf3;
17
21
  }
18
22
 
19
23
  .gm-nav-content {
@@ -25,54 +29,150 @@
25
29
  }
26
30
  }
27
31
 
32
+ .gm-nav-footer-iot {
33
+ width: 100%;
34
+ height: 64px;
35
+ cursor: pointer;
36
+ }
37
+
28
38
  .gm-nav-one {
29
- height: 50px;
30
- padding-left: 20px;
31
- text-decoration: none;
32
- color: rgba(255, 255, 255, 80%);
33
39
  display: flex;
34
40
  align-items: center;
35
- opacity: 0.8;
41
+ position: relative;
42
+ padding: 16px 20px;
43
+ color: #fff;
44
+ text-decoration: none;
36
45
 
37
46
  .gm-nav-one-icon {
47
+ margin-right: 10px;
38
48
  font-size: 18px;
39
49
  line-height: 1;
40
- margin-right: 6px;
41
50
  }
42
51
 
43
52
  .gm-nav-one-text {
44
- font-size: 14px;
53
+ font-size: 16px;
54
+ }
55
+
56
+ &::after {
57
+ content: '';
58
+ position: absolute;
59
+ right: 20px;
60
+ top: 21px;
61
+ height: 7px;
62
+ width: 7px;
63
+ border: 1px solid #fff;
64
+ opacity: 0.36;
65
+ border-top: none;
66
+ border-left: none;
67
+ transform: rotate(-45deg);
45
68
  }
46
69
  }
47
70
 
48
71
  .gm-nav-popup {
49
- color: var(--gm-color-default);
50
- background: white;
51
72
  position: absolute;
52
73
  top: 0;
53
- left: var(--gm-nav-size-width);
54
- box-shadow: 1px 1px 6px 1px rgba(36, 51, 81, 0.2);
74
+ left: 136px;
75
+ padding: 24px 8px 0 32px;
76
+ color: var(--gm-color-default);
77
+ background: #fff;
78
+ box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3);
79
+
80
+ .gm-nav-two {
81
+ min-width: 148px;
82
+ margin-right: 24px;
83
+ margin-bottom: 24px;
84
+
85
+ .gm-nav-two-title {
86
+ margin-bottom: 16px;
87
+ font-size: 16px;
88
+ font-weight: 600;
89
+ color: var(--gm-nav-popup-item-color);
90
+ }
91
+ }
92
+
93
+ .gm-nav-three-wrap {
94
+ position: relative;
95
+ margin-bottom: 8px;
96
+ background: #f7f7f7;
97
+
98
+ &.gm-nav-three-wrap-bg {
99
+ background-color: #dae7ff;
100
+ }
101
+
102
+ &.active {
103
+ color: var(--gm-color-primary-active);
104
+ background-color: #dae7ff;
105
+ }
106
+
107
+ .gm-nav-three {
108
+ display: inline-block;
109
+ padding: 8px;
110
+ // width: 100%;
111
+ font-size: 14px;
112
+ color: var(--gm-color-default);
113
+ text-decoration: none;
114
+ white-space: nowrap;
115
+ border-radius: 2px;
116
+
117
+ &:last-child {
118
+ margin-bottom: 0;
119
+ }
120
+
121
+ &:hover {
122
+ color: var(--gm-nav-popup-item-hover-color);
123
+ background-color: #dae7ff;
124
+ }
125
+
126
+ span {
127
+ font-size: 18px;
128
+ color: #99999a;
129
+ cursor: pointer;
130
+
131
+ &:hover {
132
+ color: var(--gm-nav-popup-item-hover-color);
133
+ }
134
+ }
135
+ }
136
+
137
+ .gm-nav-three-create {
138
+ position: absolute;
139
+ top: 7px;
140
+ right: 4px;
141
+ z-index: 10;
142
+ width: 20px;
143
+ height: 20px;
144
+ background-image: url(../../images/add.png);
145
+ background-size: cover;
146
+ cursor: pointer;
147
+
148
+ &:hover {
149
+ background-image: url(../../images/add-hover.png);
150
+ }
151
+ }
152
+ }
55
153
  }
56
154
 
155
+ // 第一级 item
57
156
  .gm-nav-one-box {
58
157
  position: relative;
59
158
 
159
+ // 三角形
60
160
  .gm-nav-one-triangle {
61
- display: none;
62
161
  position: absolute;
162
+ top: 19px;
163
+ right: -1px;
164
+ display: none;
63
165
  width: 0;
64
166
  height: 0;
65
167
  border: 6px solid transparent;
66
168
  border-right: 6px solid white;
67
- top: 18px;
68
- right: -1px;
69
169
  }
70
170
 
71
171
  &.hover {
72
172
  .gm-nav-one {
73
173
  color: white;
174
+ background-color: #1c2129;
74
175
  opacity: 1;
75
- background: rgba(40, 113, 187, 0.4);
76
176
  }
77
177
 
78
178
  .gm-nav-one-triangle {
@@ -82,9 +182,35 @@
82
182
 
83
183
  &.active {
84
184
  .gm-nav-one {
85
- color: white;
185
+ position: relative;
186
+ color: #fff;
187
+ background: #181b23;
86
188
  opacity: 1;
87
- background: rgba(40, 113, 187, 1);
189
+ font-weight: 600;
190
+
191
+ &::before {
192
+ content: '';
193
+ position: absolute;
194
+ left: 0;
195
+ top: 0;
196
+ height: 100%;
197
+ width: 3px;
198
+ background-color: #0363ff;
199
+ }
200
+
201
+ &::after {
202
+ content: '';
203
+ position: absolute;
204
+ right: 20px;
205
+ top: 22px;
206
+ height: 7px;
207
+ width: 7px;
208
+ border: 1px solid #fff;
209
+ opacity: 1;
210
+ border-top: none;
211
+ border-left: none;
212
+ transform: rotate(-45deg);
213
+ }
88
214
  }
89
215
 
90
216
  .gm-nav-one-triangle {
@@ -92,40 +218,4 @@
92
218
  }
93
219
  }
94
220
  }
95
-
96
- .gm-nav-two {
97
- min-width: 110px;
98
- padding: 20px 10px 20px;
99
-
100
- .gm-nav-two-title {
101
- color: var(--gm-color-default);
102
- padding: 0 0 10px;
103
- font-weight: 600;
104
- font-size: 14px;
105
- border-bottom: 1px solid #f0f1f3;
106
- margin: 0 10px 8px;
107
- }
108
- }
109
-
110
- .gm-nav-three {
111
- display: block;
112
- padding: 0 10px;
113
- margin: 2px 0;
114
- font-size: 14px;
115
- line-height: 30px;
116
- text-decoration: none;
117
- color: var(--gm-color-default);
118
- border-radius: 2px;
119
- white-space: nowrap;
120
-
121
- &:hover {
122
- color: var(--gm-color-primary);
123
- background-color: var(--gm-color-bg-back);
124
- }
125
-
126
- &.active {
127
- color: var(--gm-color-primary-active);
128
- background-color: var(--gm-color-bg-back);
129
- }
130
- }
131
221
  }
@@ -1,8 +1,20 @@
1
1
  import { CSSProperties, ReactNode, MouseEvent } from 'react'
2
2
 
3
+ interface NavExtraProps {
4
+ /** 直接到达新建页面 */
5
+ onPushCreate(data: NavDataLevel3): void
6
+ /** 底部一级菜单显示图片 */
7
+ footerImage?: ReactNode
8
+ }
9
+
3
10
  interface NavDataLevel3 {
4
11
  link: string
5
12
  name: string
13
+ /** 配置跳转到对应新建页的 提示 和 地址 */
14
+ toCreate?: {
15
+ tip: string
16
+ href: string
17
+ }
6
18
  }
7
19
 
8
20
  interface NavDataLevel2 {
@@ -20,7 +32,7 @@ interface NavData {
20
32
  sub: NavDataLevel2[]
21
33
  }
22
34
 
23
- interface NavProps {
35
+ interface NavProps extends NavExtraProps {
24
36
  logo?: ReactNode
25
37
  /** 三级菜单 没有sub就没有浮层 */
26
38
  data: NavData[]
@@ -33,9 +45,11 @@ interface NavProps {
33
45
  other?: ReactNode
34
46
  className?: string
35
47
  style?: CSSProperties
48
+ /** 底部 iot 图片 & 数据 */
49
+ footerConfig?: NavData[]
36
50
  }
37
51
 
38
- interface NavItemProps {
52
+ interface NavItemProps extends NavExtraProps {
39
53
  data: NavData
40
54
  selected: string
41
55
  onSelect(data: NavDataLevel3): void
@@ -50,6 +64,7 @@ interface PopupProps {
50
64
  data: NavDataLevel2[]
51
65
  selected: string
52
66
  onSelect(data: NavDataLevel3): void
67
+ onPushCreate(data: NavDataLevel3): void
53
68
  }
54
69
 
55
70
  type NavSingleItemData = Omit<NavData, 'sub'>
@@ -96,7 +96,7 @@
96
96
 
97
97
  // 具体业务
98
98
  // nav
99
- --gm-nav-size-width: 92px;
99
+ --gm-nav-size-width: 136px;
100
100
  // modal
101
101
  --gm-modal-size-title-height: 40px;
102
102
  // switch
Binary file
Binary file