@ithinkdt/ui 4.0.0-10 → 4.0.0-12

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.
@@ -0,0 +1,45 @@
1
+ import { NButton, NDropdown, NIcon } from 'ithinkdt-ui'
2
+ import { defineComponent } from 'vue'
3
+
4
+ export const AppLanguage = /* @__PURE__ */ defineComponent({
5
+ name: 'AppLanguage',
6
+ props: {
7
+ lang: String,
8
+ supports: Array,
9
+ },
10
+ emit: ['update:lang'],
11
+ setup(props, { emit }) {
12
+ return () => (
13
+ <NDropdown
14
+ options={props.supports}
15
+ keyField="value"
16
+ showArrow
17
+ onSelect={lang => emit('update:lang', lang)}
18
+ >
19
+ <NButton quaternary style="--n-padding: 0 12px">
20
+ <NIcon size="18">
21
+ <svg
22
+ xmlns="http://www.w3.org/2000/svg"
23
+ xmlns:xlink="http://www.w3.org/1999/xlink"
24
+ role="img"
25
+ width="1em"
26
+ height="1em"
27
+ viewBox="0 0 24 24"
28
+ >
29
+ <g
30
+ fill="none"
31
+ stroke="currentColor"
32
+ stroke-linecap="round"
33
+ stroke-linejoin="round"
34
+ stroke-width="1.5"
35
+ >
36
+ <path d="M2 12c0 5.523 4.477 10 10 10s10-4.477 10-10S17.523 2 12 2S2 6.477 2 12Z"></path>
37
+ <path d="M13 2.05S16 6 16 12c0 6-3 9.95-3 9.95m-2 0S8 18 8 12c0-6 3-9.95 3-9.95M2.63 15.5h18.74m-18.74-7h18.74"></path>
38
+ </g>
39
+ </svg>
40
+ </NIcon>
41
+ </NButton>
42
+ </NDropdown>
43
+ )
44
+ },
45
+ })
@@ -0,0 +1,241 @@
1
+ import { NButton, NIcon } from 'ithinkdt-ui'
2
+ import { defineComponent, provide, reactive, renderSlot, toRef, withDirectives } from 'vue'
3
+
4
+ import { vTooltip } from '../directives/tooltip.jsx'
5
+ import { useI18n } from '../use-i18n.js'
6
+ import useStyle, { c, cB, cE, cM } from '../use-style.js'
7
+
8
+ import { COLLAPSED_INJECTION_KEY, CTX_INJECTION_KEY, clsPrefix, getCtx } from './common.jsx'
9
+
10
+ export { getCtx }
11
+
12
+ const style = /* @__PURE__ */ c([
13
+ cB(
14
+ 'layout',
15
+ {
16
+ 'display': 'grid',
17
+ 'gridTemplateAreas': `
18
+ 'sider header'
19
+ 'sider content'
20
+ 'sider footer'
21
+ `,
22
+ 'gridTemplateRows': 'auto 1fr auto',
23
+ 'gridTemplateColumns': 'auto 1fr',
24
+ 'position': 'relative',
25
+ 'top': '0',
26
+ 'left': '0',
27
+ 'transition': 'all 0.2s cubic-bezier(0.4, 0, 0.2, 1)',
28
+ '--app-content-height': 'calc(100vh - var(--app-header-height) - var(--app-footer-height))',
29
+ },
30
+ [
31
+ cM('full-header', {
32
+ gridTemplateAreas: `
33
+ 'header header'
34
+ 'sider content'
35
+ 'sider footer'
36
+ `,
37
+ }),
38
+ cM('full-content', {
39
+ width: `calc(100% + var(--app-sider-width))`,
40
+ height: `calc(100% + var(--app-header-height))`,
41
+ left: 'calc(-1 * var(--app-sider-width))',
42
+ top: 'calc(-1 * var(--app-header-height))',
43
+ }),
44
+ ],
45
+ ),
46
+ cB(
47
+ 'header',
48
+ {
49
+ gridArea: 'header',
50
+ overflow: 'hidden',
51
+ zIndex: 2,
52
+ height: 'var(--app-header-height, 44px)',
53
+ zIndex: '2',
54
+ },
55
+ ),
56
+ cB(
57
+ 'sider',
58
+ {
59
+ gridArea: 'sider',
60
+ width: 'var(--app-sider-width, 220px)',
61
+ display: 'flex',
62
+ flexDirection: 'column',
63
+ overflow: 'auto',
64
+ position: 'relative',
65
+ transition: 'width 0.2s ease-in-out',
66
+ zIndex: '2',
67
+ },
68
+ [
69
+ cE('collapse-btn', {
70
+ '--n-padding': '0 12px',
71
+ 'position': 'absolute',
72
+ 'zIndex': '2',
73
+ 'bottom': '8px',
74
+ 'right': '8px',
75
+ }),
76
+ ],
77
+ ),
78
+ cB('content', {
79
+ gridArea: 'content',
80
+ position: 'relative',
81
+ overflow: 'hidden',
82
+ zIndex: '1',
83
+ }),
84
+ cB('footer', {
85
+ gridArea: 'footer',
86
+ lineHeight: '24px',
87
+ }),
88
+ ])
89
+
90
+ const IFold = () => (
91
+ <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
92
+ <path
93
+ fill="none"
94
+ stroke="currentColor"
95
+ stroke-linecap="round"
96
+ stroke-linejoin="round"
97
+ stroke-width="1.5"
98
+ d="M11.5 18s-6-4.419-6-6s6-6 6-6m7 12s-6-4.419-6-6s6-6 6-6"
99
+ color="currentColor"
100
+ />
101
+ </svg>
102
+ )
103
+ const IUnfold = () => (
104
+ <svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24">
105
+ <path
106
+ fill="none"
107
+ stroke="currentColor"
108
+ stroke-linecap="round"
109
+ stroke-linejoin="round"
110
+ stroke-width="1.5"
111
+ d="M12.5 18s6-4.419 6-6s-6-6-6-6m-7 12s6-4.419 6-6s-6-6-6-6"
112
+ color="currentColor"
113
+ />
114
+ </svg>
115
+ )
116
+
117
+ export const AppLayout = /* @__PURE__ */ defineComponent({
118
+ name: 'AppLayout',
119
+ props: {
120
+ layout: {
121
+ type: String,
122
+ default: 'left2right',
123
+ },
124
+ fullContent: Boolean,
125
+ },
126
+ setup(props, { slots }) {
127
+ useStyle('-layout', style, ref(clsPrefix), false)
128
+
129
+ const ctx = reactive({
130
+ siderWidth: '0px',
131
+ headerHeight: '0px',
132
+ footerHeight: '0px',
133
+ hasMultiTab: false,
134
+ })
135
+
136
+ provide(CTX_INJECTION_KEY, ctx)
137
+
138
+ return () => {
139
+ const { layout } = props
140
+
141
+ return (
142
+ <div
143
+ class={{
144
+ [`${clsPrefix}-layout`]: true,
145
+ [`${clsPrefix}-layout--full-header`]: layout === 'top2bottom',
146
+ [`${clsPrefix}-layout--full-content`]: props.fullContent,
147
+ }}
148
+ style={{
149
+ '--app-sider-width': ctx.siderWidth,
150
+ '--app-header-height': ctx.headerHeight,
151
+ '--app-footer-height': ctx.footerHeight,
152
+ }}
153
+ >
154
+ {renderSlot(slots, 'default')}
155
+ </div>
156
+ )
157
+ }
158
+ },
159
+ })
160
+
161
+ export const AppHeader = /* @__PURE__ */ defineComponent({
162
+ name: 'AppHeader',
163
+ props: {
164
+ height: { type: Number, default: 44 },
165
+ },
166
+ setup(props, { slots }) {
167
+ const ctx = getCtx()
168
+
169
+ return () => {
170
+ ctx.headerHeight = props.height + 'px'
171
+ return (
172
+ <div class={`${clsPrefix}-header`}>
173
+ {renderSlot(slots, 'default')}
174
+ </div>
175
+ )
176
+ }
177
+ },
178
+ })
179
+ export const AppSider = /* @__PURE__ */ defineComponent({
180
+ name: 'AppSider',
181
+ props: {
182
+ showCollapseBtn: { type: Boolean, default: true },
183
+ collapsed: Boolean,
184
+ width: { type: Number, default: 220 },
185
+ collapsedWidth: { type: Number, default: 60 },
186
+ },
187
+ emits: {
188
+ 'update:collapsed': () => true,
189
+ },
190
+ setup(props, { emit, slots }) {
191
+ provide(COLLAPSED_INJECTION_KEY, toRef(props, 'collapsed'))
192
+
193
+ const { t } = useI18n()
194
+
195
+ const ctx = getCtx()
196
+
197
+ return () => {
198
+ ctx.siderWidth = (props.collapsed ? props.collapsedWidth : props.width) + 'px'
199
+
200
+ return (
201
+ <div class={`${clsPrefix}-sider`}>
202
+ {renderSlot(slots, 'default')}
203
+ {props.showCollapseBtn
204
+ ? withDirectives(
205
+ <NButton
206
+ class={`${clsPrefix}-sider__collapse-btn`}
207
+ quaternary
208
+ onClick={() => {
209
+ emit('update:collapsed', !props.collapsed)
210
+ }}
211
+ >
212
+ <NIcon size="20">{props.collapsed ? <IUnfold /> : <IFold />}</NIcon>
213
+ </NButton>,
214
+ [[vTooltip, props.collapsed ? t('common.layout.sider.expand') : t('common.layout.sider.collapse')]],
215
+ )
216
+ : undefined}
217
+ </div>
218
+ )
219
+ }
220
+ },
221
+ })
222
+ export const AppContent = /* @__PURE__ */ defineComponent({
223
+ name: 'AppContent',
224
+ setup(props, { slots }) {
225
+ return () => <div class={`${clsPrefix}-content`}>{renderSlot(slots, 'default')}</div>
226
+ },
227
+ })
228
+ export const AppFooter = /* @__PURE__ */ defineComponent({
229
+ name: 'AppFooter',
230
+ props: {
231
+ height: { type: Number, default: 30 },
232
+ },
233
+ setup(props, { slots }) {
234
+ const ctx = getCtx()
235
+
236
+ return () => {
237
+ ctx.footerHeight = props.height + 'px'
238
+ return <div class={`${clsPrefix}-footer`}>{renderSlot(slots, 'default')}</div>
239
+ }
240
+ },
241
+ })
@@ -0,0 +1,91 @@
1
+ import { NText } from 'ithinkdt-ui'
2
+ import { defineComponent, inject } from 'vue'
3
+
4
+ import { COLLAPSED_INJECTION_KEY, clsPrefix } from './common.jsx'
5
+
6
+ export const AppLogo = /* @__PURE__ */ defineComponent({
7
+ name: 'AppLogo',
8
+ props: {
9
+ src: [String, Function],
10
+ name: String,
11
+ collapsed: {
12
+ type: Boolean,
13
+ default: undefined,
14
+ },
15
+ center: {
16
+ type: Boolean,
17
+ default: false,
18
+ },
19
+ link: {
20
+ type: Boolean,
21
+ default: true,
22
+ },
23
+ },
24
+ setup(props, { slots }) {
25
+ const src = asyncComputed(() => (typeof props.src === 'function' ? props.src() : props.src))
26
+ const collapsed2 = inject(COLLAPSED_INJECTION_KEY, false)
27
+ return () => {
28
+ let { name, collapsed, center, link } = props
29
+ collapsed ??= unref(collapsed2)
30
+
31
+ const scale = collapsed ? 1 : 1 / 1.1
32
+ return (
33
+ <div
34
+ class={`${clsPrefix}-logo`}
35
+ style={{
36
+ '--app-logo-img-size': '32px',
37
+ '--app-logo-name-size': '22px',
38
+ 'width': center ? '100%' : 'auto',
39
+ 'overflow': 'hidden',
40
+ 'display': 'flex',
41
+ 'alignItems': 'center',
42
+ 'justifyContent': center ? 'center' : 'flex-start',
43
+ 'cursor': link ? 'pointer' : undefined,
44
+ }}
45
+ >
46
+ {
47
+ slots.default
48
+ ? slots.default()
49
+ : (
50
+ <div
51
+ class={`${clsPrefix}-logo__img`}
52
+ style={`
53
+ width: ${collapsed ? `var(--app-sider-width, 60px)` : '56px'};
54
+ font-size: ${collapsed ? `calc(var(--app-sider-width, 60px) - 24px)` : '32px'};
55
+ transition: width 0.2s ease-in-out 0.1s;
56
+ flex: 0 0 auto;
57
+ display: flex;
58
+ justify-content: center
59
+ `}
60
+ >
61
+ {
62
+ slots.icon
63
+ ? slots.icon()
64
+ : (
65
+ <img
66
+ src={src.value}
67
+ alt="App Logo"
68
+ style={`transition: height 0.2s ease-in-out; height: calc(var(--app-logo-img-size) * ${scale})`}
69
+ />
70
+ )
71
+ }
72
+ </div>
73
+ )
74
+ }
75
+ {name
76
+ ? (
77
+ <NText
78
+ class={`${clsPrefix}-logo__name`}
79
+ style="font-size: var(--app-logo-name-size); font-weight: bold; white-space: nowrap; flex: 0 1 auto; overflow: hidden"
80
+ >
81
+ {name}
82
+ </NText>
83
+ )
84
+ : (
85
+ ''
86
+ )}
87
+ </div>
88
+ )
89
+ }
90
+ },
91
+ })
@@ -0,0 +1,133 @@
1
+ import { NMenu, NScrollbar } from 'ithinkdt-ui'
2
+ import { defineComponent, inject, shallowRef, useTemplateRef, watch, withDirectives } from 'vue'
3
+ import { RouterLink } from 'vue-router'
4
+
5
+ import { vTooltip } from '../directives/tooltip.jsx'
6
+
7
+ import { COLLAPSED_INJECTION_KEY, IBookmark } from './common.jsx'
8
+
9
+ export const AppMenu = /* @__PURE__ */ defineComponent({
10
+ name: 'AppMenu',
11
+ props: {
12
+ menus: Array,
13
+ getIcon: Function,
14
+ current: String,
15
+ horizontal: Boolean,
16
+ single: Boolean,
17
+ accordion: Boolean,
18
+ collapsed: { type: Boolean, default: undefined },
19
+ renderLabel: Function,
20
+ width: { type: Number, default: 220 },
21
+ collapsedWidth: { type: Number, default: 60 },
22
+ },
23
+ setup(props) {
24
+ const options = shallowRef([])
25
+
26
+ watch(
27
+ [() => props.menus, () => props.single],
28
+ ([menus, single]) => {
29
+ options.value = []
30
+ if (!menus?.length) return
31
+
32
+ const map = (data, depth = 0) => {
33
+ const array = []
34
+ for (const it of data) {
35
+ if (it.type === 'action') continue
36
+
37
+ const children = it.type === 'view' ? undefined : map(it.children ?? [], depth + 1)
38
+
39
+ const menu = {
40
+ _: it,
41
+ key: it.key,
42
+ label: () => props.renderLabel?.(it) ?? it.name,
43
+ icon: (depth === 0 || it.icon) ? (props.getIcon?.(it.icon) ?? IBookmark) : undefined,
44
+ children: single ? undefined : children,
45
+ path: it.path || (single ? children?.[0]?.path : undefined),
46
+ depth,
47
+ }
48
+ delete menu.type
49
+ array.push(menu)
50
+ }
51
+ return array
52
+ }
53
+
54
+ options.value = map(menus)
55
+ },
56
+ { immediate: true },
57
+ )
58
+
59
+ const menuRef = useTemplateRef('menu')
60
+ watch(
61
+ [menuRef, () => props.current],
62
+ ([menuRef, current]) => {
63
+ menuRef?.showOption(current)
64
+ },
65
+ { immediate: true },
66
+ )
67
+
68
+ const collapsed2 = inject(COLLAPSED_INJECTION_KEY, false)
69
+
70
+ const renderLabel = (menu) => {
71
+ const collapsed = props.collapsed ?? unref(collapsed2)
72
+ let label
73
+ if (menu._.type === 'view') {
74
+ if (menu.isExternal && menu.externalEmbed) {
75
+ label = (
76
+ <a href={menu.externalLink} target="_blank" onClick={e => e.stopPropagation()}>
77
+ {menu.label()}
78
+ </a>
79
+ )
80
+ } else {
81
+ label = <RouterLink to={menu.path}>{menu.label()}</RouterLink>
82
+ }
83
+ } else {
84
+ label = <span>{menu.label()}</span>
85
+ }
86
+ label.key = `${menu.key}:${collapsed ? 1 : 0}`
87
+ if (menu.depth === 0 && !collapsed) {
88
+ label = withDirectives(label, [[vTooltip, menu.label(), undefined, { auto: true, right: true }]])
89
+ }
90
+ if (menu.isNew) {
91
+ label = (
92
+ <div style="display: flex; width: 100%">
93
+ <span style="flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis">{label}</span>
94
+ <svg
95
+ xmlns="http://www.w3.org/2000/svg"
96
+ width="24"
97
+ height="24"
98
+ viewBox="0 0 1024 1024"
99
+ style="margin-left: 8px; flex: 0 0 auto;"
100
+ >
101
+ <path
102
+ d="M245.76 286.72h552.96c124.928 0 225.28 100.352 225.28 225.28s-100.352 225.28-225.28 225.28H0V532.48c0-135.168 110.592-245.76 245.76-245.76z m133.12 348.16V401.408H348.16v178.176l-112.64-178.176H204.8V634.88h30.72v-178.176L348.16 634.88h30.72z m182.272-108.544v-24.576h-96.256v-75.776h110.592v-24.576h-141.312V634.88h143.36v-24.576h-112.64v-83.968h96.256z m100.352 28.672l-34.816-151.552h-34.816l55.296 233.472H675.84l47.104-161.792 4.096-20.48 4.096 20.48 47.104 161.792h28.672l57.344-233.472h-34.816l-32.768 151.552-4.096 30.72-6.144-30.72-40.96-151.552h-30.72l-40.96 151.552-6.144 30.72-6.144-30.72z"
103
+ fill="var(--color-danger)"
104
+ >
105
+ </path>
106
+ </svg>
107
+ </div>
108
+ )
109
+ }
110
+ return label
111
+ }
112
+
113
+ return () => {
114
+ const content = (
115
+ <NMenu
116
+ ref="menu"
117
+ options={options.value}
118
+ rootIndent={16}
119
+ accordion={props.accordion}
120
+ collapsed={props.collapsed ?? unref(collapsed2)}
121
+ dropdownProps={{ showArrow: true }}
122
+ mode={props.horizontal ? 'horizontal' : 'vertical'}
123
+ value={props.current ?? null}
124
+ renderLabel={renderLabel}
125
+ responsive
126
+ collapsedWidth={props.collapsedWidth}
127
+ width={props.width}
128
+ />
129
+ )
130
+ return props.horizontal ? content : <NScrollbar>{content}</NScrollbar>
131
+ }
132
+ },
133
+ })