@veltra/desktop 1.2.32 → 1.2.34

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 (63) hide show
  1. package/dist/components/action/action-group.vue.d.ts +1 -1
  2. package/dist/components/auto-complete/auto-complete.vue.d.ts +2 -2
  3. package/dist/components/batch-edit/batch-edit.vue.d.ts +8 -8
  4. package/dist/components/cascade/cascade.vue.d.ts +8 -8
  5. package/dist/components/checkbox-group/checkbox-group.vue.d.ts +2 -2
  6. package/dist/components/date-picker/date-picker.vue.d.ts +2 -2
  7. package/dist/components/date-range-picker/date-range-picker.vue.d.ts +2 -2
  8. package/dist/components/dual-nav/dual-nav-app.js +17 -4
  9. package/dist/components/dual-nav/dual-nav-app.js.map +1 -1
  10. package/dist/components/dual-nav/dual-nav.js +5 -2
  11. package/dist/components/dual-nav/dual-nav.js.map +1 -1
  12. package/dist/components/dual-nav/dual-nav.vue.d.ts +4 -3
  13. package/dist/components/dual-nav/style2.css +22 -0
  14. package/dist/components/group-nav/group-nav-item.js +40 -0
  15. package/dist/components/group-nav/group-nav-item.js.map +1 -0
  16. package/dist/components/group-nav/group-nav.js +47 -0
  17. package/dist/components/group-nav/group-nav.js.map +1 -0
  18. package/dist/components/group-nav/group-nav.vue.d.ts +13 -0
  19. package/dist/components/group-nav/index.d.ts +1 -0
  20. package/dist/components/group-nav/style.d.ts +1 -0
  21. package/dist/components/group-nav/style.js +3 -0
  22. package/dist/components/group-nav/style2.css +119 -0
  23. package/dist/components/index.d.ts +20 -19
  24. package/dist/components/index.js +22 -20
  25. package/dist/components/index.js.map +1 -1
  26. package/dist/components/input/input.vue.d.ts +4 -4
  27. package/dist/components/multi-select/multi-select.vue.d.ts +5 -5
  28. package/dist/components/multi-tree-select/multi-tree-select.vue.d.ts +8 -8
  29. package/dist/components/number/number.vue.d.ts +1 -1
  30. package/dist/components/number-input/number-input.vue.d.ts +4 -4
  31. package/dist/components/number-range-input/number-range-input.vue.d.ts +1 -1
  32. package/dist/components/password-input/password-input.vue.d.ts +1 -1
  33. package/dist/components/pop-confirm/pop-confirm.vue.d.ts +1 -1
  34. package/dist/components/progress-nodes/progress-nodes.vue.d.ts +2 -2
  35. package/dist/components/radio-group/radio-group.vue.d.ts +2 -2
  36. package/dist/components/rich-text-editor/rich-text-editor.vue.d.ts +1 -1
  37. package/dist/components/select/select.vue.d.ts +4 -4
  38. package/dist/components/tabs/tabs-horizontal.vue.d.ts +2 -2
  39. package/dist/components/tabs/tabs-vertical.vue.d.ts +2 -2
  40. package/dist/components/tabs/tabs.vue.d.ts +2 -2
  41. package/dist/components/textarea/textarea.vue.d.ts +4 -4
  42. package/dist/components/tree/tree.vue.d.ts +2 -2
  43. package/dist/components/tree-select/tree-select.vue.d.ts +7 -7
  44. package/dist/index.d.ts +50 -48
  45. package/dist/index.js +46 -45
  46. package/dist/style.js +1 -0
  47. package/dist/types/dual-nav.d.ts +9 -1
  48. package/dist/types/group-nav.d.ts +22 -0
  49. package/dist/types/index.d.ts +3 -2
  50. package/package.json +6 -6
  51. package/src/components/dual-nav/dual-nav-app.vue +22 -3
  52. package/src/components/dual-nav/dual-nav.vue +3 -2
  53. package/src/components/dual-nav/style.scss +30 -1
  54. package/src/components/group-nav/group-nav-item.vue +32 -0
  55. package/src/components/group-nav/group-nav.vue +36 -0
  56. package/src/components/group-nav/index.ts +1 -0
  57. package/src/components/group-nav/style.scss +121 -0
  58. package/src/components/group-nav/style.ts +3 -0
  59. package/src/components/index.ts +2 -0
  60. package/src/style.ts +1 -0
  61. package/src/types/dual-nav.ts +9 -0
  62. package/src/types/group-nav.ts +20 -0
  63. package/src/types/index.ts +1 -0
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <u-tip v-model:visible="tipVisible" direction="right" hide-arrow :disabled="tipSuppressed">
2
+ <u-tip v-model:visible="tipVisible" direction="right" hide-arrow :disabled="tipDisabled">
3
3
  <button
