2025-09-14 22:49:01 +00:00
|
|
|
<script lang="ts">
|
|
|
|
|
import type { Token } from 'marked';
|
2025-09-17 03:17:35 +00:00
|
|
|
import { LinkPreview } from 'bits-ui';
|
|
|
|
|
|
|
|
|
|
import { getContext } from 'svelte';
|
|
|
|
|
|
2025-09-17 02:41:47 +00:00
|
|
|
import { goto } from '$app/navigation';
|
|
|
|
|
import { channels, models } from '$lib/stores';
|
2025-09-17 03:17:35 +00:00
|
|
|
import UserStatus from '$lib/components/channel/Messages/Message/UserStatus.svelte';
|
|
|
|
|
|
|
|
|
|
const i18n = getContext('i18n');
|
2025-09-14 22:49:01 +00:00
|
|
|
|
|
|
|
|
export let token: Token;
|
2025-09-16 20:16:48 +00:00
|
|
|
|
|
|
|
|
let triggerChar = '';
|
|
|
|
|
let label = '';
|
|
|
|
|
|
2025-09-17 02:41:47 +00:00
|
|
|
let idType = null;
|
2025-09-16 20:16:48 +00:00
|
|
|
let id = '';
|
|
|
|
|
|
|
|
|
|
$: if (token) {
|
|
|
|
|
init();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const init = () => {
|
|
|
|
|
const _id = token?.id;
|
2025-09-17 02:41:47 +00:00
|
|
|
// split by : and take first part as idType and second part as id
|
|
|
|
|
|
|
|
|
|
const parts = _id?.split(':');
|
|
|
|
|
if (parts) {
|
|
|
|
|
idType = parts[0];
|
|
|
|
|
id = parts.slice(1).join(':'); // in case id contains ':'
|
2025-09-16 20:16:48 +00:00
|
|
|
} else {
|
2025-09-17 02:41:47 +00:00
|
|
|
idType = null;
|
2025-09-16 20:16:48 +00:00
|
|
|
id = _id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
label = token?.label ?? id;
|
|
|
|
|
triggerChar = token?.triggerChar ?? '@';
|
2025-09-17 02:41:47 +00:00
|
|
|
|
|
|
|
|
if (triggerChar === '#') {
|
|
|
|
|
if (idType === 'C') {
|
|
|
|
|
// Channel
|
|
|
|
|
const channel = $channels.find((c) => c.id === id);
|
|
|
|
|
if (channel) {
|
|
|
|
|
label = channel.name;
|
|
|
|
|
} else {
|
|
|
|
|
label = $i18n.t('Unknown');
|
|
|
|
|
}
|
|
|
|
|
} else if (idType === 'T') {
|
|
|
|
|
// Thread
|
|
|
|
|
}
|
|
|
|
|
} else if (triggerChar === '@') {
|
|
|
|
|
if (idType === 'U') {
|
|
|
|
|
// User
|
|
|
|
|
} else if (idType === 'A') {
|
|
|
|
|
// Agent/assistant/ai model
|
|
|
|
|
const model = $models.find((m) => m.id === id);
|
|
|
|
|
if (model) {
|
|
|
|
|
label = model.name;
|
|
|
|
|
} else {
|
|
|
|
|
label = $i18n.t('Unknown');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-09-16 20:16:48 +00:00
|
|
|
};
|
2025-09-14 22:49:01 +00:00
|
|
|
</script>
|
|
|
|
|
|
2025-09-17 03:17:35 +00:00
|
|
|
<LinkPreview.Root openDelay={0} closeDelay={0}>
|
|
|
|
|
<LinkPreview.Trigger class="mention cursor-pointer no-underline! font-normal! ">
|
|
|
|
|
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
|
|
|
|
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
|
|
|
|
|
|
|
|
|
<span
|
|
|
|
|
on:click={async () => {
|
|
|
|
|
if (triggerChar === '@') {
|
|
|
|
|
if (idType === 'U') {
|
|
|
|
|
// Open user profile
|
|
|
|
|
console.log('Clicked user mention', id);
|
|
|
|
|
} else if (idType === 'A') {
|
|
|
|
|
// Open agent/assistant/ai model profile
|
|
|
|
|
console.log('Clicked agent mention', id);
|
|
|
|
|
await goto(`/?model=${id}`);
|
|
|
|
|
}
|
|
|
|
|
} else if (triggerChar === '#') {
|
|
|
|
|
if (idType === 'C') {
|
|
|
|
|
// Open channel
|
|
|
|
|
if ($channels.find((c) => c.id === id)) {
|
|
|
|
|
await goto(`/channels/${id}`);
|
|
|
|
|
}
|
|
|
|
|
} else if (idType === 'T') {
|
|
|
|
|
// Open thread
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Unknown trigger char, just log
|
|
|
|
|
console.log('Clicked mention', id);
|
2025-09-17 02:41:47 +00:00
|
|
|
}
|
2025-09-17 03:17:35 +00:00
|
|
|
}}
|
|
|
|
|
>
|
|
|
|
|
{triggerChar}{label}
|
|
|
|
|
</span>
|
|
|
|
|
</LinkPreview.Trigger>
|
|
|
|
|
|
|
|
|
|
<LinkPreview.Content
|
2025-09-17 03:20:50 +00:00
|
|
|
class="max-w-full w-[260px] rounded-2xl z-9999 bg-white dark:bg-black dark:text-white shadow-lg"
|
2025-09-17 03:17:35 +00:00
|
|
|
side="top"
|
|
|
|
|
align="start"
|
|
|
|
|
sideOffset={6}
|
|
|
|
|
>
|
|
|
|
|
{#if triggerChar === '@' && idType === 'U'}
|
|
|
|
|
<UserStatus {id} />
|
|
|
|
|
{/if}
|
|
|
|
|
<!-- <div class="flex space-x-4">HI</div> -->
|
|
|
|
|
</LinkPreview.Content>
|
|
|
|
|
</LinkPreview.Root>
|