@opentiny/tiny-robot 0.2.0-alpha.0 → 0.2.0-alpha.1

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 (136) hide show
  1. package/dist/action-group/ActionGroup.vue.d.ts +26 -0
  2. package/dist/action-group/ActionGroupItem.vue.d.ts +18 -0
  3. package/dist/action-group/index.d.ts +12 -0
  4. package/dist/action-group/index.type.d.ts +16 -0
  5. package/dist/feedback/components/SourceList.vue.d.ts +11 -0
  6. package/dist/feedback/components/index.d.ts +1 -0
  7. package/dist/feedback/index.d.ts +7 -0
  8. package/dist/feedback/index.type.d.ts +25 -0
  9. package/dist/feedback/index.vue.d.ts +13 -0
  10. package/dist/history/components/index.d.ts +2 -0
  11. package/dist/history/components/item-tag.vue.d.ts +5 -0
  12. package/dist/history/components/search-empty.vue.d.ts +7 -0
  13. package/dist/history/composables/index.d.ts +1 -0
  14. package/dist/history/composables/useEditItemTitle.d.ts +12 -0
  15. package/dist/history/index.d.ts +6 -0
  16. package/dist/history/index.type.d.ts +43 -0
  17. package/dist/history/index.vue.d.ts +2 -0
  18. package/dist/icon-button/index.d.ts +7 -0
  19. package/dist/icon-button/index.type.d.ts +7 -0
  20. package/dist/icon-button/index.vue.d.ts +6 -0
  21. package/dist/index.d.ts +10 -1
  22. package/dist/index.js +57 -27
  23. package/dist/node_modules/.pnpm/@opentiny_utils@3.22.0/node_modules/@opentiny/utils/dist/index.es.js +1335 -884
  24. package/dist/node_modules/.pnpm/@opentiny_vue-common@3.22.0/node_modules/@opentiny/vue-common/lib/index.js +660 -144
  25. package/dist/node_modules/.pnpm/@opentiny_vue-hooks@3.22.0/node_modules/@opentiny/vue-hooks/dist/src/vue-popper.js +85 -0
  26. package/dist/node_modules/.pnpm/@opentiny_vue-locale@3.22.0/node_modules/@opentiny/vue-locale/lib/index.js +1783 -0
  27. package/dist/node_modules/.pnpm/@opentiny_vue-renderless@3.22.0/node_modules/@opentiny/vue-renderless/tooltip/index.js +77 -0
  28. package/dist/node_modules/.pnpm/@opentiny_vue-renderless@3.22.0/node_modules/@opentiny/vue-renderless/tooltip/vue.js +90 -0
  29. package/dist/node_modules/.pnpm/@opentiny_vue-tooltip@3.22.0/node_modules/@opentiny/vue-tooltip/lib/index.js +176 -0
  30. package/dist/node_modules/.pnpm/@opentiny_vue-tooltip@3.22.0/node_modules/@opentiny/vue-tooltip/lib/pc.js +248 -0
  31. package/dist/node_modules/.pnpm/@vueuse_core@13.1.0_vue@3.5.13/node_modules/@vueuse/core/index.js +190 -0
  32. package/dist/node_modules/.pnpm/@vueuse_shared@13.1.0_vue@3.5.13/node_modules/@vueuse/shared/index.js +53 -0
  33. package/dist/packages/components/src/action-group/ActionGroup.vue.js +7 -0
  34. package/dist/packages/components/src/action-group/ActionGroup.vue2.js +97 -0
  35. package/dist/packages/components/src/action-group/ActionGroupItem.vue.js +14 -0
  36. package/dist/packages/components/src/action-group/ActionGroupItem.vue2.js +4 -0
  37. package/dist/packages/components/src/action-group/index.js +17 -0
  38. package/dist/packages/components/src/bubble/bubble.vue.js +2 -2
  39. package/dist/packages/components/src/bubble/bubble.vue2.js +46 -46
  40. package/dist/packages/components/src/container/index.vue.js +1 -1
  41. package/dist/packages/components/src/container/index.vue2.js +17 -17
  42. package/dist/packages/components/src/feedback/components/SourceList.vue.js +7 -0
  43. package/dist/packages/components/src/feedback/components/SourceList.vue2.js +52 -0
  44. package/dist/packages/components/src/feedback/index.js +9 -0
  45. package/dist/packages/components/src/feedback/index.vue.js +7 -0
  46. package/dist/packages/components/src/feedback/index.vue2.js +142 -0
  47. package/dist/packages/components/src/history/components/item-tag.vue.js +7 -0
  48. package/dist/packages/components/src/history/components/item-tag.vue2.js +21 -0
  49. package/dist/packages/components/src/history/components/search-empty.vue.js +7 -0
  50. package/dist/packages/components/src/history/components/search-empty.vue2.js +20 -0
  51. package/dist/packages/components/src/history/composables/useEditItemTitle.js +43 -0
  52. package/dist/packages/components/src/history/index.js +11 -0
  53. package/dist/packages/components/src/history/index.vue.js +7 -0
  54. package/dist/packages/components/src/history/index.vue2.js +130 -0
  55. package/dist/packages/components/src/icon-button/index.js +9 -0
  56. package/dist/packages/components/src/icon-button/index.vue.js +7 -0
  57. package/dist/packages/components/src/icon-button/index.vue2.js +40 -0
  58. package/dist/packages/components/src/prompts/prompt.vue.js +2 -2
  59. package/dist/packages/components/src/prompts/prompt.vue2.js +17 -15
  60. package/dist/packages/components/src/question/components/HotQuestions.vue.js +23 -23
  61. package/dist/packages/components/src/question/index.vue.js +18 -18
  62. package/dist/packages/components/src/sender/components/TemplateEditor.vue.js +7 -0
  63. package/dist/packages/components/src/sender/components/TemplateEditor.vue2.js +121 -0
  64. package/dist/packages/components/src/sender/index.vue.js +149 -128
  65. package/dist/packages/components/src/suggestion/components/CategoryNav.vue.js +38 -0
  66. package/dist/packages/components/src/suggestion/components/CategoryNav.vue2.js +4 -0
  67. package/dist/packages/components/src/suggestion/components/SuggestionCapsule.vue.js +107 -0
  68. package/dist/packages/components/src/suggestion/components/SuggestionCapsule.vue2.js +4 -0
  69. package/dist/packages/components/src/suggestion/components/SuggestionPanel.vue.js +123 -0
  70. package/dist/packages/components/src/suggestion/components/SuggestionPanel.vue2.js +4 -0
  71. package/dist/packages/components/src/suggestion/composables/useKeyboardNavigation.js +45 -0
  72. package/dist/packages/components/src/suggestion/composables/useTriggerDetection.js +17 -0
  73. package/dist/packages/components/src/suggestion/index.js +9 -0
  74. package/dist/packages/components/src/suggestion/index.vue.js +179 -0
  75. package/dist/packages/components/src/suggestion/index.vue2.js +4 -0
  76. package/dist/packages/components/src/suggestion/utils/dom.js +18 -0
  77. package/dist/packages/svgs/dist/tiny-robot-svgs.js +306 -90
  78. package/dist/question/components/HotQuestions.vue.d.ts +2 -2
  79. package/dist/sender/components/TemplateEditor.vue.d.ts +18 -0
  80. package/dist/sender/index.type.d.ts +47 -0
  81. package/dist/sender/index.vue.d.ts +68 -3
  82. package/dist/style.css +1 -1
  83. package/dist/suggestion/components/CategoryNav.vue.d.ts +45 -0
  84. package/dist/suggestion/components/SuggestionCapsule.vue.d.ts +32 -0
  85. package/dist/suggestion/components/SuggestionPanel.vue.d.ts +84 -0
  86. package/dist/suggestion/composables/useKeyboardNavigation.d.ts +18 -0
  87. package/dist/suggestion/composables/useSuggestionFilter.d.ts +10 -0
  88. package/dist/suggestion/composables/useTriggerDetection.d.ts +11 -0
  89. package/dist/suggestion/index.d.ts +7 -0
  90. package/dist/suggestion/index.type.d.ts +94 -0
  91. package/dist/suggestion/index.vue.d.ts +343 -0
  92. package/dist/suggestion/utils/dom.d.ts +20 -0
  93. package/package.json +4 -3
  94. package/src/action-group/ActionGroup.vue +232 -0
  95. package/src/action-group/ActionGroupItem.vue +9 -0
  96. package/src/action-group/index.ts +25 -0
  97. package/src/action-group/index.type.ts +20 -0
  98. package/src/bubble/bubble.vue +4 -14
  99. package/src/container/index.vue +1 -2
  100. package/src/feedback/components/SourceList.vue +112 -0
  101. package/src/feedback/components/index.ts +1 -0
  102. package/src/feedback/index.ts +12 -0
  103. package/src/feedback/index.type.ts +27 -0
  104. package/src/feedback/index.vue +166 -0
  105. package/src/history/components/index.ts +2 -0
  106. package/src/history/components/item-tag.vue +49 -0
  107. package/src/history/components/search-empty.vue +38 -0
  108. package/src/history/composables/index.ts +1 -0
  109. package/src/history/composables/useEditItemTitle.ts +75 -0
  110. package/src/history/index.ts +12 -0
  111. package/src/history/index.type.ts +50 -0
  112. package/src/history/index.vue +292 -0
  113. package/src/icon-button/index.ts +12 -0
  114. package/src/icon-button/index.type.ts +8 -0
  115. package/src/icon-button/index.vue +52 -0
  116. package/src/index.ts +33 -1
  117. package/src/prompts/prompt.vue +7 -21
  118. package/src/question/components/HotQuestions.vue +1 -1
  119. package/src/question/index.less +9 -10
  120. package/src/sender/components/TemplateEditor.vue +274 -0
  121. package/src/sender/index.less +17 -7
  122. package/src/sender/index.type.ts +51 -0
  123. package/src/sender/index.vue +56 -8
  124. package/src/sender/vars.less +3 -3
  125. package/src/suggestion/components/CategoryNav.vue +38 -0
  126. package/src/suggestion/components/SuggestionCapsule.vue +183 -0
  127. package/src/suggestion/components/SuggestionPanel.vue +147 -0
  128. package/src/suggestion/composables/useKeyboardNavigation.ts +101 -0
  129. package/src/suggestion/composables/useSuggestionFilter.ts +34 -0
  130. package/src/suggestion/composables/useTriggerDetection.ts +46 -0
  131. package/src/suggestion/index.less +497 -0
  132. package/src/suggestion/index.ts +12 -0
  133. package/src/suggestion/index.type.ts +101 -0
  134. package/src/suggestion/index.vue +338 -0
  135. package/src/suggestion/utils/dom.ts +66 -0
  136. package/src/suggestion/vars.less +141 -0
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ import type { HistoryItemTagProps } from '../index.type'
3
+
4
+ const props = withDefaults(defineProps<HistoryItemTagProps>(), {
5
+ type: 'default',
6
+ })
7
+ </script>
8
+
9
+ <template>
10
+ <div :class="['tr-history__item-tag', props.type]" :style="props.style">
11
+ <span>{{ props.text }}</span>
12
+ </div>
13
+ </template>
14
+
15
+ <style lang="less" scoped>
16
+ .tr-history__item-tag {
17
+ padding: 0 4px;
18
+ font-size: 12px;
19
+ line-height: 18px;
20
+ border-radius: 2px;
21
+
22
+ &.default {
23
+ color: rgb(25, 25, 25);
24
+ background-color: rgb(245, 245, 245);
25
+ }
26
+
27
+ &.success {
28
+ // TODO 成功
29
+ color: rgb(25, 25, 25);
30
+ background-color: rgb(245, 245, 245);
31
+ }
32
+
33
+ &.warning {
34
+ // TODO 警告
35
+ color: rgb(25, 25, 25);
36
+ background-color: rgb(245, 245, 245);
37
+ }
38
+
39
+ &.error {
40
+ color: rgb(242, 48, 48);
41
+ background-color: rgb(252, 227, 224);
42
+ }
43
+
44
+ &.info {
45
+ color: rgb(20, 118, 255);
46
+ background-color: rgb(222, 236, 255);
47
+ }
48
+ }
49
+ </style>
@@ -0,0 +1,38 @@
1
+ <template>
2
+ <div class="tr-history__empty">
3
+ <span class="tr-history__empty-icon">
4
+ <IconEmptySearch />
5
+ </span>
6
+ <span class="tr-history__empty-text">{{ props.text }}</span>
7
+ </div>
8
+ </template>
9
+
10
+ <script setup lang="ts">
11
+ import { IconEmptySearch } from '@opentiny/tiny-robot-svgs'
12
+
13
+ const props = withDefaults(defineProps<{ text: string }>(), {
14
+ text: '暂无内容',
15
+ })
16
+ </script>
17
+
18
+ <style lang="less" scoped>
19
+ .tr-history__empty {
20
+ display: flex;
21
+ flex-direction: column;
22
+ align-items: center;
23
+ justify-content: center;
24
+ gap: 12px;
25
+ padding: 84px;
26
+ padding-bottom: 0;
27
+
28
+ .tr-history__empty-icon {
29
+ font-size: 16px;
30
+ }
31
+
32
+ .tr-history__empty-text {
33
+ font-size: 12px;
34
+ line-height: 24px;
35
+ color: rgb(25, 25, 25);
36
+ }
37
+ }
38
+ </style>
@@ -0,0 +1 @@
1
+ export * from './useEditItemTitle'
@@ -0,0 +1,75 @@
1
+ import { onClickOutside } from '@vueuse/core'
2
+ import { ComponentPublicInstance, nextTick, ref, watchEffect } from 'vue'
3
+ import { HistoryEvents, HistoryItem } from '../index.type'
4
+
5
+ export const useEditItemTitle = (emit: HistoryEvents) => {
6
+ const editingItem = ref<Pick<HistoryItem, 'id' | 'title'> & { rawData: HistoryItem }>()
7
+
8
+ const handleEdit = (item: HistoryItem) => {
9
+ editingItem.value = {
10
+ id: item.id,
11
+ title: item.title,
12
+ rawData: item,
13
+ }
14
+ }
15
+
16
+ const inputRef = ref<HTMLInputElement | null>(null)
17
+
18
+ const handleEditorInputRef = (el: Element | ComponentPublicInstance | null) => {
19
+ if (!el) {
20
+ return
21
+ }
22
+
23
+ nextTick(() => {
24
+ inputRef.value = el as HTMLInputElement
25
+ inputRef.value.focus()
26
+ })
27
+ }
28
+
29
+ let stopFn: (() => void) | undefined = undefined
30
+
31
+ const handleConfirm = () => {
32
+ if (editingItem.value) {
33
+ if (editingItem.value.title !== editingItem.value.rawData.title) {
34
+ const { title, rawData } = editingItem.value
35
+ emit('item-title-change', title, rawData)
36
+ }
37
+ editingItem.value = undefined
38
+ }
39
+
40
+ stopFn?.()
41
+ stopFn = undefined
42
+ }
43
+
44
+ const handleCancel = () => {
45
+ editingItem.value = undefined
46
+ stopFn?.()
47
+ stopFn = undefined
48
+ }
49
+
50
+ const handleKeyDown = (e: KeyboardEvent) => {
51
+ if (e.key === 'Enter') {
52
+ handleConfirm()
53
+ } else if (e.key === 'Escape') {
54
+ handleCancel()
55
+ }
56
+ }
57
+
58
+ watchEffect(() => {
59
+ if (!inputRef.value) {
60
+ return
61
+ }
62
+
63
+ stopFn?.()
64
+ stopFn = onClickOutside(inputRef, () => {
65
+ handleConfirm()
66
+ })
67
+ })
68
+
69
+ return {
70
+ editingItem,
71
+ handleEdit,
72
+ handleEditorInputRef,
73
+ handleKeyDown,
74
+ }
75
+ }
@@ -0,0 +1,12 @@
1
+ import { App } from 'vue'
2
+ import History from './index.vue'
3
+
4
+ const install = function <T>(app: App<T>) {
5
+ app.component('TrHistory', History)
6
+ }
7
+
8
+ export default {
9
+ ...History,
10
+ install,
11
+ name: 'TrHistory',
12
+ }
@@ -0,0 +1,50 @@
1
+ import { CSSProperties } from 'vue'
2
+
3
+ interface BaseHistoryProps {
4
+ activeTab?: string
5
+ searchBar?: boolean
6
+ searchQuery?: string
7
+ searchPlaceholder?: string
8
+ searchFn?: (query: string, item: HistoryItem) => boolean
9
+ selected?: string
10
+ }
11
+
12
+ export type SingleTabHistoryProps = {
13
+ tabTitle: string
14
+ data: HistoryGroup[]
15
+ } & BaseHistoryProps
16
+
17
+ export type MultiTabHistoryProps = {
18
+ tabs: {
19
+ title: string
20
+ id: string
21
+ }[]
22
+ data: Record<string, HistoryGroup[]>
23
+ } & BaseHistoryProps
24
+
25
+ export type HistoryProps = SingleTabHistoryProps | MultiTabHistoryProps
26
+
27
+ export interface HistoryGroup<T = Record<string, unknown>> {
28
+ date: string
29
+ items: HistoryItem<T>[]
30
+ }
31
+
32
+ export interface HistoryItemTagProps {
33
+ text: string
34
+ type?: 'success' | 'warning' | 'error' | 'info' | 'default'
35
+ style?: CSSProperties
36
+ }
37
+
38
+ export interface HistoryItem<T = Record<string, unknown>> {
39
+ id: string
40
+ title: string
41
+ tag?: HistoryItemTagProps
42
+ data?: T
43
+ }
44
+
45
+ export interface HistoryEvents {
46
+ (e: 'close'): void
47
+ (e: 'item-click', item: HistoryItem): void
48
+ (e: 'item-title-change', newTitle: string, rawData: HistoryItem): void
49
+ (e: 'item-delete', item: HistoryItem): void
50
+ }
@@ -0,0 +1,292 @@
1
+ <script lang="ts" setup>
2
+ import { IconClose, IconDelete, IconEditPen, IconSearch } from '@opentiny/tiny-robot-svgs'
3
+ import { TinyButton, TinyInput } from '@opentiny/vue'
4
+ import { computed } from 'vue'
5
+ import { ItemTag, SearchEmpty } from './components'
6
+ import { useEditItemTitle } from './composables'
7
+ import type {
8
+ HistoryEvents,
9
+ HistoryGroup,
10
+ HistoryItem,
11
+ HistoryProps,
12
+ MultiTabHistoryProps,
13
+ SingleTabHistoryProps,
14
+ } from './index.type'
15
+
16
+ const props = withDefaults(defineProps<HistoryProps>(), {
17
+ searchFn: (query: string, { title }: HistoryItem) => {
18
+ if (!query) {
19
+ return true
20
+ }
21
+
22
+ return title.toLowerCase().includes(query.toLowerCase())
23
+ },
24
+ })
25
+
26
+ const activeTab = defineModel<HistoryProps['activeTab']>('activeTab')
27
+ const searchQuery = defineModel<HistoryProps['searchQuery']>('searchQuery')
28
+
29
+ const emit = defineEmits<HistoryEvents>()
30
+
31
+ const computedTabs = computed(() => {
32
+ if (Array.isArray((props as MultiTabHistoryProps).tabs)) {
33
+ return (props as MultiTabHistoryProps).tabs
34
+ }
35
+
36
+ return [{ title: (props as SingleTabHistoryProps).tabTitle, id: '0' }]
37
+ })
38
+
39
+ const computedActiveTab = computed(() => {
40
+ return activeTab.value || computedTabs.value[0].id
41
+ })
42
+
43
+ const enableTabBottomBorder = computed(() => {
44
+ return computedTabs.value.length > 1
45
+ })
46
+
47
+ const groups = computed(() => {
48
+ if (Array.isArray(props.data)) {
49
+ return props.data || []
50
+ }
51
+
52
+ return props.data[computedActiveTab.value] || []
53
+ })
54
+
55
+ const filteredGroups = computed(() => {
56
+ if (!props.searchBar) {
57
+ return groups.value
58
+ }
59
+
60
+ const groupsWithFilteredItems = groups.value.map((group) => {
61
+ return {
62
+ ...group,
63
+ items: group.items.filter((item) => props.searchFn(searchQuery.value || '', item)),
64
+ } as HistoryGroup
65
+ })
66
+
67
+ return groupsWithFilteredItems.filter((group) => group.items.length > 0)
68
+ })
69
+
70
+ const handleItemClick = (item: HistoryItem) => {
71
+ if (item.id === editingItem.value?.id) {
72
+ return
73
+ }
74
+
75
+ emit('item-click', item)
76
+ }
77
+
78
+ const handleClose = () => {
79
+ emit('close')
80
+ }
81
+
82
+ const handleDelete = (item: HistoryItem) => {
83
+ // TODO 删除确认弹窗
84
+ emit('item-delete', item)
85
+ }
86
+
87
+ const { editingItem, handleEdit, handleEditorInputRef, handleKeyDown } = useEditItemTitle(emit)
88
+ </script>
89
+
90
+ <template>
91
+ <div class="tr-history">
92
+ <div class="tr-history__tabs">
93
+ <div
94
+ v-for="tab in computedTabs"
95
+ :key="tab.id"
96
+ :class="['tr-history__tab', { active: computedActiveTab === tab.id }]"
97
+ @click="activeTab = tab.id"
98
+ >
99
+ {{ tab.title }}
100
+ </div>
101
+ </div>
102
+ <div v-if="props.searchBar" class="tr-history__search">
103
+ <tiny-input
104
+ v-model="searchQuery"
105
+ :placeholder="props.searchPlaceholder || '搜索对话名称'"
106
+ :prefix-icon="IconSearch"
107
+ clearable
108
+ />
109
+ </div>
110
+ <div class="tr-history__content">
111
+ <template v-if="filteredGroups.length > 0">
112
+ <div v-for="group in filteredGroups" :key="group.date" class="tr-history__group">
113
+ <div class="tr-history__date">
114
+ <span>{{ group.date }}</span>
115
+ </div>
116
+ <div
117
+ v-for="item in group.items"
118
+ :key="`${item.id}-${item.title}`"
119
+ :class="['tr-history__item', { selected: props.selected === item.id }]"
120
+ @click="handleItemClick(item)"
121
+ >
122
+ <template v-if="editingItem?.id !== item.id">
123
+ <span class="tr-history__item-title">{{ item.title }}</span>
124
+ <ItemTag v-if="item.tag" class="tr-history__item-tag" v-bind="item.tag" />
125
+ <div class="tr-history__item-actions">
126
+ <!-- TODO add popover提示 -->
127
+ <tiny-button :icon="IconEditPen" type="text" size="mini" @click.stop="handleEdit(item)" />
128
+ <tiny-button :icon="IconDelete" type="text" size="mini" @click.stop="handleDelete(item)" />
129
+ </div>
130
+ </template>
131
+ <template v-else>
132
+ <input
133
+ v-model="editingItem.title"
134
+ class="tr-history__item-edit"
135
+ :ref="handleEditorInputRef"
136
+ v-on:keydown="handleKeyDown"
137
+ />
138
+ </template>
139
+ </div>
140
+ </div>
141
+ </template>
142
+ <SearchEmpty v-else :text="searchQuery ? '暂无搜索结果' : '暂无内容'" />
143
+ </div>
144
+ <div class="tr-history__close">
145
+ <tiny-button :icon="IconClose" type="text" size="mini" @click="handleClose" />
146
+ </div>
147
+ </div>
148
+ </template>
149
+
150
+ <style lang="less" scoped>
151
+ .tr-history {
152
+ display: flex;
153
+ gap: 16px;
154
+ flex-direction: column;
155
+ background: #fff;
156
+ border-radius: 24px;
157
+ padding: 0 20px;
158
+ position: relative;
159
+ color: rgb(25, 25, 25);
160
+
161
+ .tr-history__tabs {
162
+ flex-shrink: 0;
163
+ display: flex;
164
+ padding-top: 24px;
165
+ gap: 32px;
166
+ font-size: 16px;
167
+ line-height: 1.5;
168
+ border-bottom: v-bind("enableTabBottomBorder ? '1px solid rgb(240, 240, 240)': 'none'");
169
+
170
+ .tr-history__tab {
171
+ cursor: pointer;
172
+ padding-bottom: 8px;
173
+
174
+ &.active {
175
+ font-weight: 600;
176
+ border-bottom: v-bind("enableTabBottomBorder ? '2px solid rgb(25, 25, 25)': 'none'");
177
+ }
178
+ }
179
+ }
180
+
181
+ .tr-history__close {
182
+ position: absolute;
183
+ right: 16px;
184
+ top: 16px;
185
+ }
186
+
187
+ .tr-history__search {
188
+ flex-shrink: 0;
189
+
190
+ :deep(.tiny-input__inner) {
191
+ border-radius: 999px;
192
+ }
193
+ }
194
+
195
+ .tr-history__content {
196
+ flex: 1;
197
+ display: flex;
198
+ flex-direction: column;
199
+ gap: 12px;
200
+ overflow-y: auto;
201
+ padding: 0 20px;
202
+ margin: 0 -20px;
203
+ margin-bottom: 12px;
204
+
205
+ .tr-history__date {
206
+ font-size: 12px;
207
+ line-height: 20px;
208
+ padding: 4px 12px;
209
+ color: rgb(128, 128, 128);
210
+ background-color: rgb(255, 255, 255);
211
+ position: sticky;
212
+ top: 0;
213
+ z-index: 10;
214
+ }
215
+
216
+ .tr-history__item {
217
+ --tr-history-item-bg: rgb(255, 255, 255);
218
+
219
+ display: flex;
220
+ align-items: center;
221
+ font-size: 14px;
222
+ line-height: 24px;
223
+ border-radius: 12px;
224
+ background-color: var(--tr-history-item-bg);
225
+ cursor: pointer;
226
+ position: relative;
227
+ z-index: 1;
228
+ transition: box-shadow 0.3s ease;
229
+
230
+ &:hover {
231
+ box-shadow: 0 4px 16px 0 rgba(0, 0, 0, 0.08);
232
+ z-index: 20;
233
+
234
+ .tr-history__item-actions {
235
+ opacity: 1;
236
+ }
237
+ }
238
+
239
+ &.selected {
240
+ --tr-history-item-bg: rgb(222, 236, 255);
241
+ }
242
+
243
+ .tr-history__item-title {
244
+ padding: 10px 12px;
245
+ font-size: 14px;
246
+ overflow: hidden;
247
+ text-overflow: ellipsis;
248
+ white-space: nowrap;
249
+ }
250
+
251
+ .tr-history__item-tag {
252
+ flex-shrink: 0;
253
+ margin-right: 12px;
254
+ }
255
+
256
+ .tr-history__item-actions {
257
+ display: flex;
258
+ gap: 8px;
259
+ opacity: 0;
260
+ position: absolute;
261
+ right: 12px;
262
+ background-color: var(--tr-history-item-bg);
263
+
264
+ &::before {
265
+ content: '';
266
+ position: absolute;
267
+ right: 100%;
268
+ width: 40px;
269
+ height: 100%;
270
+
271
+ background: linear-gradient(90deg, rgba(255, 255, 255, 0) 0%, var(--tr-history-item-bg) 100%);
272
+ }
273
+ }
274
+
275
+ .tr-history__item-edit {
276
+ width: 100%;
277
+ font-size: 14px;
278
+ height: 44px;
279
+ border-radius: 12px;
280
+ border: 1px solid rgb(20, 118, 255);
281
+ padding: 0 12px;
282
+ }
283
+ }
284
+ }
285
+
286
+ .tiny-button {
287
+ --tv-Button-height: 20px;
288
+ --tv-Button-border-radius-only-icon-ontext: 999px;
289
+ margin: 0;
290
+ }
291
+ }
292
+ </style>
@@ -0,0 +1,12 @@
1
+ import { App } from 'vue'
2
+ import IconButton from './index.vue'
3
+
4
+ IconButton.name = 'TrIconButton'
5
+
6
+ const install = function <T>(app: App<T>) {
7
+ app.component(IconButton.name!, IconButton)
8
+ }
9
+
10
+ IconButton.install = install
11
+
12
+ export default IconButton as typeof IconButton & { install: typeof install }
@@ -0,0 +1,8 @@
1
+ import { Component, VNode } from 'vue'
2
+
3
+ export interface IconButtonProps {
4
+ icon: VNode | Component
5
+ size?: string
6
+ svgSize?: string
7
+ tooltip?: string
8
+ }
@@ -0,0 +1,52 @@
1
+ <script setup lang="ts">
2
+ import TinyTooltip from '@opentiny/vue-tooltip'
3
+ import { IconButtonProps } from './index.type'
4
+
5
+ const props = withDefaults(defineProps<IconButtonProps>(), {
6
+ size: '24px',
7
+ svgSize: '16px',
8
+ })
9
+ </script>
10
+
11
+ <template>
12
+ <tiny-tooltip v-if="tooltip" :content="tooltip" effect="dark" placement="top" :open-delay="500">
13
+ <button class="tr-icon-button">
14
+ <component :is="props.icon" />
15
+ </button>
16
+ </tiny-tooltip>
17
+ <button v-else class="tr-icon-button">
18
+ <component :is="props.icon" />
19
+ </button>
20
+ </template>
21
+ <style lang="less" scoped>
22
+ button.tr-icon-button {
23
+ --tr-icon-button-bg: transparent;
24
+ --tr-icon-button-hover-bg: rgba(0, 0, 0, 0.04);
25
+ --tr-icon-button-active-bg: rgba(0, 0, 0, 0.15);
26
+ --tr-icon-button-border-radius: 8px;
27
+
28
+ width: v-bind('props.size');
29
+ height: v-bind('props.size');
30
+ display: inline-flex;
31
+ align-items: center;
32
+ justify-content: center;
33
+ border: none;
34
+ border-radius: var(--tr-icon-button-border-radius);
35
+ cursor: pointer;
36
+ padding: 0;
37
+ transition: background-color 0.3s;
38
+ background-color: var(--tr-icon-button-bg);
39
+
40
+ &:hover {
41
+ background-color: var(--tr-icon-button-hover-bg);
42
+ }
43
+
44
+ &:active {
45
+ background-color: var(--tr-icon-button-active-bg);
46
+ }
47
+
48
+ svg {
49
+ font-size: v-bind('props.svgSize');
50
+ }
51
+ }
52
+ </style>
package/src/index.ts CHANGED
@@ -2,17 +2,40 @@ import { App } from 'vue'
2
2
  import { Bubble, BubbleList } from './bubble'