4
4
  type="button"
5
5
  v-ripple="!app.disabled"
@@ -15,6 +15,7 @@
15
15
  >
16
16
  <UNavIcon v-if="app.icon" :icon="app.icon" :class="cls.e('app-icon')" />
17
17
  <span v-else :class="cls.e('app-fallback')">{{ app.title[0] }}</span>
18
+ <span v-if="labeled" :class="cls.e('app-label')">{{ displayTitle }}</span>
18
19
  </button>
19
20
 
20
21
  <template #content>
@@ -31,7 +32,7 @@
31
32
  <script setup lang="ts">
32
33
  import { vRipple } from '@veltra/directives'
33
34
  import { bem } from '@veltra/utils'
34
- import { shallowRef } from 'vue'
35
+ import { computed, shallowRef } from 'vue'
35
36
 
36
37
  import type { DualNavRootItem } from '../../types'
37
38
  import UNavIcon from '../nav/nav-icon.vue'
@@ -41,7 +42,16 @@ defineOptions({ name: 'UDualNavApp' })
41
42
 
42
43
  const cls = bem('dual-nav')
43
44
 
44
- defineProps<{ app: DualNavRootItem; active: boolean; selected: boolean }>()
45
+ /** 左轨菜单名称最多展示字数 */
46
+ const LABEL_MAX_LENGTH = 4
47
+
48
+ const props = defineProps<{
49
+ app: DualNavRootItem
50
+ active: boolean
51
+ selected: boolean
52
+ /** 是否在图标下方显示菜单名称 */
53
+ labeled?: boolean
54
+ }>()
45
55
 
46
56
  const emit = defineEmits<{ click: [] }>()
47
57
 
@@ -49,6 +59,15 @@ const tipVisible = shallowRef(false)
49
59
  /** 点击后暂时禁用 hover 弹出,移出触发区后恢复 */
50
60
  const tipSuppressed = shallowRef(false)
51
61
 
