Refine modal actions and hide query variants
build-push / docker (push) Successful in 4m29s

This commit is contained in:
AI Assistant
2026-03-16 17:09:56 +09:00
parent 19425c9503
commit 001f4fd4bb
4 changed files with 68 additions and 30 deletions
+16
View File
@@ -255,6 +255,22 @@
- backend debug broadcasts - backend debug broadcasts
## Recent Change Log ## Recent Change Log
- Date: `2026-03-16`
- What changed:
- Hid the expanded query-variant chip list from the search UI while leaving backend/debug query visibility intact.
- Reworked the result modal action panel so its primary CTA now follows source capability: `Direct Download` for Google Video and `Open Source` for Envato/Artgrid.
- Added a secondary action button area plus internal scrolling for long Source Summary text so long descriptions no longer push action buttons off-screen.
- Switched Google Video modal rendering from iframe-style embed-first behavior to a webpage-like preview panel, while keeping Artgrid/Envato on the existing media-mode path.
- Bumped the frontend asset version again to force browsers onto the updated modal behavior.
- Why it changed:
- The remaining user issues were now primarily UX/layout issues: too little visible result choice, hidden buttons under long summaries, query-variant clutter, and modal actions that did not match what each source can actually do.
- How it was verified:
- `go test ./...`
- `bash scripts/selftest.sh`
- What is still risky or incomplete:
- Live browser validation is still needed to confirm the widened search pool feels better in real queries and that the new Google Video panel feels sufficiently “webpage-like” in practice.
- `node` is still unavailable in this environment, so no frontend static syntax/build step was added here.
- Date: `2026-03-16` - Date: `2026-03-16`
- What changed: - What changed:
- Expanded search breadth moderately by increasing base query count, collector query budgets, per-source caps, enrichment scope, and final visible result target while keeping Gemini review cap at `16`. - Expanded search breadth moderately by increasing base query count, collector query budgets, per-source caps, enrichment scope, and final visible result target while keeping Gemini review cap at `16`.
+28 -22
View File
@@ -52,6 +52,7 @@ const resultModalGoogleText = document.getElementById("resultModalGoogleText");
const resultModalFallbackLabel = document.getElementById("resultModalFallbackLabel"); const resultModalFallbackLabel = document.getElementById("resultModalFallbackLabel");
const resultModalOpenExternal = document.getElementById("resultModalOpenExternal"); const resultModalOpenExternal = document.getElementById("resultModalOpenExternal");
const resultModalDownload = document.getElementById("resultModalDownload"); const resultModalDownload = document.getElementById("resultModalDownload");
const resultModalSecondaryAction = document.getElementById("resultModalSecondaryAction");
const closeResultModal = document.getElementById("closeResultModal"); const closeResultModal = document.getElementById("closeResultModal");
const resultModalReady = Boolean( const resultModalReady = Boolean(
resultModal && resultModal &&
@@ -69,6 +70,7 @@ const resultModalReady = Boolean(
resultModalFallbackLabel && resultModalFallbackLabel &&
resultModalOpenExternal && resultModalOpenExternal &&
resultModalDownload && resultModalDownload &&
resultModalSecondaryAction &&
closeResultModal, closeResultModal,
); );
@@ -254,18 +256,7 @@ function syncRanges() {
} }
function renderQueryVariants(queries = []) { function renderQueryVariants(queries = []) {
queryVariants.innerHTML = ""; queryVariants.classList.add("hidden");
if (!queries.length) {
queryVariants.classList.add("hidden");
return;
}
for (const item of queries) {
const badge = document.createElement("span");
badge.className = "rounded-full border border-white/10 bg-white/[0.03] px-3 py-1 text-xs uppercase tracking-[0.18em] text-zinc-300";
badge.textContent = item;
queryVariants.appendChild(badge);
}
queryVariants.classList.remove("hidden");
} }
function syncPlatformButtons() { function syncPlatformButtons() {
@@ -493,7 +484,7 @@ function showResultModalGooglePanel(item, message = "") {
resultModalFallbackLabel.textContent = item.source || "Preview Fallback"; resultModalFallbackLabel.textContent = item.source || "Preview Fallback";
resultModalGoogleImage.src = hasUsableThumbnail(item.thumbnailUrl) ? item.thumbnailUrl : PREVIEW_PLACEHOLDER; resultModalGoogleImage.src = hasUsableThumbnail(item.thumbnailUrl) ? item.thumbnailUrl : PREVIEW_PLACEHOLDER;
resultModalGoogleImage.alt = item.title || ""; resultModalGoogleImage.alt = item.title || "";
resultModalGoogleText.textContent = message || item.previewBlockedReason || item.snippet || item.reason || "Preview fallback is being shown."; resultModalGoogleText.textContent = message || item.previewBlockedReason || item.snippet || item.reason || "Open source page or use the primary action.";
setHidden(resultModalGooglePanel, false, "flex"); setHidden(resultModalGooglePanel, false, "flex");
} }
@@ -596,12 +587,17 @@ function openResultModal(item) {
resultModalReason.textContent = summarizeReason(item.reason) || "AI 노트가 없습니다."; resultModalReason.textContent = summarizeReason(item.reason) || "AI 노트가 없습니다.";
resultModalSnippet.textContent = item.snippet || "원본 페이지에서 사용할 수 있는 설명이 없습니다."; resultModalSnippet.textContent = item.snippet || "원본 페이지에서 사용할 수 있는 설명이 없습니다.";
resultModalOpenExternal.href = item.link || "#"; resultModalOpenExternal.href = item.link || "#";
const canDirectDownload = item.source === "Google Video" && item.link; resultModalDownload.classList.toggle("hidden", !item.actionType);
resultModalDownload.classList.toggle("hidden", !canDirectDownload); resultModalDownload.textContent = item.actionLabel || "Open Source";
const showSecondary = Boolean(item.secondaryActionLabel && item.link);
resultModalSecondaryAction.classList.toggle("hidden", !showSecondary);
resultModalSecondaryAction.textContent = item.secondaryActionLabel || "Open Source";
resetResultModalMedia(); resetResultModalMedia();
const embedURL = buildResultModalEmbedURL(item); const embedURL = buildResultModalEmbedURL(item);
const fallbackReason = item.previewBlockedReason || "Embedded view was unavailable, switched to fallback preview."; const fallbackReason = item.previewBlockedReason || "Embedded view was unavailable, switched to fallback preview.";
if (item.mediaMode === "embed" && embedURL && embedURL !== "about:blank") { if (item.source === "Google Video" && item.mediaMode === "thumbnail") {
showResultModalGooglePanel(item, item.snippet || "Open source page or download directly.");
} else if (item.mediaMode === "embed" && embedURL && embedURL !== "about:blank") {
showResultModalFrame(embedURL); showResultModalFrame(embedURL);
const timeout = window.setTimeout(() => { const timeout = window.setTimeout(() => {
logEvent("result:modal:iframe_timeout", { title: item.title, source: item.source, embedURL }); logEvent("result:modal:iframe_timeout", { title: item.title, source: item.source, embedURL });
@@ -782,13 +778,23 @@ if (resultModalReady) {
return; return;
} }
const currentItem = activeResultItem; const currentItem = activeResultItem;
try { if (currentItem.actionType === "download") {
closeResultViewer(); try {
await prepareDirectDownload(currentItem.link); closeResultViewer();
} catch (error) { await prepareDirectDownload(currentItem.link);
downloadResult.textContent = error.message; } catch (error) {
logEvent("download:preview:error", { message: error.message, data: error.data || null, source: currentItem?.source || "" }); downloadResult.textContent = error.message;
logEvent("download:preview:error", { message: error.message, data: error.data || null, source: currentItem?.source || "" });
}
return;
} }
window.open(currentItem.link, "_blank", "noopener,noreferrer");
});
resultModalSecondaryAction.addEventListener("click", () => {
if (!activeResultItem?.link) {
return;
}
window.open(activeResultItem.link, "_blank", "noopener,noreferrer");
}); });
} }
previewModal.addEventListener("click", (event) => { previewModal.addEventListener("click", (event) => {
+15 -8
View File
@@ -46,7 +46,7 @@
<button class="rounded-2xl border border-white bg-white px-7 py-4 text-base font-medium text-black transition hover:bg-zinc-200">AI Search</button> <button class="rounded-2xl border border-white bg-white px-7 py-4 text-base font-medium text-black transition hover:bg-zinc-200">AI Search</button>
</form> </form>
<div id="searchWarning" class="mt-3 hidden rounded-2xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-200"></div> <div id="searchWarning" class="mt-3 hidden rounded-2xl border border-amber-500/30 bg-amber-500/10 px-4 py-3 text-sm text-amber-200"></div>
<div id="queryVariants" class="mt-3 hidden flex-wrap gap-2"></div> <div id="queryVariants" class="hidden"></div>
<div id="searchResults" class="mt-6 grid gap-5 sm:grid-cols-2 xl:grid-cols-3"></div> <div id="searchResults" class="mt-6 grid gap-5 sm:grid-cols-2 xl:grid-cols-3"></div>
</article> </article>
@@ -184,13 +184,20 @@
<p class="text-xs uppercase tracking-[0.25em] text-zinc-500">AI Note</p> <p class="text-xs uppercase tracking-[0.25em] text-zinc-500">AI Note</p>
<p id="resultModalReason" class="mt-3 whitespace-pre-wrap text-sm leading-7 text-zinc-200"></p> <p id="resultModalReason" class="mt-3 whitespace-pre-wrap text-sm leading-7 text-zinc-200"></p>
</div> </div>
<div class="space-y-4 rounded-2xl border border-white/10 bg-white/[0.03] p-5"> <div class="flex min-h-[260px] flex-col rounded-2xl border border-white/10 bg-white/[0.03] p-5">
<button id="resultModalDownload" type="button" class="hidden w-full rounded-2xl border border-white bg-white px-4 py-3 text-sm font-medium text-black transition hover:bg-zinc-200"> <div class="mb-4 flex flex-col gap-3">
Direct Download <button id="resultModalDownload" type="button" class="hidden w-full rounded-2xl border border-white bg-white px-4 py-3 text-sm font-medium text-black transition hover:bg-zinc-200">
</button> Primary Action
<div> </button>
<button id="resultModalSecondaryAction" type="button" class="hidden w-full rounded-2xl border border-white/10 px-4 py-3 text-sm font-medium text-zinc-100 transition hover:border-white/30">
Secondary Action
</button>
</div>
<div class="flex min-h-0 flex-1 flex-col">
<p class="text-xs uppercase tracking-[0.25em] text-zinc-500">Source Summary</p> <p class="text-xs uppercase tracking-[0.25em] text-zinc-500">Source Summary</p>
<p id="resultModalSnippet" class="mt-3 text-sm leading-7 text-zinc-300"></p> <div class="result-summary-scroll mt-3 min-h-0 flex-1 overflow-y-auto pr-2">
<p id="resultModalSnippet" class="text-sm leading-7 text-zinc-300"></p>
</div>
</div> </div>
</div> </div>
</div> </div>
@@ -216,6 +223,6 @@
</button> </button>
</template> </template>
<script src="/app.js?v=20260316h" defer></script> <script src="/app.js?v=20260316i" defer></script>
</body> </body>
</html> </html>
+9
View File
@@ -41,6 +41,15 @@ body {
border-radius: 9999px; border-radius: 9999px;
} }
.result-summary-scroll::-webkit-scrollbar {
width: 10px;
}
.result-summary-scroll::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.16);
border-radius: 9999px;
}
.debug-entry { .debug-entry {
border-bottom: 1px solid rgba(255, 255, 255, 0.06); border-bottom: 1px solid rgba(255, 255, 255, 0.06);
padding: 10px 8px; padding: 10px 8px;