3
3
  import Container from './container'
4
4
  import Conversations from './conversations'
5
+ import Feedback from './feedback'
6
+ import History from './history'
7
+ import IconButton from './icon-button'
5
8
  import { Prompt, Prompts } from './prompts'
6
9
  import Question from './question'
7
10
  import Sender from './sender'
8
11
  import Welcome from './welcome'
12
+ import Suggestion from './suggestion'
9
13
 
10
14
  export * from './bubble/index.type'
15
+ export * from './container/index.type'
16
+ export * from './feedback/index.type'
17
+ export * from './history/index.type'
18
+ export * from './icon-button/index.type'
11
19
  export * from './prompts/index.type'
12
20
  export * from './sender/index.type'
13
21
  export * from './welcome/index.type'
22
+ export * from './suggestion/index.type'
14
23
 
15
- const components = [Bubble, BubbleList, Container, Conversations, Prompt, Prompts, Question, Sender, Welcome]
24
+ const components = [
25
+ Bubble,
26
+ BubbleList,
27
+ Container,
28
+ Conversations,
29
+ Feedback,
30
+ History,
31
+ IconButton,
32
+ Prompt,
33
+ Prompts,
34
+ Question,
35
+ Sender,
36
+ Welcome,
37
+ Suggestion,
38
+ ]
16
39
 
17
40
  export default {
18
41
  install<T>(app: App<T>) {
@@ -32,6 +55,12 @@ export {
32
55
  Container as TrContainer,
33
56
  Conversations,
34
57
  Conversations as TrConversations,
58
+ Feedback,
59
+ Feedback as TrFeedback,
60
+ History,
61
+ History as TrHistory,
62
+ IconButton,
63
+ IconButton as TrIconButton,
35
64
  Prompt,
36
65
  Prompt as TrPrompt,
37
66
  Prompts,
@@ -40,5 +69,8 @@ export {
40
69
  Sender as TrSender,
41
70
  Welcome,
42
71
  Welcome as TrWelcome,
72
+ Suggestion,
73
+ Suggestion as TrSuggestion,
43
74
  Question,
75
+ Question as TrQuestion,
44
76
  }