Add inline media preview inside center prompt input card
Browse files- Visual inputs (images/videos) now display directly inside the input box
- Preview shows between task badge and textarea with 220px max-height
- Remove button (X) overlaid on preview to clear attachment
- Synced with file uploads, example selections, and clearSelectedFile
- Auto-hidden in output mode for clean layout
- index.html +113 -2
index.html
CHANGED
|
@@ -299,6 +299,10 @@
|
|
| 299 |
display: none;
|
| 300 |
}
|
| 301 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 302 |
/* Hide branding when output is showing */
|
| 303 |
.viewport-bottom.output-hidden {
|
| 304 |
opacity: 0;
|
|
@@ -355,6 +359,67 @@
|
|
| 355 |
width: 100%;
|
| 356 |
}
|
| 357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 358 |
.center-prompt-body textarea.prompt-textarea {
|
| 359 |
width: 100%;
|
| 360 |
height: 44px;
|
|
@@ -1497,6 +1562,15 @@
|
|
| 1497 |
<span class="active-task-pill" id="center-task-badge">Text to Video</span>
|
| 1498 |
</div>
|
| 1499 |
<div class="center-prompt-body">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1500 |
<textarea class="prompt-textarea" id="prompt-input" placeholder="Describe what you want to generate..."></textarea>
|
| 1501 |
</div>
|
| 1502 |
<div class="center-prompt-footer">
|
|
@@ -2066,6 +2140,36 @@
|
|
| 2066 |
}
|
| 2067 |
}
|
| 2068 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2069 |
// --- Handle Uploaded Files locally ---
|
| 2070 |
function handleSelectedFile(file) {
|
| 2071 |
if (!file) return;
|
|
@@ -2078,14 +2182,16 @@
|
|
| 2078 |
// Build visual thumbnail preview
|
| 2079 |
previewMediaWrapper.innerHTML = "";
|
| 2080 |
const fileType = selectedFile.type;
|
|
|
|
| 2081 |
|
| 2082 |
if (fileType.startsWith("image/")) {
|
| 2083 |
const img = document.createElement("img");
|
| 2084 |
-
img.src =
|
| 2085 |
previewMediaWrapper.appendChild(img);
|
|
|
|
| 2086 |
} else if (fileType.startsWith("video/")) {
|
| 2087 |
const video = document.createElement("video");
|
| 2088 |
-
video.src =
|
| 2089 |
video.muted = true;
|
| 2090 |
video.playsInline = true;
|
| 2091 |
previewMediaWrapper.appendChild(video);
|
|
@@ -2094,12 +2200,14 @@
|
|
| 2094 |
video.addEventListener("loadeddata", () => {
|
| 2095 |
video.currentTime = 0.5;
|
| 2096 |
});
|
|
|
|
| 2097 |
} else {
|
| 2098 |
const docIcon = document.createElement("div");
|
| 2099 |
docIcon.style.color = "var(--text-secondary)";
|
| 2100 |
docIcon.innerHTML = '<i data-lucide="file"></i>';
|
| 2101 |
previewMediaWrapper.appendChild(docIcon);
|
| 2102 |
lucide.createIcons();
|
|
|
|
| 2103 |
}
|
| 2104 |
|
| 2105 |
dragDropZone.style.display = "none";
|
|
@@ -2112,6 +2220,7 @@
|
|
| 2112 |
uploadedFileReference = null;
|
| 2113 |
fileSelector.value = "";
|
| 2114 |
filePreviewCard.style.display = "none";
|
|
|
|
| 2115 |
|
| 2116 |
const isEdit = activeTask === "image_edit" || activeTask === "video_edit";
|
| 2117 |
const isUnderstanding = activeTask === "x2t_video" || activeTask === "x2t_image";
|
|
@@ -2170,6 +2279,7 @@
|
|
| 2170 |
filePreviewCard.style.display = "flex";
|
| 2171 |
|
| 2172 |
uploadedFileReference = hasVideo;
|
|
|
|
| 2173 |
} else if (hasImage && (activeTask === "image_edit" || activeTask === "x2t_image")) {
|
| 2174 |
previewFilename.textContent = hasImage.split("/").pop();
|
| 2175 |
previewFilesize.textContent = "Example Asset";
|
|
@@ -2183,6 +2293,7 @@
|
|
| 2183 |
filePreviewCard.style.display = "flex";
|
| 2184 |
|
| 2185 |
uploadedFileReference = hasImage;
|
|
|
|
| 2186 |
}
|
| 2187 |
|
| 2188 |
// Trigger reset of viewer output
|
|
|
|
| 299 |
display: none;
|
| 300 |
}
|
| 301 |
|
| 302 |
+
.viewport-center-trigger.output-mode .center-inline-preview {
|
| 303 |
+
display: none;
|
| 304 |
+
}
|
| 305 |
+
|
| 306 |
/* Hide branding when output is showing */
|
| 307 |
.viewport-bottom.output-hidden {
|
| 308 |
opacity: 0;
|
|
|
|
| 359 |
width: 100%;
|
| 360 |
}
|
| 361 |
|
| 362 |
+
/* Inline media attachment preview inside center prompt card */
|
| 363 |
+
.center-inline-preview {
|
| 364 |
+
display: none;
|
| 365 |
+
width: 100%;
|
| 366 |
+
border-radius: 10px;
|
| 367 |
+
overflow: hidden;
|
| 368 |
+
background: rgba(0, 0, 0, 0.25);
|
| 369 |
+
border: 1px solid rgba(255, 255, 255, 0.08);
|
| 370 |
+
position: relative;
|
| 371 |
+
margin-bottom: 6px;
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
.center-inline-preview.visible {
|
| 375 |
+
display: block;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
.center-inline-preview-media {
|
| 379 |
+
width: 100%;
|
| 380 |
+
max-height: 220px;
|
| 381 |
+
display: flex;
|
| 382 |
+
align-items: center;
|
| 383 |
+
justify-content: center;
|
| 384 |
+
overflow: hidden;
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
.center-inline-preview-media img,
|
| 388 |
+
.center-inline-preview-media video {
|
| 389 |
+
width: 100%;
|
| 390 |
+
max-height: 220px;
|
| 391 |
+
object-fit: contain;
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
.center-inline-preview-remove {
|
| 395 |
+
position: absolute;
|
| 396 |
+
top: 8px;
|
| 397 |
+
right: 8px;
|
| 398 |
+
width: 26px;
|
| 399 |
+
height: 26px;
|
| 400 |
+
border-radius: 50%;
|
| 401 |
+
background: rgba(0, 0, 0, 0.6);
|
| 402 |
+
border: 1px solid rgba(255, 255, 255, 0.15);
|
| 403 |
+
color: #fff;
|
| 404 |
+
display: flex;
|
| 405 |
+
align-items: center;
|
| 406 |
+
justify-content: center;
|
| 407 |
+
cursor: pointer;
|
| 408 |
+
transition: var(--transition-fast);
|
| 409 |
+
backdrop-filter: blur(8px);
|
| 410 |
+
-webkit-backdrop-filter: blur(8px);
|
| 411 |
+
}
|
| 412 |
+
|
| 413 |
+
.center-inline-preview-remove:hover {
|
| 414 |
+
background: rgba(239, 68, 68, 0.7);
|
| 415 |
+
border-color: rgba(239, 68, 68, 0.5);
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
.center-inline-preview-remove i {
|
| 419 |
+
width: 13px;
|
| 420 |
+
height: 13px;
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
.center-prompt-body textarea.prompt-textarea {
|
| 424 |
width: 100%;
|
| 425 |
height: 44px;
|
|
|
|
| 1562 |
<span class="active-task-pill" id="center-task-badge">Text to Video</span>
|
| 1563 |
</div>
|
| 1564 |
<div class="center-prompt-body">
|
| 1565 |
+
<!-- Inline media attachment preview -->
|
| 1566 |
+
<div class="center-inline-preview" id="center-inline-preview">
|
| 1567 |
+
<div class="center-inline-preview-media" id="center-inline-preview-media">
|
| 1568 |
+
<!-- JS injects img/video here -->
|
| 1569 |
+
</div>
|
| 1570 |
+
<button class="center-inline-preview-remove" id="center-inline-preview-remove" title="Remove attachment">
|
| 1571 |
+
<i data-lucide="x"></i>
|
| 1572 |
+
</button>
|
| 1573 |
+
</div>
|
| 1574 |
<textarea class="prompt-textarea" id="prompt-input" placeholder="Describe what you want to generate..."></textarea>
|
| 1575 |
</div>
|
| 1576 |
<div class="center-prompt-footer">
|
|
|
|
| 2140 |
}
|
| 2141 |
}
|
| 2142 |
|
| 2143 |
+
// --- Inline preview element caches ---
|
| 2144 |
+
const centerInlinePreview = document.getElementById("center-inline-preview");
|
| 2145 |
+
const centerInlinePreviewMedia = document.getElementById("center-inline-preview-media");
|
| 2146 |
+
const centerInlinePreviewRemove = document.getElementById("center-inline-preview-remove");
|
| 2147 |
+
|
| 2148 |
+
// Bind inline preview remove button
|
| 2149 |
+
centerInlinePreviewRemove.addEventListener("click", () => clearSelectedFile());
|
| 2150 |
+
|
| 2151 |
+
// --- Sync inline preview inside center prompt card ---
|
| 2152 |
+
function updateCenterInlinePreview(src, type) {
|
| 2153 |
+
centerInlinePreviewMedia.innerHTML = "";
|
| 2154 |
+
if (!src) {
|
| 2155 |
+
centerInlinePreview.classList.remove("visible");
|
| 2156 |
+
return;
|
| 2157 |
+
}
|
| 2158 |
+
if (type === "video") {
|
| 2159 |
+
const video = document.createElement("video");
|
| 2160 |
+
video.src = src;
|
| 2161 |
+
video.muted = true;
|
| 2162 |
+
video.playsInline = true;
|
| 2163 |
+
video.addEventListener("loadeddata", () => { video.currentTime = 0.5; });
|
| 2164 |
+
centerInlinePreviewMedia.appendChild(video);
|
| 2165 |
+
} else {
|
| 2166 |
+
const img = document.createElement("img");
|
| 2167 |
+
img.src = src;
|
| 2168 |
+
centerInlinePreviewMedia.appendChild(img);
|
| 2169 |
+
}
|
| 2170 |
+
centerInlinePreview.classList.add("visible");
|
| 2171 |
+
}
|
| 2172 |
+
|
| 2173 |
// --- Handle Uploaded Files locally ---
|
| 2174 |
function handleSelectedFile(file) {
|
| 2175 |
if (!file) return;
|
|
|
|
| 2182 |
// Build visual thumbnail preview
|
| 2183 |
previewMediaWrapper.innerHTML = "";
|
| 2184 |
const fileType = selectedFile.type;
|
| 2185 |
+
const objectUrl = URL.createObjectURL(selectedFile);
|
| 2186 |
|
| 2187 |
if (fileType.startsWith("image/")) {
|
| 2188 |
const img = document.createElement("img");
|
| 2189 |
+
img.src = objectUrl;
|
| 2190 |
previewMediaWrapper.appendChild(img);
|
| 2191 |
+
updateCenterInlinePreview(objectUrl, "image");
|
| 2192 |
} else if (fileType.startsWith("video/")) {
|
| 2193 |
const video = document.createElement("video");
|
| 2194 |
+
video.src = objectUrl;
|
| 2195 |
video.muted = true;
|
| 2196 |
video.playsInline = true;
|
| 2197 |
previewMediaWrapper.appendChild(video);
|
|
|
|
| 2200 |
video.addEventListener("loadeddata", () => {
|
| 2201 |
video.currentTime = 0.5;
|
| 2202 |
});
|
| 2203 |
+
updateCenterInlinePreview(objectUrl, "video");
|
| 2204 |
} else {
|
| 2205 |
const docIcon = document.createElement("div");
|
| 2206 |
docIcon.style.color = "var(--text-secondary)";
|
| 2207 |
docIcon.innerHTML = '<i data-lucide="file"></i>';
|
| 2208 |
previewMediaWrapper.appendChild(docIcon);
|
| 2209 |
lucide.createIcons();
|
| 2210 |
+
updateCenterInlinePreview(null, null);
|
| 2211 |
}
|
| 2212 |
|
| 2213 |
dragDropZone.style.display = "none";
|
|
|
|
| 2220 |
uploadedFileReference = null;
|
| 2221 |
fileSelector.value = "";
|
| 2222 |
filePreviewCard.style.display = "none";
|
| 2223 |
+
updateCenterInlinePreview(null, null);
|
| 2224 |
|
| 2225 |
const isEdit = activeTask === "image_edit" || activeTask === "video_edit";
|
| 2226 |
const isUnderstanding = activeTask === "x2t_video" || activeTask === "x2t_image";
|
|
|
|
| 2279 |
filePreviewCard.style.display = "flex";
|
| 2280 |
|
| 2281 |
uploadedFileReference = hasVideo;
|
| 2282 |
+
updateCenterInlinePreview(hasVideo, "video");
|
| 2283 |
} else if (hasImage && (activeTask === "image_edit" || activeTask === "x2t_image")) {
|
| 2284 |
previewFilename.textContent = hasImage.split("/").pop();
|
| 2285 |
previewFilesize.textContent = "Example Asset";
|
|
|
|
| 2293 |
filePreviewCard.style.display = "flex";
|
| 2294 |
|
| 2295 |
uploadedFileReference = hasImage;
|
| 2296 |
+
updateCenterInlinePreview(hasImage, "image");
|
| 2297 |
}
|
| 2298 |
|
| 2299 |
// Trigger reset of viewer output
|