Files
ai-media-hub/frontend/index.html
T
GHStaK e79d15de2e
build-push / docker (push) Successful in 4m32s
Simplify GIPHY result presentation
2026-03-24 16:36:00 +09:00

273 lines
19 KiB
HTML

<!DOCTYPE html>
<html lang="ko" class="h-full bg-zinc-950">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>AI Media Hub</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.20/dist/hls.min.js"></script>
<link rel="stylesheet" href="/style.css" />
</head>
<body class="min-h-full bg-zinc-950 text-zinc-100 selection:bg-white selection:text-black">
<main class="mx-auto flex min-h-screen max-w-[1560px] flex-col gap-8 px-5 py-8 lg:px-10">
<header class="rounded-3xl border border-white/10 bg-white/5 p-8 backdrop-blur">
<div class="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div>
<p class="text-xs uppercase tracking-[0.4em] text-zinc-500">AI Media Asset Ingest Hub</p>
<h1 class="mt-3 text-4xl font-semibold tracking-tight text-white">SAVE THE NURSE AI Search</h1>
</div>
<div class="w-full max-w-md">
<div class="mb-2 flex items-center justify-between text-xs uppercase tracking-[0.3em] text-zinc-500">
<span>Realtime Status</span>
<span id="statusLabel">Idle</span>
</div>
<div class="h-3 overflow-hidden rounded-full bg-white/10">
<div id="statusBar" class="h-full w-0 rounded-full bg-white transition-all duration-300"></div>
</div>
</div>
</div>
</header>
<section class="grid gap-8 lg:grid-cols-[1.3fr_0.95fr]">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-7">
<div class="mb-4 flex items-center justify-between">
<div>
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Zone A</p>
<h2 id="searchModeTitle" class="text-2xl font-semibold text-white">AI Smart Discovery</h2>
</div>
</div>
<div class="mb-4 flex flex-wrap items-center gap-3">
<div class="inline-flex rounded-full border border-white/10 bg-black/30 p-1">
<button data-media-type-toggle="video" class="media-type-toggle rounded-full bg-white px-4 py-2 text-sm font-medium text-black transition">Video</button>
<button data-media-type-toggle="image" class="media-type-toggle rounded-full px-4 py-2 text-sm font-medium text-zinc-300 transition">Image</button>
</div>
<p id="searchModeHint" class="text-sm text-zinc-400">비디오 검색 모드입니다. 실제 검색 API와 연결되어 있습니다.</p>
</div>
<div class="mb-4 flex flex-wrap gap-3">
<button data-platform-toggle="envato" class="platform-toggle rounded-full border border-white bg-white px-4 py-2 text-sm font-medium text-black">Envato</button>
<button data-platform-toggle="artgrid" class="platform-toggle rounded-full border border-white bg-white px-4 py-2 text-sm font-medium text-black">Artgrid</button>
<button data-platform-toggle="google video" class="platform-toggle rounded-full border border-white bg-white px-4 py-2 text-sm font-medium text-black">Google Video</button>
</div>
<form id="searchForm" class="flex flex-col gap-3 md:flex-row">
<input id="searchQuery" type="text" placeholder="한글 검색어를 입력하세요" class="flex-1 rounded-2xl border border-white/10 bg-black/40 px-5 py-4 text-base text-white outline-none ring-0 placeholder:text-zinc-500" />
<button id="searchSubmitButton" 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>
<div id="imageSearchSandbox" class="mt-4 hidden rounded-3xl border border-white/10 bg-[linear-gradient(135deg,rgba(250,204,21,0.07),rgba(59,130,246,0.08))] p-4">
<div class="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div class="space-y-2">
<div class="flex flex-wrap items-center gap-3">
<p class="text-xs uppercase tracking-[0.25em] text-zinc-500">GIPHY Image Search</p>
<span class="rounded-full border border-white/10 bg-black/30 px-3 py-1 text-[11px] uppercase tracking-[0.24em] text-zinc-300">Powered by GIPHY</span>
</div>
<p class="max-w-2xl text-sm leading-6 text-zinc-300">
어떤 언어로 검색해도 GIPHY 이미지/GIF 검색 결과를 최대 100개까지 내부 스크롤 패널에서 바로 탐색할 수 있습니다.
</p>
</div>
<div class="flex flex-wrap gap-2">
<button type="button" class="image-prompt-chip rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-200" data-image-prompt="cinematic city night">Cinematic City</button>
<button type="button" class="image-prompt-chip rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-200" data-image-prompt="vintage fashion portrait">Vintage Portrait</button>
<button type="button" class="image-prompt-chip rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-200" data-image-prompt="minimal product mockup">Product Mockup</button>
</div>
</div>
</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="hidden"></div>
<div id="searchResultsViewport" class="mt-6">
<div id="searchResults" class="grid gap-5 sm:grid-cols-2 xl:grid-cols-3"></div>
</div>
</article>
<div class="grid gap-8">
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-7">
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Zone B</p>
<h2 class="text-2xl font-semibold text-white">Smart Ingest Dropzone</h2>
<label id="dropzone" class="mt-4 flex min-h-64 cursor-pointer flex-col items-center justify-center rounded-3xl border border-dashed border-white/20 bg-black/30 p-6 text-center transition hover:border-white/50 hover:bg-white/[0.05]">
<input id="fileInput" type="file" class="hidden" />
<span class="text-2xl font-medium text-white">Drop file here</span>
<span class="mt-2 text-base text-zinc-400">or click to upload into /app/downloads</span>
</label>
<p id="uploadResult" class="mt-3 text-sm text-zinc-400"></p>
</article>
<article class="rounded-3xl border border-white/10 bg-white/[0.03] p-7">
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Zone C</p>
<h2 class="text-2xl font-semibold text-white">Direct Downloader & Crop</h2>
<form id="downloadForm" class="mt-4 space-y-3">
<input id="downloadUrl" type="url" placeholder="https://..." class="w-full rounded-2xl border border-white/10 bg-black/40 px-5 py-4 text-base text-white placeholder:text-zinc-500" />
<button class="w-full rounded-2xl border border-white px-6 py-4 text-base font-medium text-white transition hover:bg-white hover:text-black">Preview & Queue</button>
</form>
<p id="downloadResult" class="mt-3 text-sm text-zinc-400"></p>
</article>
</div>
</section>
</main>
<button id="debugToggle" class="fixed bottom-4 right-4 z-40 rounded-full border border-white/15 bg-black/70 px-4 py-2 text-xs uppercase tracking-[0.25em] text-zinc-300 backdrop-blur">
Logs
</button>
<aside id="debugPanel" class="fixed bottom-4 right-4 z-40 hidden h-[60vh] w-[min(92vw,720px)] overflow-hidden rounded-3xl border border-white/10 bg-zinc-950/95 shadow-2xl backdrop-blur">
<div class="flex items-center justify-between border-b border-white/10 px-4 py-3">
<div>
<p class="text-[11px] uppercase tracking-[0.25em] text-zinc-500">Developer Logs</p>
<p id="debugSummary" class="text-sm text-zinc-300">No events yet</p>
</div>
<div class="flex items-center gap-2">
<button id="downloadLogs" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Download .log</button>
<button id="clearLogs" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Clear</button>
<button id="closeDebugPanel" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Close</button>
</div>
</div>
<div id="debugLogList" class="h-[calc(60vh-78px)] overflow-auto px-3 py-3 font-mono text-xs text-zinc-200"></div>
</aside>
<div id="previewModal" class="fixed inset-0 z-50 hidden items-center justify-center bg-black/80 px-4">
<div class="w-full max-w-5xl rounded-3xl border border-white/10 bg-zinc-950 p-5 shadow-2xl">
<div class="flex items-start justify-between gap-4">
<div>
<p class="text-xs uppercase tracking-[0.3em] text-zinc-500">Download Preview</p>
<h3 id="previewTitle" class="mt-2 text-xl font-semibold text-white"></h3>
</div>
<button id="closePreviewModal" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Close</button>
</div>
<div class="mt-5 flex flex-col gap-5">
<div id="previewMediaFrame" class="min-w-0 flex min-h-[320px] items-center justify-center overflow-hidden rounded-3xl border border-white/10 bg-black/30 p-2">
<video id="previewVideo" class="hidden max-h-[60vh] w-full bg-black object-contain" controls playsinline></video>
<img id="previewThumbnail" class="max-h-[60vh] w-full object-contain" alt="" />
</div>
<div class="min-w-0 grid gap-4 lg:grid-cols-2">
<div class="rounded-2xl border border-white/10 bg-white/[0.03] p-4">
<div class="flex items-center justify-between text-sm text-zinc-400">
<span>Detected duration</span>
<span id="previewDuration"></span>
</div>
</div>
<div class="rounded-2xl border border-white/10 bg-white/[0.03] p-4">
<div class="mb-3 flex items-center justify-between text-sm text-zinc-400">
<span>Crop Range</span>
<span id="rangeSummary">00:00:00 - 00:00:00</span>
</div>
<div class="space-y-3">
<div class="dual-slider relative h-10">
<div class="dual-slider__track absolute left-0 right-0 top-1/2 h-1 -translate-y-1/2 rounded-full bg-white/15"></div>
<div id="rangeFill" class="dual-slider__fill absolute top-1/2 h-1 -translate-y-1/2 rounded-full bg-white"></div>
<button id="startThumb" type="button" class="dual-slider__thumb absolute top-1/2 h-5 w-5 -translate-y-1/2 rounded-full border-2 border-zinc-950 bg-white"></button>
<button id="endThumb" type="button" class="dual-slider__thumb absolute top-1/2 h-5 w-5 -translate-y-1/2 rounded-full border-2 border-zinc-950 bg-white"></button>
</div>
<div class="flex items-center justify-between text-xs uppercase tracking-[0.2em] text-zinc-500">
<span id="startLabel">Start 00:00:00</span>
<span id="endLabel">End 00:00:00</span>
</div>
</div>
<div class="mt-3 flex gap-3">
<button id="setStartFromPreview" type="button" class="flex-1 rounded-2xl border border-white/10 px-4 py-3 text-sm text-zinc-200 transition hover:border-white/30">Set Start</button>
<button id="setEndFromPreview" type="button" class="flex-1 rounded-2xl border border-white/10 px-4 py-3 text-sm text-zinc-200 transition hover:border-white/30">Set End</button>
</div>
</div>
<label class="block space-y-2">
<span class="text-sm text-zinc-400">Quality</span>
<select id="qualitySelect" class="w-full rounded-2xl border border-white/10 bg-black/40 px-4 py-3 text-sm text-white"></select>
</label>
<div class="lg:col-span-2">
<button id="confirmDownload" class="w-full rounded-2xl border border-white bg-white px-5 py-3 text-sm font-medium text-black transition hover:bg-zinc-200">Confirm Download</button>
</div>
</div>
</div>
</div>
</div>
<div id="resultModal" class="fixed inset-0 z-50 hidden items-start justify-center overflow-y-auto bg-black/80 px-2 py-2 sm:px-4 sm:py-4">
<div class="result-modal-shell flex w-full max-w-6xl min-h-0 flex-col overflow-hidden rounded-3xl border border-white/10 bg-zinc-950 shadow-2xl">
<div class="flex items-center justify-between border-b border-white/10 px-4 py-3 sm:px-5 sm:py-4">
<div class="min-w-0">
<p id="resultModalSource" class="text-xs uppercase tracking-[0.25em] text-zinc-500"></p>
<h3 id="resultModalTitle" class="mt-1 truncate text-xl font-semibold text-white"></h3>
</div>
<div class="flex items-center gap-2">
<a id="resultModalOpenExternal" target="_blank" rel="noreferrer" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Open</a>
<button id="closeResultModal" type="button" class="rounded-full border border-white/10 px-3 py-2 text-xs uppercase tracking-[0.2em] text-zinc-300">Close</button>
</div>
</div>
<div class="border-b border-white/10 bg-black/40 p-2 sm:p-3">
<div id="resultModalMediaFrame" class="result-modal-media-frame aspect-video overflow-hidden rounded-2xl border border-white/10 bg-black">
<iframe id="resultModalFrame" class="hidden h-full w-full bg-white" referrerpolicy="no-referrer" allow="autoplay; fullscreen; encrypted-media; picture-in-picture" allowfullscreen></iframe>
<video id="resultModalVideo" class="hidden h-full w-full bg-black object-contain" controls playsinline></video>
<img id="resultModalThumbnail" class="hidden h-full w-full object-contain" alt="" />
<div id="resultModalGooglePanel" class="hidden h-full w-full items-center justify-center bg-[radial-gradient(circle_at_top,#24344a,transparent_55%),linear-gradient(180deg,#0f1724,#05070b)] p-6">
<div class="flex w-full max-w-3xl flex-col gap-5">
<div class="overflow-hidden rounded-2xl border border-white/10 bg-black/40">
<img id="resultModalGoogleImage" class="aspect-video w-full object-cover" alt="" />
</div>
<div class="flex flex-col gap-3 rounded-2xl border border-white/10 bg-white/[0.04] p-5 text-left">
<p id="resultModalFallbackLabel" class="text-xs uppercase tracking-[0.25em] text-zinc-500">Preview Fallback</p>
<p id="resultModalGoogleText" class="text-sm leading-7 text-zinc-200"></p>
</div>
</div>
</div>
</div>
</div>
<div class="result-modal-details grid min-h-0 gap-3 px-3 py-3 sm:gap-4 sm:px-4 sm:py-4 lg:grid-cols-[1.5fr_0.8fr]">
<div class="flex min-h-[180px] min-w-0 flex-col rounded-2xl border border-white/10 bg-white/[0.03] p-4">
<p id="resultModalReasonLabel" class="text-xs uppercase tracking-[0.25em] text-zinc-500">AI Note</p>
<div class="result-panel-scroll mt-3 min-h-0 flex-1 overflow-y-auto pr-2">
<p id="resultModalReason" class="whitespace-pre-wrap text-xs leading-6 text-zinc-200 sm:text-sm"></p>
</div>
</div>
<div class="flex min-h-[200px] min-w-0 flex-col rounded-2xl border border-white/10 bg-white/[0.03] p-4">
<div class="mb-3 flex flex-col gap-2">
<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">
Primary Action
</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 id="resultModalSnippetLabel" class="text-xs uppercase tracking-[0.25em] text-zinc-500">Source Summary</p>
<div class="result-summary-scroll mt-3 min-h-0 flex-1 overflow-y-auto pr-2">
<p id="resultModalSnippet" class="text-xs leading-6 text-zinc-300 sm:text-sm"></p>
</div>
</div>
</div>
</div>
</div>
</div>
<template id="searchCardTemplate">
<button type="button" class="group overflow-hidden rounded-3xl border border-white/10 bg-black/30 text-left transition hover:border-white/30">
<div class="relative aspect-video overflow-hidden bg-zinc-900">
<img class="h-full w-full object-cover transition duration-500 group-hover:scale-105" alt="" />
<video class="preview-hover absolute inset-0 hidden h-full w-full object-cover" muted loop playsinline preload="none"></video>
<div class="media-fallback absolute inset-0 hidden items-center justify-center bg-[radial-gradient(circle_at_top,#2b3342,transparent_60%),linear-gradient(180deg,#111827,#05070b)] p-5 text-center text-xs uppercase tracking-[0.24em] text-zinc-300">
Preview unavailable
</div>
<div class="source-badge preview-overlay absolute bottom-3 left-3 rounded-full bg-white px-3 py-1 text-[11px] font-medium uppercase tracking-[0.2em] text-black"></div>
</div>
<div class="space-y-2 p-5">
<h3 class="line-clamp-2 text-base font-medium text-white"></h3>
<p class="result-snippet line-clamp-2 text-sm text-zinc-300"></p>
<p class="result-reason line-clamp-3 text-xs tracking-[0.02em] text-zinc-500"></p>
</div>
</button>
</template>
<template id="imageCardTemplate">
<button type="button" class="group overflow-hidden rounded-3xl border border-white/10 bg-black/30 text-left transition hover:border-white/30">
<div class="relative aspect-[4/3] overflow-hidden bg-zinc-900">
<img class="h-full w-full object-cover transition duration-500 group-hover:scale-105" alt="" />
<div class="absolute inset-x-0 bottom-0 bg-gradient-to-t from-black/80 via-black/10 to-transparent p-4">
<p class="image-card-tag text-[11px] uppercase tracking-[0.25em] text-zinc-300"></p>
</div>
</div>
<div class="space-y-2 p-5">
<h3 class="image-card-title line-clamp-2 text-base font-medium text-white"></h3>
<p class="image-card-caption line-clamp-3 text-sm text-zinc-300"></p>
<p class="image-card-meta text-[11px] uppercase tracking-[0.22em] text-zinc-500"></p>
</div>
</button>
</template>
<script src="/app.js?v=20260324a" defer></script>
</body>
</html>