use-vibes
Version:
Transform any DOM element into an AI-powered micro-app
125 lines • 6.59 kB
JavaScript
import * as React from 'react';
import { combineClasses, defaultClasses } from '../../utils/style-utils';
import { ImageOverlay } from './overlays/ImageOverlay';
// Component for loading/placeholder state
export function ImgGenDisplayPlaceholder({ className, alt, prompt, progress, error, classes = defaultClasses, }) {
// State to track the visible progress width for animation
const [visibleProgress, setVisibleProgress] = React.useState(0);
// Animate progress bar when component mounts or progress changes
React.useEffect(() => {
// Only start at zero on initial mount, not on every progress update
if (progress === 0) {
setVisibleProgress(0);
}
// Smoothly animate to the actual progress (or minimum 5%)
const timer = setTimeout(() => {
setVisibleProgress(Math.max(5, progress));
}, 20); // Smaller delay for smoother transitions
return () => clearTimeout(timer);
}, [progress]);
// Extract error information from the error object
const parseErrorInfo = (error) => {
const errorMsg = error.message;
let title = 'Image Generation Failed';
let body = errorMsg;
let code = '';
// Try to parse JSON error details if present
if (errorMsg.includes('{')) {
try {
const jsonStart = errorMsg.indexOf('{');
const jsonStr = errorMsg.substring(jsonStart);
const jsonObj = JSON.parse(jsonStr);
// Get error code if it exists
if (errorMsg.match(/\d{3}/)) {
code = errorMsg.match(/\d{3}/)?.[0] || '';
}
// Special handling for moderation blocked errors
if (jsonObj.details?.error?.code === 'moderation_blocked' ||
jsonObj.code === 'moderation_blocked') {
// Include error code in title but avoid duplication
title = code ? `${code} - Failed to generate image` : 'Failed to generate image';
body =
'Your request was rejected as a result of our safety system. Your request may contain content that is not allowed by our safety system.';
return { title, body, code };
}
// Set the title from the main error message
if (jsonObj.error) {
title = jsonObj.error;
}
// Set the body from the detailed error message
if (jsonObj.details?.error?.message) {
body = jsonObj.details.error.message;
}
else if (jsonObj.error?.details?.error?.message) {
body = jsonObj.error.details.error.message;
}
}
catch { }
}
return { title, body, code };
};
// Check if we're displaying an error
if (error) {
return (React.createElement("div", { className: combineClasses('imggen-placeholder', 'imggen-error-container', className, classes.placeholder), style: {
backgroundColor: '#222', // Dark gray background
width: '100%',
height: '100%',
minHeight: '512px', // Standard image height
aspectRatio: '1 / 1', // Square aspect ratio like images
}, "aria-label": alt || 'Error display', role: "img" },
React.createElement("div", { className: combineClasses('imggen-error', classes.error) }, (() => {
const { title, body } = parseErrorInfo(error);
return (React.createElement(React.Fragment, null,
React.createElement("h3", { className: "imggen-error-title", style: { color: '#ff4d4d', margin: '0 0 0.75rem 0' } }, title),
React.createElement("p", { className: "imggen-error-message", style: { color: '#e0e0e0', margin: '0' } }, body)));
})())));
}
// Regular placeholder when no error
return (React.createElement("div", { className: combineClasses('imggen-placeholder', className, classes.placeholder), "aria-label": alt || prompt || 'Image placeholder', role: "img", style: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
textAlign: 'center',
minHeight: '200px',
position: 'relative',
backgroundColor: '#222', // Ensure dark background
color: '#eee', // Light text color
} },
prompt && (React.createElement("div", { className: "imggen-progress-container", style: {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '6px',
overflow: 'hidden',
backgroundColor: 'rgba(0, 0, 0, 0.1)',
zIndex: 10,
} },
React.createElement("div", { className: combineClasses('imggen-progress', classes.progress), style: {
width: `${visibleProgress}%`,
height: '100%',
backgroundColor: 'var(--imggen-accent-color, #0074d9)',
transition: 'width 0.5s ease-out',
}, "aria-hidden": "true" }))),
!prompt && (React.createElement("div", { style: {
color: '#eee',
fontSize: 'var(--imggen-font-size)',
padding: '20px',
} }, "Waiting for prompt")),
prompt && !error && (
/* In production environment, show the styled prompt text */
React.createElement(React.Fragment, null,
React.createElement("div", { style: {
color: '#eee',
fontSize: 'var(--imggen-font-size)',
padding: '20px',
maxWidth: '90%',
wordBreak: 'break-word',
fontWeight: 'bold',
textAlign: 'center',
} }, prompt),
React.createElement("div", { style: { display: 'none' } },
React.createElement(ImageOverlay, { promptText: prompt || '', editedPrompt: null, setEditedPrompt: () => { }, handlePromptEdit: () => { }, handleDeleteConfirm: () => { }, handlePrevVersion: () => { }, handleNextVersion: () => { }, handleRegen: () => { }, versionIndex: 0, totalVersions: 1, classes: classes, showControls: false, showDelete: false }))))));
}
//# sourceMappingURL=ImgGenDisplayPlaceholder.js.map