@opentiny/tiny-robot 0.2.0-alpha.1 → 0.2.0-alpha.2
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/dist/action-group/index.type.d.ts +1 -0
- package/dist/bubble/index.d.ts +2 -2
- package/dist/bubble/index.type.d.ts +16 -18
- package/dist/feedback/index.vue.d.ts +2 -2
- package/dist/icon-button/index.type.d.ts +2 -3
- package/dist/icon-button/index.vue.d.ts +3 -3
- package/dist/node_modules/.pnpm/@vueuse_core@13.1.0_vue@3.5.13/node_modules/@vueuse/core/index.js +262 -142
- package/dist/node_modules/.pnpm/@vueuse_shared@13.1.0_vue@3.5.13/node_modules/@vueuse/shared/index.js +96 -39
- package/dist/packages/components/src/action-group/ActionGroup.vue.js +2 -2
- package/dist/packages/components/src/action-group/ActionGroup.vue2.js +96 -72
- package/dist/packages/components/src/bubble/Bubble.vue.js +7 -0
- package/dist/packages/components/src/bubble/Bubble.vue2.js +76 -0
- package/dist/packages/components/src/bubble/BubbleList.vue.js +7 -0
- package/dist/packages/components/src/bubble/BubbleList.vue2.js +50 -0
- package/dist/packages/components/src/bubble/index.js +2 -2
- package/dist/packages/components/src/container/index.vue.js +2 -2
- package/dist/packages/components/src/container/index.vue2.js +36 -36
- package/dist/packages/components/src/feedback/index.vue.js +2 -2
- package/dist/packages/components/src/feedback/index.vue2.js +72 -71
- package/dist/packages/components/src/icon-button/index.vue.js +2 -2
- package/dist/packages/components/src/icon-button/index.vue2.js +9 -27
- package/dist/packages/components/src/sender/components/TemplateEditor.vue.js +2 -2
- package/dist/packages/components/src/sender/components/TemplateEditor.vue2.js +137 -83
- package/dist/sender/index.vue.d.ts +2 -2
- package/dist/style.css +1 -1
- package/package.json +3 -3
- package/src/action-group/ActionGroup.vue +38 -23
- package/src/action-group/index.type.ts +1 -0
- package/src/bubble/{bubble.vue → Bubble.vue} +13 -97
- package/src/bubble/BubbleList.vue +55 -0
- package/src/bubble/index.ts +2 -2
- package/src/bubble/index.type.ts +7 -21
- package/src/container/index.vue +10 -35
- package/src/feedback/index.vue +14 -14
- package/src/icon-button/index.type.ts +2 -3
- package/src/icon-button/index.vue +16 -10
- package/src/sender/components/TemplateEditor.vue +301 -110
- package/dist/bubble/components/actions/copy.vue.d.ts +0 -10
- package/dist/bubble/components/actions/index.d.ts +0 -2
- package/dist/bubble/components/actions/refresh.vue.d.ts +0 -2
- package/dist/bubble/useScroll.d.ts +0 -4
- package/dist/packages/components/src/bubble/bubble-list.vue.js +0 -7
- package/dist/packages/components/src/bubble/bubble-list.vue2.js +0 -37
- package/dist/packages/components/src/bubble/bubble.vue.js +0 -7
- package/dist/packages/components/src/bubble/bubble.vue2.js +0 -118
- package/dist/packages/components/src/bubble/components/actions/copy.vue.js +0 -7
- package/dist/packages/components/src/bubble/components/actions/copy.vue2.js +0 -35
- package/dist/packages/components/src/bubble/components/actions/refresh.vue.js +0 -7
- package/dist/packages/components/src/bubble/components/actions/refresh.vue2.js +0 -16
- package/dist/packages/components/src/bubble/useScroll.js +0 -13
- package/src/bubble/bubble-list.vue +0 -42
- package/src/bubble/components/actions/copy.vue +0 -54
- package/src/bubble/components/actions/index.ts +0 -2
- package/src/bubble/components/actions/refresh.vue +0 -31
- package/src/bubble/useScroll.ts +0 -14
- /package/dist/bubble/{bubble-list.vue.d.ts → BubbleList.vue.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opentiny/tiny-robot",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.2",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"vue": "^3.3.11"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@opentiny/tiny-robot-svgs": "0.2.0-alpha.
|
|
19
|
+
"@opentiny/tiny-robot-svgs": "0.2.0-alpha.2",
|
|
20
20
|
"@opentiny/vue": "^3.21.0",
|
|
21
21
|
"@opentiny/vue-button": "^3.21.0",
|
|
22
22
|
"@opentiny/vue-icon": "^3.22.0",
|
|
@@ -40,5 +40,5 @@
|
|
|
40
40
|
"vue": "^3.3.11",
|
|
41
41
|
"vue-tsc": "^2.2.8"
|
|
42
42
|
},
|
|
43
|
-
"gitHead": "
|
|
43
|
+
"gitHead": "f334d2ba1772fe0e2859d5f859980257e70f36e1"
|
|
44
44
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { IconMenu } from '@opentiny/tiny-robot-svgs'
|
|
3
|
+
import TinyTooltip from '@opentiny/vue-tooltip'
|
|
3
4
|
import { onClickOutside, useWindowSize } from '@vueuse/core'
|
|
4
5
|
import { computed, nextTick, ref, useTemplateRef, VNode, watch } from 'vue'
|
|
5
6
|
import IconButton from '../icon-button'
|
|
@@ -108,32 +109,46 @@ watch(windowHeight, () => {
|
|
|
108
109
|
|
|
109
110
|
<template>
|
|
110
111
|
<div class="tr-action-group">
|
|
111
|
-
<
|
|
112
|
+
<tiny-tooltip
|
|
112
113
|
v-for="(item, index) in list"
|
|
113
114
|
:key="index"
|
|
114
|
-
|
|
115
|
-
|
|
115
|
+
:content="item.props?.label"
|
|
116
|
+
effect="dark"
|
|
117
|
+
placement="top"
|
|
118
|
+
:open-delay="500"
|
|
119
|
+
:disabled="!props.showTooltip"
|
|
116
120
|
>
|
|
117
|
-
<
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
121
|
+
<span class="tr-action-group__btn-wrapper" @click="handleItemClick(item.props?.name)">
|
|
122
|
+
<component :is="item" />
|
|
123
|
+
</span>
|
|
124
|
+
</tiny-tooltip>
|
|
125
|
+
<tiny-tooltip
|
|
126
|
+
v-if="showMore"
|
|
127
|
+
content="更多"
|
|
128
|
+
effect="dark"
|
|
129
|
+
placement="top"
|
|
130
|
+
:open-delay="500"
|
|
131
|
+
:disabled="!props.showTooltip"
|
|
132
|
+
>
|
|
133
|
+
<span ref="moreBtnRef" class="tr-action-group__btn-wrapper" @click="handleMoreClick">
|
|
134
|
+
<slot name="moreBtn">
|
|
135
|
+
<icon-button :icon="IconMenu" />
|
|
136
|
+
</slot>
|
|
137
|
+
<transition name="tr-action-group-dropdown">
|
|
138
|
+
<ul v-show="showDropdown" ref="dropDownRef" :class="['tr-action-group__dropdown', dropDownPlacement]">
|
|
139
|
+
<li
|
|
140
|
+
class="tr-action-group__dropdown-item"
|
|
141
|
+
v-for="(item, index) in moreList"
|
|
142
|
+
:key="index"
|
|
143
|
+
@click.stop="handleItemClick(item.props?.name)"
|
|
144
|
+
>
|
|
145
|
+
<component v-if="!props.dropDownShowLabelOnly" :is="item" />
|
|
146
|
+
<span class="tr-action-group__dropdown-item-text">{{ item.props?.label }}</span>
|
|
147
|
+
</li>
|
|
148
|
+
</ul>
|
|
149
|
+
</transition>
|
|
150
|
+
</span>
|
|
151
|
+
</tiny-tooltip>
|
|
137
152
|
</div>
|
|
138
153
|
</template>
|
|
139
154
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import markdownit from 'markdown-it'
|
|
3
|
-
import { computed
|
|
4
|
-
import {
|
|
5
|
-
import { BubbleActionOptions, BubbleEvents, BubbleProps, BubbleSlots } from './index.type'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import { BubbleProps, BubbleSlots } from './index.type'
|
|
6
5
|
|
|
7
6
|
const props = withDefaults(defineProps<BubbleProps>(), {
|
|
8
7
|
content: '',
|
|
@@ -11,72 +10,20 @@ const props = withDefaults(defineProps<BubbleProps>(), {
|
|
|
11
10
|
maxWidth: '80%',
|
|
12
11
|
})
|
|
13
12
|
|
|
14
|
-
const
|
|
13
|
+
const slots = defineSlots<BubbleSlots>()
|
|
15
14
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
const markdownItInstance = computed(() => {
|
|
16
|
+
return markdownit(props.mdConfig || {})
|
|
17
|
+
})
|
|
19
18
|
|
|
20
19
|
const bubbleContent = computed(() => {
|
|
21
20
|
if (props.type === 'markdown') {
|
|
22
|
-
return
|
|
21
|
+
return markdownItInstance.value.render(props.content)
|
|
23
22
|
}
|
|
24
23
|
return props.content
|
|
25
24
|
})
|
|
26
25
|
|
|
27
26
|
const placementStart = computed(() => props.placement === 'start')
|
|
28
|
-
|
|
29
|
-
const defaultActionsMap = new Map<string, BubbleActionOptions>([
|
|
30
|
-
[
|
|
31
|
-
'copy',
|
|
32
|
-
{
|
|
33
|
-
name: 'copy',
|
|
34
|
-
vnode: CopyAction,
|
|
35
|
-
show: true,
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
[
|
|
39
|
-
'refresh',
|
|
40
|
-
{
|
|
41
|
-
name: 'refresh',
|
|
42
|
-
vnode: RefreshAction,
|
|
43
|
-
show: true,
|
|
44
|
-
},
|
|
45
|
-
],
|
|
46
|
-
])
|
|
47
|
-
|
|
48
|
-
const computedActions = computed(() => {
|
|
49
|
-
const actions = (props.actions || []).map((action) => {
|
|
50
|
-
if (typeof action === 'string') {
|
|
51
|
-
return defaultActionsMap.get(action)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (defaultActionsMap.has(action.name)) {
|
|
55
|
-
return {
|
|
56
|
-
...defaultActionsMap.get(action.name),
|
|
57
|
-
...action,
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
return action
|
|
62
|
-
})
|
|
63
|
-
|
|
64
|
-
return actions.filter((action): action is BubbleActionOptions => Boolean(action))
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
const handleActionClick = (name: string, ...args: unknown[]) => {
|
|
68
|
-
if (name === 'copy') {
|
|
69
|
-
emit('copy', args[0] as boolean)
|
|
70
|
-
return
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
if (name === 'refresh') {
|
|
74
|
-
emit('refresh')
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
emit('action', name, ...args)
|
|
79
|
-
}
|
|
80
27
|
</script>
|
|
81
28
|
|
|
82
29
|
<template>
|
|
@@ -93,7 +40,7 @@ const handleActionClick = (name: string, ...args: unknown[]) => {
|
|
|
93
40
|
<component :is="props.avatar"></component>
|
|
94
41
|
</div>
|
|
95
42
|
<div class="tr-bubble__content-wrapper">
|
|
96
|
-
<slot v-if="props.loading" name="loading">
|
|
43
|
+
<slot v-if="props.loading" name="loading" :bubble-props="props">
|
|
97
44
|
<div class="tr-bubble__loading">
|
|
98
45
|
<span></span>
|
|
99
46
|
<span></span>
|
|
@@ -102,26 +49,14 @@ const handleActionClick = (name: string, ...args: unknown[]) => {
|
|
|
102
49
|
</slot>
|
|
103
50
|
<div v-else :class="['tr-bubble__content']">
|
|
104
51
|
<div class="tr-bubbule__body">
|
|
105
|
-
<slot>
|
|
52
|
+
<slot :bubble-props="props">
|
|
106
53
|
<span v-if="props.type === 'markdown'" v-html="bubbleContent"></span>
|
|
107
54
|
<span v-else>{{ bubbleContent }}</span>
|
|
108
55
|
<span v-if="props.aborted" class="tr-bubbule__aborted">(用户停止)</span>
|
|
109
56
|
</slot>
|
|
110
57
|
</div>
|
|
111
|
-
<div v-if="slots.footer
|
|
112
|
-
<
|
|
113
|
-
<slot name="footer"></slot>
|
|
114
|
-
</div>
|
|
115
|
-
<div class="tr-bubbule__footer-actions">
|
|
116
|
-
<template v-for="action in computedActions" :key="action?.name">
|
|
117
|
-
<component
|
|
118
|
-
:is="action.vnode"
|
|
119
|
-
v-show="typeof action.show === 'function' ? action.show(props) : action.show"
|
|
120
|
-
:bubbleItem="props"
|
|
121
|
-
@click="handleActionClick(action.name, $event)"
|
|
122
|
-
></component>
|
|
123
|
-
</template>
|
|
124
|
-
</div>
|
|
58
|
+
<div v-if="slots.footer" class="tr-bubbule__footer">
|
|
59
|
+
<slot name="footer" :bubble-props="props"></slot>
|
|
125
60
|
</div>
|
|
126
61
|
</div>
|
|
127
62
|
</div>
|
|
@@ -203,6 +138,7 @@ const handleActionClick = (name: string, ...args: unknown[]) => {
|
|
|
203
138
|
color: rgb(25, 25, 25);
|
|
204
139
|
font-size: 16px;
|
|
205
140
|
line-height: 26px;
|
|
141
|
+
word-break: break-word;
|
|
206
142
|
}
|
|
207
143
|
|
|
208
144
|
.tr-bubbule__aborted {
|
|
@@ -211,27 +147,7 @@ const handleActionClick = (name: string, ...args: unknown[]) => {
|
|
|
211
147
|
}
|
|
212
148
|
|
|
213
149
|
.tr-bubbule__footer {
|
|
214
|
-
|
|
215
|
-
gap: 12px;
|
|
216
|
-
|
|
217
|
-
.tr-bubbule__footer-left {
|
|
218
|
-
flex: 1;
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
.tr-bubbule__footer-actions {
|
|
222
|
-
display: flex;
|
|
223
|
-
flex-shrink: 0;
|
|
224
|
-
gap: 4px;
|
|
225
|
-
margin-top: 12px;
|
|
226
|
-
|
|
227
|
-
& > * {
|
|
228
|
-
display: flex;
|
|
229
|
-
align-items: center;
|
|
230
|
-
justify-content: center;
|
|
231
|
-
width: 24px;
|
|
232
|
-
height: 24px;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
150
|
+
margin-top: 12px;
|
|
235
151
|
}
|
|
236
152
|
}
|
|
237
153
|
</style>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useScroll } from '@vueuse/core'
|
|
3
|
+
import { computed, useTemplateRef, watch } from 'vue'
|
|
4
|
+
import Bubble from './Bubble.vue'
|
|
5
|
+
import { BubbleListProps, BubbleProps, BubbleSlots } from './index.type'
|
|
6
|
+
|
|
7
|
+
const props = withDefaults(defineProps<BubbleListProps>(), {})
|
|
8
|
+
|
|
9
|
+
const scrollContainerRef = useTemplateRef<HTMLDivElement>('scrollContainer')
|
|
10
|
+
const { y } = useScroll(scrollContainerRef, {
|
|
11
|
+
behavior: 'smooth',
|
|
12
|
+
throttle: 100,
|
|
13
|
+
})
|
|
14
|
+
const lastBubble = computed(() => props.items.at(-1))
|
|
15
|
+
|
|
16
|
+
watch([() => props.items.length, () => lastBubble.value?.content], () => {
|
|
17
|
+
if (!props.autoScroll || !scrollContainerRef.value) {
|
|
18
|
+
return
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
y.value = scrollContainerRef.value.scrollHeight
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
const getItemProps = (item: BubbleProps & { slots?: BubbleSlots }): BubbleProps => {
|
|
25
|
+
const defaultConfig = item.role ? props.roles?.[item.role] || {} : {}
|
|
26
|
+
const { slots: _roleSlots, ...rest } = defaultConfig
|
|
27
|
+
const { slots: _itemSlots, ...restItem } = item
|
|
28
|
+
return { ...rest, ...restItem }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const getItemSlots = (item: BubbleProps & { slots?: BubbleSlots }): BubbleSlots => {
|
|
32
|
+
const defaultConfig = item.role ? props.roles?.[item.role] || {} : {}
|
|
33
|
+
return { ...defaultConfig.slots, ...item.slots }
|
|
34
|
+
}
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<template>
|
|
38
|
+
<div class="tr-bubble-list" ref="scrollContainer">
|
|
39
|
+
<Bubble v-for="(item, index) in props.items" :key="item.id || index" v-bind="getItemProps(item)">
|
|
40
|
+
<template v-for="(_, slotName) in getItemSlots(item)" #[slotName]="slotProps" :key="slotName">
|
|
41
|
+
<component :is="getItemSlots(item)[slotName]" v-bind="slotProps" />
|
|
42
|
+
</template>
|
|
43
|
+
</Bubble>
|
|
44
|
+
</div>
|
|
45
|
+
</template>
|
|
46
|
+
|
|
47
|
+
<style lang="less" scoped>
|
|
48
|
+
.tr-bubble-list {
|
|
49
|
+
display: flex;
|
|
50
|
+
flex-direction: column;
|
|
51
|
+
gap: 16px;
|
|
52
|
+
overflow-y: auto;
|
|
53
|
+
padding: 16px;
|
|
54
|
+
}
|
|
55
|
+
</style>
|
package/src/bubble/index.ts
CHANGED
package/src/bubble/index.type.ts
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
1
|
import { Options as MarkdownItOptions } from 'markdown-it'
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
export interface BubbleActionOptions {
|
|
5
|
-
name: 'copy' | 'refresh' | string
|
|
6
|
-
vnode?: VNode | Component
|
|
7
|
-
show?: boolean | ((props: BubbleProps) => boolean)
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export type BubbleAction = 'copy' | 'refresh' | BubbleActionOptions
|
|
2
|
+
import { CSSProperties, VNode } from 'vue'
|
|
11
3
|
|
|
12
4
|
export type BubblePalcement = 'start' | 'end'
|
|
13
5
|
|
|
@@ -33,28 +25,22 @@ export interface BubbleProps {
|
|
|
33
25
|
* type 为 'markdown' 时,markdown 的配置项
|
|
34
26
|
*/
|
|
35
27
|
mdConfig?: MarkdownItOptions
|
|
36
|
-
|
|
37
|
-
actions?: BubbleAction[]
|
|
38
28
|
// 样式相关
|
|
39
29
|
maxWidth?: CSSProperties['maxWidth']
|
|
40
30
|
}
|
|
41
31
|
|
|
42
32
|
export interface BubbleSlots {
|
|
43
|
-
default:
|
|
44
|
-
footer:
|
|
45
|
-
loading:
|
|
33
|
+
default?: (slotProps: { bubbleProps: BubbleProps }) => unknown
|
|
34
|
+
footer?: (slotProps: { bubbleProps: BubbleProps }) => unknown
|
|
35
|
+
loading?: (slotProps: { bubbleProps: BubbleProps }) => unknown
|
|
46
36
|
}
|
|
47
37
|
|
|
48
|
-
export
|
|
49
|
-
|
|
50
|
-
(e: 'refresh'): void
|
|
51
|
-
(e: 'action', name: string, ...args: unknown[]): void
|
|
38
|
+
export type BubbleRoleConfig = Pick<BubbleProps, 'placement' | 'avatar' | 'type' | 'mdConfig' | 'maxWidth'> & {
|
|
39
|
+
slots?: BubbleSlots
|
|
52
40
|
}
|
|
53
41
|
|
|
54
|
-
export type BubbleRoleConfig = Pick<BubbleProps, 'placement' | 'avatar' | 'type' | 'mdConfig' | 'actions' | 'maxWidth'>
|
|
55
|
-
|
|
56
42
|
export interface BubbleListProps {
|
|
57
|
-
items: BubbleProps[]
|
|
43
|
+
items: (BubbleProps & { slots?: BubbleSlots })[]
|
|
58
44
|
/**
|
|
59
45
|
* 每个角色的默认配置项
|
|
60
46
|
*/
|
package/src/container/index.vue
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
import { IconCancelFullScreen, IconClose, IconFullScreen } from '@opentiny/tiny-robot-svgs'
|
|
3
3
|
import { computed } from 'vue'
|
|
4
|
+
import IconButton from '../icon-button'
|
|
4
5
|
import { ContainerProps, ContainerSlots } from './index.type'
|
|
5
6
|
|
|
6
7
|
const show = defineModel<ContainerProps['show']>('show', { required: true })
|
|
@@ -22,17 +23,16 @@ const IconFullScreenSwitcher = computed(() => (fullscreen.value ? IconCancelFull
|
|
|
22
23
|
</slot>
|
|
23
24
|
<div class="tr-container__header-operations">
|
|
24
25
|
<slot name="operations"></slot>
|
|
25
|
-
<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
26
|
+
<icon-button
|
|
27
|
+
size="28"
|
|
28
|
+
svg-size="20"
|
|
29
|
+
:icon="IconFullScreenSwitcher"
|
|
30
|
+
@click="$emit('update:fullscreen', !fullscreen)"
|
|
31
|
+
></icon-button>
|
|
32
|
+
<icon-button size="28" svg-size="20" :icon="IconClose" @click="$emit('update:show', false)"></icon-button>
|
|
31
33
|
</div>
|
|
32
34
|
</div>
|
|
33
|
-
<
|
|
34
|
-
<slot></slot>
|
|
35
|
-
</div>
|
|
35
|
+
<slot></slot>
|
|
36
36
|
<div class="tr-container__footer">
|
|
37
37
|
<slot name="footer"></slot>
|
|
38
38
|
</div>
|
|
@@ -95,34 +95,9 @@ const IconFullScreenSwitcher = computed(() => (fullscreen.value ? IconCancelFull
|
|
|
95
95
|
.tr-container__header-operations {
|
|
96
96
|
display: flex;
|
|
97
97
|
gap: 8px;
|
|
98
|
-
|
|
99
|
-
button.icon-btn {
|
|
100
|
-
width: 28px;
|
|
101
|
-
height: 28px;
|
|
102
|
-
display: inline-flex;
|
|
103
|
-
align-items: center;
|
|
104
|
-
justify-content: center;
|
|
105
|
-
border: none;
|
|
106
|
-
border-radius: 8px;
|
|
107
|
-
cursor: pointer;
|
|
108
|
-
padding: 0;
|
|
109
|
-
transition: background-color 0.3s;
|
|
110
|
-
|
|
111
|
-
&:hover {
|
|
112
|
-
background-color: rgba(0, 0, 0, 0.04);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
&:active {
|
|
116
|
-
background-color: rgba(0, 0, 0, 0.15);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
svg {
|
|
120
|
-
font-size: 20px;
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
98
|
}
|
|
124
99
|
|
|
125
|
-
.tr-
|
|
100
|
+
.tr-container__header + :slotted(*) {
|
|
126
101
|
flex: 1;
|
|
127
102
|
overflow-y: auto;
|
|
128
103
|
}
|
package/src/feedback/index.vue
CHANGED
|
@@ -42,8 +42,9 @@ const handleSourceList = () => {
|
|
|
42
42
|
<template>
|
|
43
43
|
<div class="tr-feedback">
|
|
44
44
|
<div class="tr-feedback__operations">
|
|
45
|
-
<div
|
|
45
|
+
<div class="tr-feedback__operations-left">
|
|
46
46
|
<action-group
|
|
47
|
+
v-if="props.operations?.length"
|
|
47
48
|
:max-num="props.operationsLimit"
|
|
48
49
|
:drop-down-show-label-only="true"
|
|
49
50
|
@item-click="handleOperation"
|
|
@@ -66,32 +67,31 @@ const handleSourceList = () => {
|
|
|
66
67
|
</tiny-button>
|
|
67
68
|
</template>
|
|
68
69
|
</action-group>
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
</
|
|
70
|
+
<div v-else-if="props.sources?.length">
|
|
71
|
+
<span class="tr-feedback__source" @click="handleSourceList">
|
|
72
|
+
<span>{{ props.sources?.length }}条来源</span>
|
|
73
|
+
<component :is="showSourceList ? IconArrowUp : IconArrowDown" />
|
|
74
|
+
</span>
|
|
75
|
+
</div>
|
|
75
76
|
</div>
|
|
76
77
|
<div class="tr-feedback__operations-right">
|
|
77
|
-
<action-group :max-num="props.actionsLimit" @item-click="handleAction">
|
|
78
|
+
<action-group :max-num="props.actionsLimit" :show-tooltip="true" @item-click="handleAction">
|
|
78
79
|
<action-group-item
|
|
79
80
|
v-for="action in props.actions"
|
|
80
81
|
:key="action.name"
|
|
81
82
|
:name="action.name"
|
|
82
83
|
:label="action.label"
|
|
83
84
|
>
|
|
84
|
-
<icon-button
|
|
85
|
-
v-if="typeof action.icon === 'string'"
|
|
86
|
-
:icon="iconMap[action.icon]"
|
|
87
|
-
:tooltip="action.label"
|
|
88
|
-
></icon-button>
|
|
85
|
+
<icon-button v-if="typeof action.icon === 'string'" :icon="iconMap[action.icon]"></icon-button>
|
|
89
86
|
<component v-else :is="action.icon"></component>
|
|
90
87
|
</action-group-item>
|
|
91
88
|
</action-group>
|
|
92
89
|
</div>
|
|
93
90
|
</div>
|
|
94
|
-
<div
|
|
91
|
+
<div
|
|
92
|
+
v-if="(props.operations?.length && props.sources?.length) || (showSourceList && props.sources)"
|
|
93
|
+
class="tr-feedback__footer"
|
|
94
|
+
>
|
|
95
95
|
<div v-if="props.operations?.length && props.sources?.length">
|
|
96
96
|
<span class="tr-feedback__source" @click="handleSourceList">
|
|
97
97
|
<span>{{ props.sources?.length }}条来源</span>
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import TinyTooltip from '@opentiny/vue-tooltip'
|
|
3
2
|
import { IconButtonProps } from './index.type'
|
|
3
|
+
import { computed } from 'vue'
|
|
4
4
|
|
|
5
5
|
const props = withDefaults(defineProps<IconButtonProps>(), {
|
|
6
6
|
size: '24px',
|
|
7
7
|
svgSize: '16px',
|
|
8
8
|
})
|
|
9
|
+
|
|
10
|
+
const formatSize = (size: string | number) => {
|
|
11
|
+
if (!isNaN(Number(size))) {
|
|
12
|
+
return `${size}px`
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return size as string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const size = computed(() => formatSize(props.size))
|
|
19
|
+
const svgSize = computed(() => formatSize(props.svgSize))
|
|
9
20
|
</script>
|
|
10
21
|
|
|
11
22
|
<template>
|
|
12
|
-
<
|
|
13
|
-
<button class="tr-icon-button">
|
|
14
|
-
<component :is="props.icon" />
|
|
15
|
-
</button>
|
|
16
|
-
</tiny-tooltip>
|
|
17
|
-
<button v-else class="tr-icon-button">
|
|
23
|
+
<button class="tr-icon-button">
|
|
18
24
|
<component :is="props.icon" />
|
|
19
25
|
</button>
|
|
20
26
|
</template>
|
|
@@ -25,8 +31,8 @@ button.tr-icon-button {
|
|
|
25
31
|
--tr-icon-button-active-bg: rgba(0, 0, 0, 0.15);
|
|
26
32
|
--tr-icon-button-border-radius: 8px;
|
|
27
33
|
|
|
28
|
-
width: v-bind('
|
|
29
|
-
height: v-bind('
|
|
34
|
+
width: v-bind('size');
|
|
35
|
+
height: v-bind('size');
|
|
30
36
|
display: inline-flex;
|
|
31
37
|
align-items: center;
|
|
32
38
|
justify-content: center;
|
|
@@ -46,7 +52,7 @@ button.tr-icon-button {
|
|
|
46
52
|
}
|
|
47
53
|
|
|
48
54
|
svg {
|
|
49
|
-
font-size: v-bind('
|
|
55
|
+
font-size: v-bind('svgSize');
|
|
50
56
|
}
|
|
51
57
|
}
|
|
52
58
|
</style>
|