chore: update live chat and work server changes
This commit is contained in:
131
src/app/main/mainChatPanel/previewItems.ts
Normal file
131
src/app/main/mainChatPanel/previewItems.ts
Normal file
@@ -0,0 +1,131 @@
|
||||
import { normalizeChatResourceUrl } from './chatResourceUrl';
|
||||
import { extractAutoDetectedPreviewUrls } from './inlinePreviewUrls';
|
||||
import { extractHiddenPreviewUrls } from './previewMarkers';
|
||||
import type { ChatMessage } from './types';
|
||||
|
||||
export type PreviewKind = 'image' | 'video' | 'markdown' | 'code' | 'diff' | 'document' | 'pdf' | 'file';
|
||||
|
||||
export type PreviewItem = {
|
||||
id: string;
|
||||
label: string;
|
||||
url: string;
|
||||
kind: PreviewKind;
|
||||
source: 'message' | 'context';
|
||||
};
|
||||
|
||||
function normalizePreviewUrl(value: string) {
|
||||
return normalizeChatResourceUrl(value);
|
||||
}
|
||||
|
||||
function isPreviewRouteUrl(url: string) {
|
||||
if (typeof window === 'undefined') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = new URL(url, window.location.origin);
|
||||
const pathname = parsed.pathname.toLowerCase();
|
||||
const hasKnownFileExtension = /\.[a-z0-9]+$/i.test(pathname);
|
||||
return parsed.origin === window.location.origin && !hasKnownFileExtension && /^https?:$/.test(parsed.protocol);
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export function classifyPreviewKind(url: string): PreviewKind {
|
||||
const pathname = url.toLowerCase().split('?')[0] ?? '';
|
||||
|
||||
if (/\.(png|jpe?g|gif|webp|svg|bmp|ico)$/i.test(pathname)) {
|
||||
return 'image';
|
||||
}
|
||||
|
||||
if (/\.(mp4|webm|mov|m4v|ogg)$/i.test(pathname)) {
|
||||
return 'video';
|
||||
}
|
||||
|
||||
if (/\.(md|markdown)$/i.test(pathname)) {
|
||||
return 'markdown';
|
||||
}
|
||||
|
||||
if (/\.(diff|patch)$/i.test(pathname)) {
|
||||
return 'diff';
|
||||
}
|
||||
|
||||
if (/\.(ts|tsx|js|jsx|json|css|scss|html|xml|java|kt|sql|sh|py|go|rs|c|cpp|h|hpp|yml|yaml)$/i.test(pathname)) {
|
||||
return 'code';
|
||||
}
|
||||
|
||||
if (/\.(txt|log|csv)$/i.test(pathname)) {
|
||||
return 'document';
|
||||
}
|
||||
|
||||
if (/\.pdf$/i.test(pathname)) {
|
||||
return 'pdf';
|
||||
}
|
||||
|
||||
if (isPreviewRouteUrl(url)) {
|
||||
return 'document';
|
||||
}
|
||||
|
||||
return 'file';
|
||||
}
|
||||
|
||||
export function buildPreviewLabel(url: string, source: PreviewItem['source']) {
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
const lastSegment = parsed.pathname.split('/').filter(Boolean).at(-1);
|
||||
|
||||
if (lastSegment) {
|
||||
return source === 'context' ? `현재 화면 · ${lastSegment}` : lastSegment;
|
||||
}
|
||||
|
||||
return source === 'context' ? '현재 화면 미리보기' : parsed.hostname;
|
||||
} catch {
|
||||
return source === 'context' ? '현재 화면 미리보기' : url;
|
||||
}
|
||||
}
|
||||
|
||||
export function isHtmlPreviewItem(item: PreviewItem | null | undefined) {
|
||||
if (!item || item.kind !== 'code') {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
const parsed = new URL(item.url, typeof window !== 'undefined' ? window.location.origin : 'https://local.invalid');
|
||||
const pathname = parsed.pathname.toLowerCase();
|
||||
return pathname.endsWith('.html') || pathname.endsWith('.htm');
|
||||
} catch {
|
||||
const pathname = item.url.toLowerCase().split('?')[0] ?? '';
|
||||
return pathname.endsWith('.html') || pathname.endsWith('.htm');
|
||||
}
|
||||
}
|
||||
|
||||
export function extractPreviewItems(messages: ChatMessage[]) {
|
||||
const seen = new Set<string>();
|
||||
const items: PreviewItem[] = [];
|
||||
const orderedMessages = [...messages].reverse();
|
||||
|
||||
orderedMessages.forEach((message) => {
|
||||
const matches = [...extractAutoDetectedPreviewUrls(message.text), ...extractHiddenPreviewUrls(message.text)];
|
||||
|
||||
matches.forEach((matchedUrl) => {
|
||||
const normalizedUrl = normalizePreviewUrl(matchedUrl);
|
||||
const kind = classifyPreviewKind(normalizedUrl);
|
||||
|
||||
if (seen.has(normalizedUrl)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seen.add(normalizedUrl);
|
||||
items.push({
|
||||
id: `${message.id}-${normalizedUrl}`,
|
||||
label: buildPreviewLabel(normalizedUrl, 'message'),
|
||||
url: normalizedUrl,
|
||||
kind,
|
||||
source: 'message',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return items.slice(0, 12);
|
||||
}
|
||||
Reference in New Issue
Block a user