This commit is contained in:
+124
-1
@@ -5,7 +5,13 @@ const searchQuery = document.getElementById("searchQuery");
|
||||
const searchResults = document.getElementById("searchResults");
|
||||
const searchWarning = document.getElementById("searchWarning");
|
||||
const queryVariants = document.getElementById("queryVariants");
|
||||
const searchModeTitle = document.getElementById("searchModeTitle");
|
||||
const searchModeHint = document.getElementById("searchModeHint");
|
||||
const searchSubmitButton = document.getElementById("searchSubmitButton");
|
||||
const mediaTypeToggles = Array.from(document.querySelectorAll("[data-media-type-toggle]"));
|
||||
const platformToggles = Array.from(document.querySelectorAll("[data-platform-toggle]"));
|
||||
const imageSearchSandbox = document.getElementById("imageSearchSandbox");
|
||||
const imagePromptChips = Array.from(document.querySelectorAll("[data-image-prompt]"));
|
||||
const dropzone = document.getElementById("dropzone");
|
||||
const fileInput = document.getElementById("fileInput");
|
||||
const uploadResult = document.getElementById("uploadResult");
|
||||
@@ -13,6 +19,7 @@ const downloadForm = document.getElementById("downloadForm");
|
||||
const downloadUrl = document.getElementById("downloadUrl");
|
||||
const downloadResult = document.getElementById("downloadResult");
|
||||
const cardTemplate = document.getElementById("searchCardTemplate");
|
||||
const imageCardTemplate = document.getElementById("imageCardTemplate");
|
||||
const previewModal = document.getElementById("previewModal");
|
||||
const previewMediaFrame = document.getElementById("previewMediaFrame");
|
||||
const previewTitle = document.getElementById("previewTitle");
|
||||
@@ -89,7 +96,46 @@ const summaryTranslationInflight = new Map();
|
||||
const resultPreviewCache = new Map();
|
||||
const resultPreviewInflight = new Map();
|
||||
let cardSummaryObserver = null;
|
||||
let activeMediaType = "video";
|
||||
const PREVIEW_PLACEHOLDER = "https://placehold.co/1280x720/0a0a0a/ffffff?text=Preview";
|
||||
const MOCK_IMAGE_RESULTS = [
|
||||
{
|
||||
title: "Neon Crosswalk Portrait",
|
||||
tag: "Test Image",
|
||||
caption: "도심 야간 조명과 보케를 강조한 테스트용 이미지 카드입니다. 향후 이미지 검색 결과 카드 레이아웃 검증에 사용할 수 있습니다.",
|
||||
imageUrl: "https://placehold.co/1200x900/0f172a/f8fafc?text=Neon+Crosswalk",
|
||||
},
|
||||
{
|
||||
title: "Editorial Summer Street",
|
||||
tag: "Prototype",
|
||||
caption: "에디토리얼 라이프스타일 톤을 가정한 샘플 썸네일입니다. 카드 비율과 타이포 계층을 보기에 적당합니다.",
|
||||
imageUrl: "https://placehold.co/1200x900/f59e0b/111827?text=Summer+Street",
|
||||
},
|
||||
{
|
||||
title: "Minimal Product Tabletop",
|
||||
tag: "Mock Result",
|
||||
caption: "제품 컷 기반 이미지 검색을 상정한 목업 결과입니다. 이미지 중심 레이아웃에서 텍스트 양을 테스트하기 위한 예시입니다.",
|
||||
imageUrl: "https://placehold.co/1200x900/e5e7eb/111827?text=Product+Tabletop",
|
||||
},
|
||||
{
|
||||
title: "Vintage Fashion Frame",
|
||||
tag: "Image Search",
|
||||
caption: "패션 무드보드나 포스터 레퍼런스 탐색 화면에 어울리도록 구성한 테스트용 결과입니다.",
|
||||
imageUrl: "https://placehold.co/1200x900/7c3aed/f5f3ff?text=Vintage+Fashion",
|
||||
},
|
||||
{
|
||||
title: "Botanical Studio Light",
|
||||
tag: "Preview",
|
||||
caption: "정적인 피사체 중심 이미지 검색 UI에서 호버 없이도 충분히 읽히는 카드 밀도를 보기 위한 샘플입니다.",
|
||||
imageUrl: "https://placehold.co/1200x900/14532d/d1fae5?text=Botanical+Studio",
|
||||
},
|
||||
{
|
||||
title: "Magazine Cover Layout",
|
||||
tag: "Test Asset",
|
||||
caption: "향후 이미지 상세 모달이나 컬렉션 기능을 붙일 때 사용할 수 있는 테스트용 카드 자리입니다.",
|
||||
imageUrl: "https://placehold.co/1200x900/111827/fde68a?text=Magazine+Cover",
|
||||
},
|
||||
];
|
||||
|
||||
function proxiedPreviewURL(src) {
|
||||
if (!src) {
|
||||
@@ -281,6 +327,59 @@ function renderQueryVariants(queries = []) {
|
||||
queryVariants.classList.add("hidden");
|
||||
}
|
||||
|
||||
function syncMediaTypeButtons() {
|
||||
for (const button of mediaTypeToggles) {
|
||||
const type = button.dataset.mediaTypeToggle;
|
||||
const active = type === activeMediaType;
|
||||
button.classList.toggle("bg-white", active);
|
||||
button.classList.toggle("text-black", active);
|
||||
button.classList.toggle("text-zinc-300", !active);
|
||||
}
|
||||
}
|
||||
|
||||
function renderMockImageResults(queryText = "") {
|
||||
const queryLabel = String(queryText || "").trim() || "test image";
|
||||
searchResults.innerHTML = "";
|
||||
searchResults.classList.remove("xl:grid-cols-3");
|
||||
searchResults.classList.add("xl:grid-cols-4");
|
||||
for (const item of MOCK_IMAGE_RESULTS) {
|
||||
const node = imageCardTemplate.content.firstElementChild.cloneNode(true);
|
||||
const image = node.querySelector("img");
|
||||
image.src = item.imageUrl;
|
||||
image.alt = item.title;
|
||||
node.querySelector(".image-card-tag").textContent = `${item.tag} / ${queryLabel}`;
|
||||
node.querySelector(".image-card-title").textContent = item.title;
|
||||
node.querySelector(".image-card-caption").textContent = item.caption;
|
||||
searchResults.appendChild(node);
|
||||
}
|
||||
}
|
||||
|
||||
function applyMediaTypeUI() {
|
||||
const isImageMode = activeMediaType === "image";
|
||||
syncMediaTypeButtons();
|
||||
setHidden(imageSearchSandbox, !isImageMode, "block");
|
||||
setHidden(queryVariants, true, "");
|
||||
showWarning("");
|
||||
searchModeTitle.textContent = isImageMode ? "AI Image Discovery" : "AI Smart Discovery";
|
||||
searchModeHint.textContent = isImageMode
|
||||
? "이미지 검색 프로토타입 모드입니다. 현재는 UI 전용 테스트 결과를 표시합니다."
|
||||
: "비디오 검색 모드입니다. 실제 검색 API와 연결되어 있습니다.";
|
||||
searchQuery.placeholder = isImageMode ? "검색할 이미지를 설명하세요" : "한글 검색어를 입력하세요";
|
||||
searchSubmitButton.textContent = isImageMode ? "Image Search Test" : "AI Search";
|
||||
for (const button of platformToggles) {
|
||||
button.classList.toggle("hidden", isImageMode);
|
||||
}
|
||||
if (isImageMode) {
|
||||
setStatus("image prototype mode", 0);
|
||||
renderMockImageResults(searchQuery.value);
|
||||
} else {
|
||||
searchResults.classList.add("xl:grid-cols-3");
|
||||
searchResults.classList.remove("xl:grid-cols-4");
|
||||
searchResults.innerHTML = "";
|
||||
setStatus(`active platforms: ${Array.from(activePlatforms).join(", ")}`, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function syncPlatformButtons() {
|
||||
for (const button of platformToggles) {
|
||||
const platform = button.dataset.platformToggle;
|
||||
@@ -796,6 +895,12 @@ function closeResultViewer() {
|
||||
|
||||
searchForm.addEventListener("submit", async (event) => {
|
||||
event.preventDefault();
|
||||
if (activeMediaType === "image") {
|
||||
renderMockImageResults(searchQuery.value);
|
||||
logEvent("image-search:prototype", { query: searchQuery.value, results: MOCK_IMAGE_RESULTS.length });
|
||||
setStatus("image prototype results ready", 100);
|
||||
return;
|
||||
}
|
||||
setStatus("preparing search", 5);
|
||||
showWarning("");
|
||||
try {
|
||||
@@ -816,6 +921,24 @@ searchForm.addEventListener("submit", async (event) => {
|
||||
}
|
||||
});
|
||||
|
||||
for (const button of mediaTypeToggles) {
|
||||
button.addEventListener("click", () => {
|
||||
activeMediaType = button.dataset.mediaTypeToggle || "video";
|
||||
applyMediaTypeUI();
|
||||
logEvent("media-type:update", { active: activeMediaType });
|
||||
});
|
||||
}
|
||||
|
||||
for (const chip of imagePromptChips) {
|
||||
chip.addEventListener("click", () => {
|
||||
searchQuery.value = chip.dataset.imagePrompt || "";
|
||||
if (activeMediaType === "image") {
|
||||
renderMockImageResults(searchQuery.value);
|
||||
setStatus("image prompt applied", 100);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async function uploadFile(file) {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
@@ -1075,5 +1198,5 @@ window.addEventListener("unhandledrejection", (event) => {
|
||||
|
||||
connectWS();
|
||||
syncPlatformButtons();
|
||||
setStatus(`active platforms: ${Array.from(activePlatforms).join(", ")}`, 0);
|
||||
applyMediaTypeUI();
|
||||
logEvent("app:ready", { activePlatforms: Array.from(activePlatforms) });
|
||||
|
||||
Reference in New Issue
Block a user