xiaolongmr commited on
Commit ·
b254df8
1
Parent(s): 9b99184
Revert "Switch image previews to loaded URLs"
Browse filesThis reverts commit 9b99184ceea9451f3a8ab1f877ae6e67b0d83a26.
web/src/app/image/components/image-results.tsx
CHANGED
|
@@ -24,7 +24,6 @@ type ImageResultsProps = {
|
|
| 24 |
onReuseTurnConfig: (conversationId: string, turnId: string) => void | Promise<void>;
|
| 25 |
onRegenerateTurn: (conversationId: string, turnId: string) => void | Promise<void>;
|
| 26 |
onRetryImage: (conversationId: string, turnId: string, imageId: string) => void | Promise<void>;
|
| 27 |
-
onImageUrlReady: (conversationId: string, turnId: string, imageId: string) => void | Promise<void>;
|
| 28 |
formatConversationTime: (value: string) => string;
|
| 29 |
};
|
| 30 |
|
|
@@ -65,7 +64,6 @@ export function ImageResults({
|
|
| 65 |
onReuseTurnConfig,
|
| 66 |
onRegenerateTurn,
|
| 67 |
onRetryImage,
|
| 68 |
-
onImageUrlReady,
|
| 69 |
formatConversationTime,
|
| 70 |
}: ImageResultsProps) {
|
| 71 |
const [imageDimensions, setImageDimensions] = useState<Record<string, string>>({});
|
|
@@ -83,6 +81,42 @@ export function ImageResults({
|
|
| 83 |
return () => window.clearInterval(timer);
|
| 84 |
}, [hasPendingTurns]);
|
| 85 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
const updateImageDimensions = (id: string, width: number, height: number) => {
|
| 87 |
const dimensions = formatImageDimensions(width, height);
|
| 88 |
setImageDimensions((current) => {
|
|
@@ -93,11 +127,6 @@ export function ImageResults({
|
|
| 93 |
});
|
| 94 |
};
|
| 95 |
|
| 96 |
-
const markImageUrlReady = (conversationId: string, turnId: string, imageId: string) => {
|
| 97 |
-
setUrlReadyImageIds((current) => (current[imageId] ? current : { ...current, [imageId]: true }));
|
| 98 |
-
void onImageUrlReady(conversationId, turnId, imageId);
|
| 99 |
-
};
|
| 100 |
-
|
| 101 |
if (!selectedConversation) {
|
| 102 |
return (
|
| 103 |
<div className="flex h-full min-h-[260px] items-center justify-center text-center sm:min-h-[420px]">
|
|
@@ -229,23 +258,13 @@ export function ImageResults({
|
|
| 229 |
const currentIndex = successfulTurnImages.findIndex((item) => item.id === image.id);
|
| 230 |
const sizeLabel = image.b64_json ? formatBase64ImageSize(image.b64_json) : "";
|
| 231 |
const dimensions = imageDimensions[image.id];
|
| 232 |
-
const urlSrc = normalizeImageUrl(image.url || "");
|
| 233 |
const imageMeta = [sizeLabel, dimensions].filter(Boolean).join(" · ");
|
| 234 |
|
| 235 |
return (
|
| 236 |
<div
|
| 237 |
key={image.id}
|
| 238 |
-
className="
|
| 239 |
>
|
| 240 |
-
{image.b64_json && urlSrc && !urlReadyImageIds[image.id] ? (
|
| 241 |
-
<img
|
| 242 |
-
src={urlSrc}
|
| 243 |
-
alt=""
|
| 244 |
-
aria-hidden="true"
|
| 245 |
-
className="pointer-events-none absolute size-px opacity-0"
|
| 246 |
-
onLoad={() => markImageUrlReady(selectedConversation.id, turn.id, image.id)}
|
| 247 |
-
/>
|
| 248 |
-
) : null}
|
| 249 |
<button
|
| 250 |
type="button"
|
| 251 |
onClick={() => onOpenLightbox(successfulTurnImages, currentIndex)}
|
|
|
|
| 24 |
onReuseTurnConfig: (conversationId: string, turnId: string) => void | Promise<void>;
|
| 25 |
onRegenerateTurn: (conversationId: string, turnId: string) => void | Promise<void>;
|
| 26 |
onRetryImage: (conversationId: string, turnId: string, imageId: string) => void | Promise<void>;
|
|
|
|
| 27 |
formatConversationTime: (value: string) => string;
|
| 28 |
};
|
| 29 |
|
|
|
|
| 64 |
onReuseTurnConfig,
|
| 65 |
onRegenerateTurn,
|
| 66 |
onRetryImage,
|
|
|
|
| 67 |
formatConversationTime,
|
| 68 |
}: ImageResultsProps) {
|
| 69 |
const [imageDimensions, setImageDimensions] = useState<Record<string, string>>({});
|
|
|
|
| 81 |
return () => window.clearInterval(timer);
|
| 82 |
}, [hasPendingTurns]);
|
| 83 |
|
| 84 |
+
useEffect(() => {
|
| 85 |
+
const pendingImages =
|
| 86 |
+
selectedConversation?.turns.flatMap((turn) =>
|
| 87 |
+
turn.images.flatMap((image) => {
|
| 88 |
+
const url = normalizeImageUrl(image.url || "");
|
| 89 |
+
if (image.status !== "success" || !image.b64_json || !url || urlReadyImageIds[image.id]) {
|
| 90 |
+
return [];
|
| 91 |
+
}
|
| 92 |
+
return [{ id: image.id, url }];
|
| 93 |
+
}),
|
| 94 |
+
) || [];
|
| 95 |
+
if (pendingImages.length === 0) {
|
| 96 |
+
return;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
let cancelled = false;
|
| 100 |
+
const loaders = pendingImages.map(({ id, url }) => {
|
| 101 |
+
const loader = new Image();
|
| 102 |
+
loader.onload = () => {
|
| 103 |
+
if (cancelled) {
|
| 104 |
+
return;
|
| 105 |
+
}
|
| 106 |
+
setUrlReadyImageIds((current) => (current[id] ? current : { ...current, [id]: true }));
|
| 107 |
+
};
|
| 108 |
+
loader.src = url;
|
| 109 |
+
return loader;
|
| 110 |
+
});
|
| 111 |
+
|
| 112 |
+
return () => {
|
| 113 |
+
cancelled = true;
|
| 114 |
+
loaders.forEach((loader) => {
|
| 115 |
+
loader.onload = null;
|
| 116 |
+
});
|
| 117 |
+
};
|
| 118 |
+
}, [selectedConversation, urlReadyImageIds]);
|
| 119 |
+
|
| 120 |
const updateImageDimensions = (id: string, width: number, height: number) => {
|
| 121 |
const dimensions = formatImageDimensions(width, height);
|
| 122 |
setImageDimensions((current) => {
|
|
|
|
| 127 |
});
|
| 128 |
};
|
| 129 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 130 |
if (!selectedConversation) {
|
| 131 |
return (
|
| 132 |
<div className="flex h-full min-h-[260px] items-center justify-center text-center sm:min-h-[420px]">
|
|
|
|
| 258 |
const currentIndex = successfulTurnImages.findIndex((item) => item.id === image.id);
|
| 259 |
const sizeLabel = image.b64_json ? formatBase64ImageSize(image.b64_json) : "";
|
| 260 |
const dimensions = imageDimensions[image.id];
|
|
|
|
| 261 |
const imageMeta = [sizeLabel, dimensions].filter(Boolean).join(" · ");
|
| 262 |
|
| 263 |
return (
|
| 264 |
<div
|
| 265 |
key={image.id}
|
| 266 |
+
className="break-inside-avoid"
|
| 267 |
>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 268 |
<button
|
| 269 |
type="button"
|
| 270 |
onClick={() => onOpenLightbox(successfulTurnImages, currentIndex)}
|
web/src/app/image/page.tsx
CHANGED
|
@@ -759,39 +759,6 @@ function ImagePageContent({ session }: { session: StoredAuthSession }) {
|
|
| 759 |
clearComposerInputs();
|
| 760 |
}, [clearComposerInputs]);
|
| 761 |
|
| 762 |
-
const handleImageUrlReady = useCallback(
|
| 763 |
-
async (conversationId: string, turnId: string, imageId: string) => {
|
| 764 |
-
const snapshot = conversationsRef.current.find((item) => item.id === conversationId);
|
| 765 |
-
if (!snapshot) {
|
| 766 |
-
return;
|
| 767 |
-
}
|
| 768 |
-
|
| 769 |
-
await updateConversation(conversationId, (current) => {
|
| 770 |
-
const conversation = current ?? snapshot;
|
| 771 |
-
let changed = false;
|
| 772 |
-
const turns = conversation.turns.map((turn) => {
|
| 773 |
-
if (turn.id !== turnId) {
|
| 774 |
-
return turn;
|
| 775 |
-
}
|
| 776 |
-
const images = turn.images.map((image) => {
|
| 777 |
-
if (image.id !== imageId || !image.b64_json || !image.url) {
|
| 778 |
-
return image;
|
| 779 |
-
}
|
| 780 |
-
changed = true;
|
| 781 |
-
return {
|
| 782 |
-
...image,
|
| 783 |
-
b64_json: undefined,
|
| 784 |
-
};
|
| 785 |
-
});
|
| 786 |
-
return changed ? { ...turn, images } : turn;
|
| 787 |
-
});
|
| 788 |
-
|
| 789 |
-
return changed ? { ...conversation, turns } : conversation;
|
| 790 |
-
});
|
| 791 |
-
},
|
| 792 |
-
[updateConversation],
|
| 793 |
-
);
|
| 794 |
-
|
| 795 |
const handleCreateDraft = () => {
|
| 796 |
setSelectedConversationId(null);
|
| 797 |
resetComposer();
|
|
@@ -1571,7 +1538,6 @@ function ImagePageContent({ session }: { session: StoredAuthSession }) {
|
|
| 1571 |
onReuseTurnConfig={handleReuseTurnConfig}
|
| 1572 |
onRegenerateTurn={handleRegenerateTurn}
|
| 1573 |
onRetryImage={handleRetryImage}
|
| 1574 |
-
onImageUrlReady={handleImageUrlReady}
|
| 1575 |
formatConversationTime={formatConversationTime}
|
| 1576 |
/>
|
| 1577 |
</div>
|
|
|
|
| 759 |
clearComposerInputs();
|
| 760 |
}, [clearComposerInputs]);
|
| 761 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 762 |
const handleCreateDraft = () => {
|
| 763 |
setSelectedConversationId(null);
|
| 764 |
resetComposer();
|
|
|
|
| 1538 |
onReuseTurnConfig={handleReuseTurnConfig}
|
| 1539 |
onRegenerateTurn={handleRegenerateTurn}
|
| 1540 |
onRetryImage={handleRetryImage}
|
|
|
|
| 1541 |
formatConversationTime={formatConversationTime}
|
| 1542 |
/>
|
| 1543 |
</div>
|