62
+ const displayTitle = computed(() => props.app.title.slice(0, LABEL_MAX_LENGTH))
63
+
64
+ /** labeled 且标题未截断、无描述时,tooltip 无额外信息 */
65
+ const tipUnnecessary = computed(() => {
66
+ return !!props.labeled && props.app.title.length <= LABEL_MAX_LENGTH && !props.app.description
67
+ })
68
+
69
+ const tipDisabled = computed(() => tipSuppressed.value || tipUnnecessary.value)
70
+
52
71
  function handleClick() {
53
72
  tipSuppressed.value = true
54
73
  tipVisible.value = false
@@ -1,5 +1,5 @@
1
1
  <template>
2
- <div :class="cls.b">
2
+ <div :class="[cls.b, railVariant === 'labeled' && cls.m('labeled')]">
3
3
  <div :class="cls.e('rail')">
4
4
  <DualNavApp
5
5
  v-for="app in menus"
@@ -7,6 +7,7 @@
7
7
  :app="app"
8
8
  :active="isAppActive(app)"
9
9
  :selected="isAppSelected(app)"
10
+ :labeled="railVariant === 'labeled'"
10
11
  @click="handleAppClick(app)"
11
12
  />
12
13
  </div>
@@ -72,7 +73,7 @@ import { findFirstLeaf, findRootApp } from './helper'
72
73
 
73
74
  defineOptions({ name: 'UDualNav' })
74
75
 
75
- const props = defineProps<DualNavProps>()
76
+ const props = withDefaults(defineProps<DualNavProps>(), { railVariant: 'icon' })
76
77
  const emit = defineEmits<DualNavEmits>()
77
78
 
78
79
  const cls = bem('dual-nav')
@@ -2,7 +2,9 @@
2
2
  @use 'pkg:@veltra/styles/functions' as fn;
3
3
  @use 'pkg:@veltra/styles/vars';
4
4
 
5
- @include m.b(dual-nav) {
5
+ $root-name: dual-nav;
6
+
7
+ @include m.b($root-name) {
6
8
  display: flex;
7
9
  height: 100%;
8
10
  min-height: 0;
@@ -21,6 +23,23 @@
21
23
  background-color: fn.use-var(bg-color, middle);
22
24
  }
23
25
 
26
+ @include m.m(labeled) {
27
+ @include m.bem($root-name, rail) {
28
+ width: var(--u-nav-rail-labeled-width);
29
+ padding: 8px 4px;
30
+ gap: 2px;
31
+ }
32
+
33
+ @include m.bem($root-name, app) {
34
+ aspect-ratio: auto;
35
+ max-width: none;
36
+ flex-direction: column;
37
+ gap: 2px;
38
+ padding: 6px 2px;
39
+ min-height: 0;
40
+ }
41
+ }
42
+
24
43
  @include m.e(divider) {
25
44
  flex-shrink: 0;
26
45
  width: 1px;
@@ -164,6 +183,16 @@
164
183
  line-height: 1;
165
184
  }
166
185
 
186
+ @include m.e(app-label) {
187
+ max-width: 100%;
188
+ overflow: hidden;
189
+ text-overflow: ellipsis;
190
+ white-space: nowrap;
191
+ font-size: fn.use-var(font-size-assist, default);
192
+ line-height: 1.2;
193
+ text-align: center;
194
+ }
195
+
167
196
  @include m.e(app-tip) {
168
197
  display: flex;
169
198
  flex-direction: column;
@@ -0,0 +1,32 @@
1
+ <template>
2
+ <li
3
+ :class="[cls.e('item'), bem.is('active', active), bem.is('disabled', item.disabled ?? false)]"
4
+ @click="handleClick"
5
+ >
6
+ <NavIcon v-if="item.icon" :icon="item.icon" :class="cls.e('icon')" />
7
+
8
+ <span :class="cls.e('item-title')">
9
+ {{ item.title }}
10
+ </span>
11
+ </li>
12
+ </template>
13
+
14
+ <script setup lang="ts">
15
+ import { bem } from '@veltra/utils'
16
+
17
+ import type { NavItem } from '../../types/nav'
18
+ import NavIcon from '../nav/nav-icon.vue'
19
+
20
+ defineOptions({ name: 'UGroupNavItem' })
21
+
22
+ const props = defineProps<{ item: NavItem; active: boolean }>()
23
+
24
+ const emit = defineEmits<{ (e: 'click', item: NavItem): void }>()
25
+
26
+ const cls = bem('group-nav')
27
+
28
+ function handleClick() {
29
+ if (props.item.disabled) return
30
+ emit('click', props.item)
31
+ }
32
+ </script>
@@ -0,0 +1,36 @@
1
+ <template>
2
+ <u-scroll tag="ul" :class="cls.b" :container-class="cls.e('container')">
3
+ <li v-for="(group, index) of groups" :key="group.title || index" :class="cls.e('group')">
4
+ <div :class="cls.e('group-label')">{{ group.title }}</div>
5
+ <ul :class="cls.e('group-list')">
6
+ <GroupNavItem
7
+ v-for="(child, childIndex) of group.children"
8
+ :key="child.path || childIndex"
9
+ :item="child"
10
+ :active="currentPath === child.path"
11
+ @click="handleItemClick"
12
+ />
13
+ </ul>
14
+ </li>
15
+ </u-scroll>
16
+ </template>
17
+
18
+ <script lang="ts" setup>
19
+ import { bem } from '@veltra/utils'
20
+
21
+ import type { GroupNavEmits, GroupNavProps } from '../../types/group-nav'
22
+ import type { NavItem } from '../../types/nav'
23
+ import { UScroll } from '../scroll'
24
+ import GroupNavItem from './group-nav-item.vue'
25
+
26
+ defineOptions({ name: 'UGroupNav' })
27
+
28
+ defineProps<GroupNavProps>()
29
+ const emit = defineEmits<GroupNavEmits>()
30
+
31
+ const cls = bem('group-nav')
32
+
33
+ function handleItemClick(item: NavItem) {
34
+ emit('item-click', item)
35
+ }
36
+ </script>
@@ -0,0 +1 @@
1
+ export { default as UGroupNav } from './group-nav.vue'
@@ -0,0 +1,121 @@
1
+ @use 'pkg:@veltra/styles/mixins' as m;
2
+ @use 'pkg:@veltra/styles/functions' as fn;
3
+ @use 'pkg:@veltra/styles/vars';
4
+
5
+ @include m.b(group-nav) {
6
+ margin: 0;
7
+ padding: 0;
8
+ user-select: none;
9
+ color: var(--u-nav-color);
10
+ background-color: var(--u-nav-bg-color);
11
+ backdrop-filter: fn.use-var(bg-filter);
12
+ -webkit-backdrop-filter: fn.use-var(bg-filter);
13
+ background-image: var(--u-nav-bg-image);
14
+ background-size: cover;
15
+ background-repeat: no-repeat;
16
+ border: 1px solid fn.use-var(border, color);
17
+ border-radius: calc(fn.use-var(radius, large) + 6px);
18
+ box-shadow:
19
+ 0 1px 2px rgba(15, 23, 42, 0.05),
20
+ 0 12px 28px rgba(15, 23, 42, 0.08);
21
+
22
+ @include m.e(container) {
23
+ padding: 8px;
24
+ }
25
+
26
+ @include m.e(group, group-list, item) {
27
+ list-style: none;
28
+ margin: 0;
29
+ padding: 0;
30
+ }
31
+
32
+ // 组与组之间统一间距(仅 groups,无独立叶子)
33
+ @include m.e(group) {
34
+ & + & {
35
+ margin-top: 16px;
36
+ }
37
+ }
38
+
39
+ @include m.e(group-label) {
40
+ padding: 0 8px 6px;
41
+ font-size: fn.use-var(font-size-assist, default);
42
+ font-weight: 500;
43
+ line-height: 1.4;
44
+ letter-spacing: 0.02em;
45
+ color: fn.use-var(text-color, second);
46
+ }
47
+
48
+ @include m.e(group-list) {
49
+ display: flex;
50
+ flex-direction: column;
51
+ gap: 3px;
52
+ }
53
+
54
+ @include m.e(item) {
55
+ width: 100%;
56
+ min-height: var(--u-nav-height-default);
57
+ margin: 0;
58
+ padding: 0 8px;
59
+ gap: 8px;
60
+ cursor: pointer;
61
+ color: inherit;
62
+ border-radius: calc(fn.use-var(radius, default) + 4px);
63
+ transition:
64
+ background-color 0.15s ease,
65
+ color 0.15s ease;
66
+
67
+ @include m.flex;
68
+
69
+ &:hover {
70
+ background-color: var(--u-nav-hover-bg);
71
+ color: var(--u-nav-hover-color);
72
+ }
73
+
74
+ @include m.is(active) {
75
+ position: relative;
76
+ background-color: var(--u-nav-active-bg);
77
+ color: var(--u-nav-active-color);
78
+
79
+ &::before {
80
+ content: '';
81
+ position: absolute;
82
+ left: 0;
83
+ top: 50%;
84
+ width: 3px;
85
+ height: 56%;
86
+ min-height: 10px;
87
+ border-radius: 9999px;
88
+ background-color: fn.use-var(color, primary);
89
+ transform: translateY(-50%);
90
+ pointer-events: none;
91
+ }
92
+ }
93
+
94
+ @include m.is(disabled) {
95
+ opacity: 0.55;
96
+ cursor: not-allowed;
97
+ }
98
+ }
99
+
100
+ @include m.e(icon) {
101
+ width: 16px;
102
+ height: 16px;
103
+ font-size: 16px;
104
+ flex-shrink: 0;
105
+ display: inline-flex;
106
+ justify-content: center;
107
+ align-items: center;
108
+ border-radius: calc(fn.use-var(radius, small) + 2px);
109
+ color: inherit;
110
+ object-fit: contain;
111
+ }
112
+
113
+ @include m.e(item-title) {
114
+ flex: 1;
115
+ min-width: 0;
116
+ font-size: fn.use-var(font-size-main, default);
117
+ font-weight: 500;
118
+ letter-spacing: 0.01em;
119
+ @include m.ellipsis;
120
+ }
121
+ }
@@ -0,0 +1,3 @@
1
+ import '../nav/style'
2
+ import '../scroll/style'
3
+ import './style.scss'
@@ -112,6 +112,8 @@ export * from './nav'
112
112
 
113
113
  export * from './dual-nav'
114
114
 
115
+ export * from './group-nav'
116
+
115
117
  export * from './grid-input'
116
118
 
117
119
  export * from './switch'
package/src/style.ts CHANGED
@@ -38,6 +38,7 @@ import './components/layout/style'
38
38
  import './components/list/style'
39
39
  import './components/loading/style'
40
40
  import './components/dual-nav/style'
41
+ import './components/group-nav/style'
41
42
  import './components/nav/style'
42
43
  import './components/message-confirm/style'
43
44
  import './components/message/style'
@@ -2,6 +2,9 @@ import type { DeconstructValue } from '@veltra/utils'
2
2
 
3
3
  import type { NavItem } from './nav'
4
4
 
5
+ /** 双栏导航左轨变体 */
6
+ export type DualNavRailVariant = 'icon' | 'labeled'
7
+
5
8
  /** 双栏导航根级应用项;`description` 在左轨 tooltip 与右栏顶部展示 */
6
9
  export interface DualNavRootItem extends NavItem {
7
10
  /** 子导航 */
@@ -14,6 +17,12 @@ export interface DualNavProps {
14
17
  currentPath?: string
15
18
  /** 根级应用导航列表 */
16
19
  menus?: DualNavRootItem[]
20
+ /**
21
+ * 左轨变体
22
+ * - `icon`:仅图标(默认)
23
+ * - `labeled`:加宽左轨,图标下方显示菜单名称(最多 4 个字)
24
+ */
25
+ railVariant?: DualNavRailVariant
17
26
  }
18
27
 
19
28
  /** 双栏导航组件定义的事件 */
@@ -0,0 +1,20 @@
1
+ import type { NavItem } from './nav'
2
+
3
+ /** 分组:标题 + 叶子菜单 */
4
+ export interface GroupNavGroup {
5
+ title: string
6
+ children: NavItem[]
7
+ }
8
+
9
+ /** 分组导航组件属性 */
10
+ export interface GroupNavProps {
11
+ /** 当前路径 */
12
+ currentPath?: string
13
+ /** 分组列表(每组仅渲染一层叶子,更深嵌套舍弃) */
14
+ groups?: GroupNavGroup[]
15
+ }
16
+
17
+ /** 分组导航组件定义的事件 */
18
+ export interface GroupNavEmits {
19
+ (e: 'item-click', item: NavItem): void
20
+ }
@@ -49,6 +49,7 @@ export * from './table-editor'
49
49
  export * from './table'
50
50
  export * from './nav'
51
51
  export * from './dual-nav'
52
+ export * from './group-nav'
52
53
  export * from './password-input'
53
54
  export * from './date-picker'
54
55
  export * from './dropdown'