pukaad-ui-lib 1.460.0 → 1.462.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/dist/module.json +1 -1
- package/dist/runtime/components/card/card-mention/card-mention.d.vue.ts +2 -1
- package/dist/runtime/components/card/card-mention/card-mention.vue +3 -2
- package/dist/runtime/components/card/card-mention/card-mention.vue.d.ts +2 -1
- package/dist/runtime/components/chat/chat-message-bubble.d.vue.ts +3 -1
- package/dist/runtime/components/chat/chat-message-bubble.vue +16 -2
- package/dist/runtime/components/chat/chat-message-bubble.vue.d.ts +3 -1
- package/dist/runtime/components/chat/chat-room.d.vue.ts +6 -1
- package/dist/runtime/components/chat/chat-room.vue +20 -1
- package/dist/runtime/components/chat/chat-room.vue.d.ts +6 -1
- package/dist/runtime/components/draggable.d.vue.ts +26 -3
- package/dist/runtime/components/draggable.vue +67 -20
- package/dist/runtime/components/draggable.vue.d.ts +26 -3
- package/dist/runtime/components/input/input-chat.d.vue.ts +2 -0
- package/dist/runtime/components/input/input-chat.vue +7 -2
- package/dist/runtime/components/input/input-chat.vue.d.ts +2 -0
- package/dist/runtime/components/input/input-comment.d.vue.ts +1 -1
- package/dist/runtime/components/input/input-comment.vue.d.ts +1 -1
- package/dist/runtime/components/input/input-mention.vue +4 -20
- package/dist/runtime/components/modal/modal-chat-share.d.vue.ts +17 -0
- package/dist/runtime/components/modal/modal-chat-share.vue +214 -0
- package/dist/runtime/components/modal/modal-chat-share.vue.d.ts +17 -0
- package/dist/runtime/components/modal/modal-password-confirmed.d.vue.ts +1 -1
- package/dist/runtime/components/modal/modal-password-confirmed.vue.d.ts +1 -1
- package/dist/runtime/components/modal/modal-password-verify.d.vue.ts +1 -1
- package/dist/runtime/components/modal/modal-password-verify.vue.d.ts +1 -1
- package/dist/runtime/composables/store-chat.d.ts +83 -2
- package/dist/runtime/composables/store-chat.js +39 -5
- package/dist/runtime/composables/useChatSession.d.ts +82 -1
- package/dist/runtime/types/chat.d.ts +16 -1
- package/dist/runtime/utils/mention.d.ts +39 -0
- package/dist/runtime/utils/mention.js +52 -0
- package/package.json +1 -1
package/dist/module.json
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export interface CardMentionItem {
|
|
2
2
|
id: string;
|
|
3
|
-
mentionType: "post" | "blog" | "link";
|
|
3
|
+
mentionType: "post" | "blog" | "place" | "link";
|
|
4
4
|
title: string;
|
|
5
5
|
contentType?: string;
|
|
6
6
|
coverColor?: string;
|
|
7
7
|
image?: string | null;
|
|
8
8
|
thumbnail?: string;
|
|
9
9
|
placeName?: string;
|
|
10
|
+
address?: string;
|
|
10
11
|
author?: {
|
|
11
12
|
name: string;
|
|
12
13
|
avatar?: string | null;
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
/>
|
|
33
33
|
</template>
|
|
34
34
|
<Image
|
|
35
|
-
v-else-if="props.item.mentionType === 'blog'"
|
|
35
|
+
v-else-if="props.item.mentionType === 'blog' || props.item.mentionType === 'place'"
|
|
36
36
|
:src="props.item.image ?? ''"
|
|
37
37
|
:width="71"
|
|
38
38
|
:height="40"
|
|
39
|
-
class="shrink-0 rounded-[4px]"
|
|
39
|
+
class="shrink-0 rounded-[4px] bg-cloud"
|
|
40
40
|
/>
|
|
41
41
|
|
|
42
42
|
<div class="flex flex-col gap-[4px] min-w-0 flex-1">
|
|
@@ -98,6 +98,7 @@ const displayTitle = computed(() => {
|
|
|
98
98
|
const subtitle = computed(() => {
|
|
99
99
|
if (props.item.mentionType === "link") return props.item.url;
|
|
100
100
|
if (isPost.value) return props.item.placeName;
|
|
101
|
+
if (props.item.mentionType === "place") return props.item.address;
|
|
101
102
|
return "";
|
|
102
103
|
});
|
|
103
104
|
</script>
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
export interface CardMentionItem {
|
|
2
2
|
id: string;
|
|
3
|
-
mentionType: "post" | "blog" | "link";
|
|
3
|
+
mentionType: "post" | "blog" | "place" | "link";
|
|
4
4
|
title: string;
|
|
5
5
|
contentType?: string;
|
|
6
6
|
coverColor?: string;
|
|
7
7
|
image?: string | null;
|
|
8
8
|
thumbnail?: string;
|
|
9
9
|
placeName?: string;
|
|
10
|
+
address?: string;
|
|
10
11
|
author?: {
|
|
11
12
|
name: string;
|
|
12
13
|
avatar?: string | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatMessage } from "../../types/chat.js";
|
|
1
|
+
import type { ChatMessage, ChatSharePreview } from "../../types/chat.js";
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
message: ChatMessage;
|
|
4
4
|
mine: boolean;
|
|
@@ -16,6 +16,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
16
16
|
retry: (message: ChatMessage) => void;
|
|
17
17
|
"open-media": (message: ChatMessage, index: number) => void;
|
|
18
18
|
jump: (messageId: string) => void;
|
|
19
|
+
"open-share": (share: ChatSharePreview) => void;
|
|
19
20
|
"media-error": () => void;
|
|
20
21
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
21
22
|
onDelete?: ((message: ChatMessage) => any) | undefined;
|
|
@@ -23,6 +24,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
23
24
|
onRetry?: ((message: ChatMessage) => any) | undefined;
|
|
24
25
|
"onOpen-media"?: ((message: ChatMessage, index: number) => any) | undefined;
|
|
25
26
|
onJump?: ((messageId: string) => any) | undefined;
|
|
27
|
+
"onOpen-share"?: ((share: ChatSharePreview) => any) | undefined;
|
|
26
28
|
"onMedia-error"?: (() => any) | undefined;
|
|
27
29
|
}>, {
|
|
28
30
|
showMeta: boolean;
|
|
@@ -40,8 +40,19 @@
|
|
|
40
40
|
>
|
|
41
41
|
{{ mine ? "\u0E04\u0E38\u0E13\u0E25\u0E1A\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E19\u0E35\u0E49" : `${peerName} \u0E25\u0E1A\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E19\u0E35\u0E49` }}
|
|
42
42
|
</div>
|
|
43
|
+
<button
|
|
44
|
+
v-else-if="message.kind === 'share' && message.share"
|
|
45
|
+
type="button"
|
|
46
|
+
:class="[
|
|
47
|
+
'block w-[320px] max-w-full rounded-[8px] bg-white p-[8px] text-left shadow-[0_1px_6px_rgba(0,0,0,0.15)]',
|
|
48
|
+
message.status === 'sending' ? 'opacity-60' : ''
|
|
49
|
+
]"
|
|
50
|
+
@click="emit('open-share', message.share)"
|
|
51
|
+
>
|
|
52
|
+
<CardMention :item="mapShare(message.share)" />
|
|
53
|
+
</button>
|
|
43
54
|
<ChatMediaGrid
|
|
44
|
-
v-else-if="message.kind
|
|
55
|
+
v-else-if="message.kind === 'image' || message.kind === 'video'"
|
|
45
56
|
:items="message.attachments"
|
|
46
57
|
:progress="message.status === 'sending' ? message.progress ?? 0 : void 0"
|
|
47
58
|
@open="(i) => emit('open-media', message, i)"
|
|
@@ -111,6 +122,8 @@
|
|
|
111
122
|
import { computed, ref, useTemplateRef } from "vue";
|
|
112
123
|
import { onLongPress, useElementHover } from "@vueuse/core";
|
|
113
124
|
import { useConvert } from "../../composables/useConvert";
|
|
125
|
+
import CardMention from "../card/card-mention/card-mention.vue";
|
|
126
|
+
import { mapShare } from "../../utils/mention";
|
|
114
127
|
const { convertDateTime } = useConvert();
|
|
115
128
|
const props = defineProps({
|
|
116
129
|
message: { type: Object, required: true },
|
|
@@ -123,7 +136,7 @@ const props = defineProps({
|
|
|
123
136
|
showMeta: { type: Boolean, required: false, default: true },
|
|
124
137
|
highlighted: { type: Boolean, required: false }
|
|
125
138
|
});
|
|
126
|
-
const emit = defineEmits(["delete", "retry", "reply", "open-media", "jump", "media-error"]);
|
|
139
|
+
const emit = defineEmits(["delete", "retry", "reply", "open-media", "jump", "open-share", "media-error"]);
|
|
127
140
|
const isMenuOpen = ref(false);
|
|
128
141
|
const contentRef = useTemplateRef("contentRef");
|
|
129
142
|
const rowRef = useTemplateRef("rowRef");
|
|
@@ -146,6 +159,7 @@ const replyText = computed(() => {
|
|
|
146
159
|
if (r.is_deleted) return "\u0E02\u0E49\u0E2D\u0E04\u0E27\u0E32\u0E21\u0E19\u0E35\u0E49\u0E16\u0E39\u0E01\u0E25\u0E1A\u0E41\u0E25\u0E49\u0E27";
|
|
147
160
|
if (r.kind === "image") return r.body || "\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E";
|
|
148
161
|
if (r.kind === "video") return r.body || "\u0E27\u0E34\u0E14\u0E35\u0E42\u0E2D";
|
|
162
|
+
if (r.kind === "share") return r.body || "\u0E02\u0E49\u0E2D\u0E21\u0E39\u0E25\u0E17\u0E35\u0E48\u0E41\u0E0A\u0E23\u0E4C";
|
|
149
163
|
return r.body;
|
|
150
164
|
});
|
|
151
165
|
</script>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChatMessage } from "../../types/chat.js";
|
|
1
|
+
import type { ChatMessage, ChatSharePreview } from "../../types/chat.js";
|
|
2
2
|
type __VLS_Props = {
|
|
3
3
|
message: ChatMessage;
|
|
4
4
|
mine: boolean;
|
|
@@ -16,6 +16,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
16
16
|
retry: (message: ChatMessage) => void;
|
|
17
17
|
"open-media": (message: ChatMessage, index: number) => void;
|
|
18
18
|
jump: (messageId: string) => void;
|
|
19
|
+
"open-share": (share: ChatSharePreview) => void;
|
|
19
20
|
"media-error": () => void;
|
|
20
21
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
21
22
|
onDelete?: ((message: ChatMessage) => any) | undefined;
|
|
@@ -23,6 +24,7 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {
|
|
|
23
24
|
onRetry?: ((message: ChatMessage) => any) | undefined;
|
|
24
25
|
"onOpen-media"?: ((message: ChatMessage, index: number) => any) | undefined;
|
|
25
26
|
onJump?: ((messageId: string) => any) | undefined;
|
|
27
|
+
"onOpen-share"?: ((share: ChatSharePreview) => any) | undefined;
|
|
26
28
|
"onMedia-error"?: (() => any) | undefined;
|
|
27
29
|
}>, {
|
|
28
30
|
showMeta: boolean;
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import type { ChatSharePreview } from "../../types/chat.js";
|
|
1
2
|
type __VLS_Props = {
|
|
2
3
|
conversationId: string;
|
|
3
4
|
};
|
|
4
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"open-share": (share: ChatSharePreview) => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
8
|
+
"onOpen-share"?: ((share: ChatSharePreview) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
10
|
declare const _default: typeof __VLS_export;
|
|
6
11
|
export default _default;
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
@retry="onRetry"
|
|
52
52
|
@open-media="onOpenMedia"
|
|
53
53
|
@media-error="onMediaError"
|
|
54
|
+
@open-share="(share) => emit('open-share', share)"
|
|
54
55
|
/>
|
|
55
56
|
<div v-if="isPeerTyping" class="flex items-end gap-[8px]">
|
|
56
57
|
<div class="flex items-center gap-[4px] rounded-[16px] bg-silver px-[12px] py-[12px]" aria-label="กำลังพิมพ์">
|
|
@@ -74,10 +75,17 @@
|
|
|
74
75
|
<Icon name="lucide:x" class="size-[20px]" />
|
|
75
76
|
</Button>
|
|
76
77
|
</div>
|
|
77
|
-
<InputChat
|
|
78
|
+
<InputChat
|
|
79
|
+
ref="composerRef"
|
|
80
|
+
v-model="draft"
|
|
81
|
+
:maxlength="4e3"
|
|
82
|
+
@send="onSend"
|
|
83
|
+
@share="isShareOpen = true"
|
|
84
|
+
/>
|
|
78
85
|
</div>
|
|
79
86
|
</div>
|
|
80
87
|
<ChatMediaViewer v-model="isViewerOpen" :items="viewerItems" :start-index="viewerStart" />
|
|
88
|
+
<ModalChatShare v-model="isShareOpen" :profile-ids="shareProfileIds" @send="onShare" />
|
|
81
89
|
</template>
|
|
82
90
|
|
|
83
91
|
<div v-else class="flex flex-1 flex-col items-center justify-center gap-[16px] p-[16px]">
|
|
@@ -143,14 +151,24 @@ import {
|
|
|
143
151
|
useTimeoutFn
|
|
144
152
|
} from "@vueuse/core";
|
|
145
153
|
import { useChatStore } from "../../composables/store-chat";
|
|
154
|
+
import { toSharePreview } from "../../utils/mention";
|
|
146
155
|
const props = defineProps({
|
|
147
156
|
conversationId: { type: String, required: true }
|
|
148
157
|
});
|
|
158
|
+
const emit = defineEmits(["open-share"]);
|
|
149
159
|
const storeChat = useChatStore();
|
|
150
160
|
const { $toast, $alert } = useNuxtApp();
|
|
151
161
|
const conversationId = computed(() => props.conversationId);
|
|
152
162
|
const conversation = computed(() => storeChat.headers[conversationId.value]);
|
|
153
163
|
const messageList = computed(() => storeChat.messages[conversationId.value] ?? []);
|
|
164
|
+
const isShareOpen = ref(false);
|
|
165
|
+
const shareProfileIds = computed(
|
|
166
|
+
() => [storeChat.myProfileId, conversation.value?.profile?.id].filter((id) => !!id)
|
|
167
|
+
);
|
|
168
|
+
const onShare = (item) => {
|
|
169
|
+
isShareOpen.value = false;
|
|
170
|
+
void storeChat.sendShare(conversationId.value, toSharePreview(item));
|
|
171
|
+
};
|
|
154
172
|
const TIME_GROUP_GAP_MS = 5 * 60 * 1e3;
|
|
155
173
|
const isLastOfTimeGroup = (index) => {
|
|
156
174
|
const message = messageList.value[index];
|
|
@@ -295,6 +313,7 @@ const replyBarText = computed(() => {
|
|
|
295
313
|
if (!m) return "";
|
|
296
314
|
if (m.kind === "image") return "\u0E23\u0E39\u0E1B\u0E20\u0E32\u0E1E";
|
|
297
315
|
if (m.kind === "video") return "\u0E27\u0E34\u0E14\u0E35\u0E42\u0E2D";
|
|
316
|
+
if (m.kind === "share") return m.share?.title ?? "";
|
|
298
317
|
return m.body.replace(/\s+/g, " ");
|
|
299
318
|
});
|
|
300
319
|
const onReply = (message) => {
|
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
import type { ChatSharePreview } from "../../types/chat.js";
|
|
1
2
|
type __VLS_Props = {
|
|
2
3
|
conversationId: string;
|
|
3
4
|
};
|
|
4
|
-
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
"open-share": (share: ChatSharePreview) => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
8
|
+
"onOpen-share"?: ((share: ChatSharePreview) => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
5
10
|
declare const _default: typeof __VLS_export;
|
|
6
11
|
export default _default;
|
|
@@ -1,18 +1,41 @@
|
|
|
1
|
+
interface DraggableProps {
|
|
2
|
+
itemKey?: string;
|
|
3
|
+
handle?: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface DraggableMoveEvent {
|
|
7
|
+
item: any;
|
|
8
|
+
oldIndex: number;
|
|
9
|
+
newIndex: number;
|
|
10
|
+
}
|
|
11
|
+
type __VLS_Props = DraggableProps;
|
|
1
12
|
type __VLS_ModelProps = {
|
|
2
13
|
modelValue?: any[];
|
|
3
14
|
};
|
|
15
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
4
16
|
declare var __VLS_1: {
|
|
5
17
|
item: any;
|
|
6
18
|
index: number;
|
|
19
|
+
dragging: boolean;
|
|
7
20
|
};
|
|
8
21
|
type __VLS_Slots = {} & {
|
|
9
22
|
item?: (props: typeof __VLS_1) => any;
|
|
10
23
|
};
|
|
11
|
-
declare const __VLS_base: import("vue").DefineComponent<
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
change: (event: DraggableMoveEvent) => any;
|
|
26
|
+
start: (index: number) => any;
|
|
27
|
+
end: (event: DraggableMoveEvent) => any;
|
|
12
28
|
"update:modelValue": (value: any[]) => any;
|
|
13
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
29
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
30
|
+
onChange?: ((event: DraggableMoveEvent) => any) | undefined;
|
|
31
|
+
onStart?: ((index: number) => any) | undefined;
|
|
32
|
+
onEnd?: ((event: DraggableMoveEvent) => any) | undefined;
|
|
14
33
|
"onUpdate:modelValue"?: ((value: any[]) => any) | undefined;
|
|
15
|
-
}>, {
|
|
34
|
+
}>, {
|
|
35
|
+
disabled: boolean;
|
|
36
|
+
itemKey: string;
|
|
37
|
+
handle: string;
|
|
38
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
39
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
17
40
|
declare const _default: typeof __VLS_export;
|
|
18
41
|
export default _default;
|
|
@@ -1,40 +1,87 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div v-bind="$attrs">
|
|
3
3
|
<div
|
|
4
|
-
v-for="(
|
|
5
|
-
:key="
|
|
6
|
-
class="
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@
|
|
4
|
+
v-for="(item, index) in items"
|
|
5
|
+
:key="getItemKey(item, index)"
|
|
6
|
+
:class="[
|
|
7
|
+
!props.disabled && !props.handle && 'cursor-grab active:cursor-grabbing'
|
|
8
|
+
]"
|
|
9
|
+
:draggable="isItemDraggable(index)"
|
|
10
|
+
@mousedown="onMouseDown($event, index)"
|
|
11
|
+
@mouseup="handleIndex = null"
|
|
12
|
+
@dragstart="onDragStart($event, index)"
|
|
13
|
+
@dragover.prevent="onDragOver(index)"
|
|
14
|
+
@dragend="onDragEnd"
|
|
11
15
|
@dragenter.prevent
|
|
12
16
|
@dragleave.prevent
|
|
13
17
|
>
|
|
14
|
-
<slot
|
|
18
|
+
<slot
|
|
19
|
+
name="item"
|
|
20
|
+
:item="item"
|
|
21
|
+
:index="index"
|
|
22
|
+
:dragging="currentIndex === index"
|
|
23
|
+
></slot>
|
|
15
24
|
</div>
|
|
16
25
|
</div>
|
|
17
26
|
</template>
|
|
18
27
|
|
|
19
28
|
<script setup>
|
|
20
29
|
import { ref } from "vue";
|
|
30
|
+
const props = defineProps({
|
|
31
|
+
itemKey: { type: String, required: false, default: "" },
|
|
32
|
+
handle: { type: String, required: false, default: "" },
|
|
33
|
+
disabled: { type: Boolean, required: false, default: false }
|
|
34
|
+
});
|
|
35
|
+
const emit = defineEmits(["start", "end", "change"]);
|
|
21
36
|
const items = defineModel({ type: Array, ...{
|
|
22
37
|
default: []
|
|
23
38
|
} });
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
39
|
+
const startIndex = ref(null);
|
|
40
|
+
const currentIndex = ref(null);
|
|
41
|
+
const handleIndex = ref(null);
|
|
42
|
+
const getItemKey = (item, index) => props.itemKey ? item?.[props.itemKey] : index;
|
|
43
|
+
const isItemDraggable = (index) => {
|
|
44
|
+
if (props.disabled) return false;
|
|
45
|
+
if (!props.handle) return true;
|
|
46
|
+
return handleIndex.value === index;
|
|
27
47
|
};
|
|
28
|
-
const
|
|
29
|
-
|
|
48
|
+
const onMouseDown = (event, index) => {
|
|
49
|
+
if (!props.handle) return;
|
|
50
|
+
const row = event.currentTarget;
|
|
51
|
+
const handleEl = event.target.closest(props.handle);
|
|
52
|
+
handleIndex.value = handleEl && row.contains(handleEl) ? index : null;
|
|
30
53
|
};
|
|
31
|
-
const
|
|
32
|
-
if (
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
54
|
+
const onDragStart = (event, index) => {
|
|
55
|
+
if (!isItemDraggable(index)) {
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (event.dataTransfer && event.target === event.currentTarget) {
|
|
60
|
+
event.dataTransfer.setData("text/plain", "");
|
|
61
|
+
event.dataTransfer.effectAllowed = "move";
|
|
38
62
|
}
|
|
63
|
+
startIndex.value = index;
|
|
64
|
+
currentIndex.value = index;
|
|
65
|
+
emit("start", index);
|
|
66
|
+
};
|
|
67
|
+
const onDragOver = (index) => {
|
|
68
|
+
const from = currentIndex.value;
|
|
69
|
+
if (from === null || from === index) return;
|
|
70
|
+
const next = [...items.value];
|
|
71
|
+
const [moved] = next.splice(from, 1);
|
|
72
|
+
next.splice(index, 0, moved);
|
|
73
|
+
items.value = next;
|
|
74
|
+
currentIndex.value = index;
|
|
75
|
+
};
|
|
76
|
+
const onDragEnd = () => {
|
|
77
|
+
const oldIndex = startIndex.value;
|
|
78
|
+
const newIndex = currentIndex.value;
|
|
79
|
+
startIndex.value = null;
|
|
80
|
+
currentIndex.value = null;
|
|
81
|
+
handleIndex.value = null;
|
|
82
|
+
if (oldIndex === null || newIndex === null) return;
|
|
83
|
+
const payload = { item: items.value[newIndex], oldIndex, newIndex };
|
|
84
|
+
emit("end", payload);
|
|
85
|
+
if (oldIndex !== newIndex) emit("change", payload);
|
|
39
86
|
};
|
|
40
87
|
</script>
|
|
@@ -1,18 +1,41 @@
|
|
|
1
|
+
interface DraggableProps {
|
|
2
|
+
itemKey?: string;
|
|
3
|
+
handle?: string;
|
|
4
|
+
disabled?: boolean;
|
|
5
|
+
}
|
|
6
|
+
interface DraggableMoveEvent {
|
|
7
|
+
item: any;
|
|
8
|
+
oldIndex: number;
|
|
9
|
+
newIndex: number;
|
|
10
|
+
}
|
|
11
|
+
type __VLS_Props = DraggableProps;
|
|
1
12
|
type __VLS_ModelProps = {
|
|
2
13
|
modelValue?: any[];
|
|
3
14
|
};
|
|
15
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
4
16
|
declare var __VLS_1: {
|
|
5
17
|
item: any;
|
|
6
18
|
index: number;
|
|
19
|
+
dragging: boolean;
|
|
7
20
|
};
|
|
8
21
|
type __VLS_Slots = {} & {
|
|
9
22
|
item?: (props: typeof __VLS_1) => any;
|
|
10
23
|
};
|
|
11
|
-
declare const __VLS_base: import("vue").DefineComponent<
|
|
24
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
25
|
+
change: (event: DraggableMoveEvent) => any;
|
|
26
|
+
start: (index: number) => any;
|
|
27
|
+
end: (event: DraggableMoveEvent) => any;
|
|
12
28
|
"update:modelValue": (value: any[]) => any;
|
|
13
|
-
}, string, import("vue").PublicProps, Readonly<
|
|
29
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
30
|
+
onChange?: ((event: DraggableMoveEvent) => any) | undefined;
|
|
31
|
+
onStart?: ((index: number) => any) | undefined;
|
|
32
|
+
onEnd?: ((event: DraggableMoveEvent) => any) | undefined;
|
|
14
33
|
"onUpdate:modelValue"?: ((value: any[]) => any) | undefined;
|
|
15
|
-
}>, {
|
|
34
|
+
}>, {
|
|
35
|
+
disabled: boolean;
|
|
36
|
+
itemKey: string;
|
|
37
|
+
handle: string;
|
|
38
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
39
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
17
40
|
declare const _default: typeof __VLS_export;
|
|
18
41
|
export default _default;
|
|
@@ -39,10 +39,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
39
39
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
40
40
|
"update:modelValue": (value: string) => any;
|
|
41
41
|
send: (payload: InputChatSendPayload) => any;
|
|
42
|
+
share: () => any;
|
|
42
43
|
"update:media": (value: InputChatMediaItem[]) => any;
|
|
43
44
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
44
45
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
45
46
|
onSend?: ((payload: InputChatSendPayload) => any) | undefined;
|
|
47
|
+
onShare?: (() => any) | undefined;
|
|
46
48
|
"onUpdate:media"?: ((value: InputChatMediaItem[]) => any) | undefined;
|
|
47
49
|
}>, {
|
|
48
50
|
disabled: boolean;
|
|
@@ -21,7 +21,12 @@
|
|
|
21
21
|
>
|
|
22
22
|
<Icon name="lucide:video" class="size-[20px] text-black" />
|
|
23
23
|
</Button>
|
|
24
|
-
<Button
|
|
24
|
+
<Button
|
|
25
|
+
variant="text"
|
|
26
|
+
class="w-[32px] h-[32px] disabled:opacity-100"
|
|
27
|
+
:disabled="props.disabled"
|
|
28
|
+
@click="emit('share')"
|
|
29
|
+
>
|
|
25
30
|
<Icon name="lucide:megaphone" class="size-[20px] text-black" />
|
|
26
31
|
</Button>
|
|
27
32
|
<Button variant="text" class="w-[32px] h-[32px] disabled:opacity-100" disabled>
|
|
@@ -111,7 +116,7 @@ const props = defineProps({
|
|
|
111
116
|
disabledMedia: { type: Boolean, required: false, default: false },
|
|
112
117
|
class: { type: null, required: false }
|
|
113
118
|
});
|
|
114
|
-
const emit = defineEmits(["send"]);
|
|
119
|
+
const emit = defineEmits(["send", "share"]);
|
|
115
120
|
const text = defineModel({ type: String, ...{ default: "" } });
|
|
116
121
|
const media = defineModel("media", { type: Array, ...{ default: [] } });
|
|
117
122
|
const ACCEPT_IMAGE = "image/jpeg,image/png,image/webp,image/gif";
|
|
@@ -39,10 +39,12 @@ declare const __VLS_base: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
39
39
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
40
40
|
"update:modelValue": (value: string) => any;
|
|
41
41
|
send: (payload: InputChatSendPayload) => any;
|
|
42
|
+
share: () => any;
|
|
42
43
|
"update:media": (value: InputChatMediaItem[]) => any;
|
|
43
44
|
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
44
45
|
"onUpdate:modelValue"?: ((value: string) => any) | undefined;
|
|
45
46
|
onSend?: ((payload: InputChatSendPayload) => any) | undefined;
|
|
47
|
+
onShare?: (() => any) | undefined;
|
|
46
48
|
"onUpdate:media"?: ((value: InputChatMediaItem[]) => any) | undefined;
|
|
47
49
|
}>, {
|
|
48
50
|
disabled: boolean;
|
|
@@ -48,9 +48,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
48
48
|
disabled: boolean;
|
|
49
49
|
placeholder: string;
|
|
50
50
|
autofocus: boolean;
|
|
51
|
+
cancelText: string;
|
|
51
52
|
disabledAvatar: boolean;
|
|
52
53
|
submitText: string;
|
|
53
|
-
cancelText: string;
|
|
54
54
|
actionsOnFocus: boolean;
|
|
55
55
|
disabledActions: boolean;
|
|
56
56
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -48,9 +48,9 @@ declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {
|
|
|
48
48
|
disabled: boolean;
|
|
49
49
|
placeholder: string;
|
|
50
50
|
autofocus: boolean;
|
|
51
|
+
cancelText: string;
|
|
51
52
|
disabledAvatar: boolean;
|
|
52
53
|
submitText: string;
|
|
53
|
-
cancelText: string;
|
|
54
54
|
actionsOnFocus: boolean;
|
|
55
55
|
disabledActions: boolean;
|
|
56
56
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
@@ -125,6 +125,10 @@ import { useApi } from "../../composables/useApi";
|
|
|
125
125
|
import CardMention, {
|
|
126
126
|
} from "../card/card-mention/card-mention.vue";
|
|
127
127
|
import CardMentionSkeleton from "../card/card-mention/card-mention-skeleton.vue";
|
|
128
|
+
import {
|
|
129
|
+
mapBlog,
|
|
130
|
+
mapPost
|
|
131
|
+
} from "../../utils/mention";
|
|
128
132
|
const props = defineProps({
|
|
129
133
|
label: { type: String, required: false, default: "\u0E01\u0E32\u0E23\u0E40\u0E2D\u0E48\u0E22\u0E16\u0E36\u0E07" },
|
|
130
134
|
placeholder: { type: String, required: false, default: "\u0E40\u0E1E\u0E34\u0E48\u0E21\u0E01\u0E32\u0E23\u0E40\u0E2D\u0E48\u0E22\u0E16\u0E36\u0E07" }
|
|
@@ -150,26 +154,6 @@ const states = reactive({
|
|
|
150
154
|
});
|
|
151
155
|
const generations = { post: 0, blog: 0, link: 0 };
|
|
152
156
|
const linkId = (url) => `link:${url}`;
|
|
153
|
-
const mapPost = (raw) => {
|
|
154
|
-
const contentType = raw.content_type === "post_it" ? "post-it" : raw.content_type;
|
|
155
|
-
return {
|
|
156
|
-
id: raw.id,
|
|
157
|
-
mentionType: "post",
|
|
158
|
-
title: raw.cover_text?.trim() || raw.description?.trim() || "",
|
|
159
|
-
contentType,
|
|
160
|
-
coverColor: contentType === "post-it" ? raw.cover_color : void 0,
|
|
161
|
-
image: contentType === "image" ? raw.media?.[0]?.url ?? null : null,
|
|
162
|
-
thumbnail: contentType === "video" ? raw.video_poster_url : void 0,
|
|
163
|
-
placeName: raw.places?.[0]?.name || void 0
|
|
164
|
-
};
|
|
165
|
-
};
|
|
166
|
-
const mapBlog = (raw) => ({
|
|
167
|
-
id: raw.id,
|
|
168
|
-
mentionType: "blog",
|
|
169
|
-
title: raw.title,
|
|
170
|
-
image: raw.cover_image_url,
|
|
171
|
-
author: raw.author ? { name: raw.author.name, avatar: raw.author.avatar } : void 0
|
|
172
|
-
});
|
|
173
157
|
const mapLink = (raw) => ({
|
|
174
158
|
id: linkId(raw.url),
|
|
175
159
|
mentionType: "link",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type CardMentionItem } from "../card/card-mention/card-mention.vue.js";
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
profileIds: string[];
|
|
4
|
+
};
|
|
5
|
+
type __VLS_ModelProps = {
|
|
6
|
+
modelValue?: boolean;
|
|
7
|
+
};
|
|
8
|
+
type __VLS_PublicProps = __VLS_Props & __VLS_ModelProps;
|
|
9
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
10
|
+
"update:modelValue": (value: boolean) => any;
|
|
11
|
+
send: (item: CardMentionItem) => any;
|
|
12
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{
|
|
13
|
+
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
14
|
+
onSend?: ((item: CardMentionItem) => any) | undefined;
|
|
15
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
16
|
+
declare const _default: typeof __VLS_export;
|
|
17
|
+
export default _default;
|