diff --git a/frontend/apps/artcraft-website/src/pages/media/media.tsx b/frontend/apps/artcraft-website/src/pages/media/media.tsx
index 85edcc0fc1..deb4354e45 100644
--- a/frontend/apps/artcraft-website/src/pages/media/media.tsx
+++ b/frontend/apps/artcraft-website/src/pages/media/media.tsx
@@ -12,6 +12,9 @@ import {
faLink,
faCheck,
faArrowDownToLine,
+ faPencil,
+ faCircleInfo,
+ faImage,
} from "@fortawesome/pro-solid-svg-icons";
import {
addCorsParam,
@@ -47,6 +50,8 @@ interface MediaData {
createdAt: string | null;
isVideo: boolean;
isLoaded: boolean;
+ width?: number;
+ height?: number;
}
interface PromptData {
@@ -106,6 +111,15 @@ const useCopyFeedback = () => {
return { copied, triggerCopy };
};
+const InfoRow = ({ label, value }: { label: string; value: React.ReactNode }) => (
+
+ {label}
+
+ {value}
+
+
+);
+
export default function MediaPage() {
const { id: routeId } = useParams<{ id?: string }>();
const [searchParams] = useSearchParams();
@@ -121,13 +135,11 @@ export default function MediaPage() {
const [mediaRecordLoading, setMediaRecordLoading] = useState(true);
const [promptData, setPromptData] = useState(EMPTY_PROMPT_DATA);
- const [isPromptHovered, setIsPromptHovered] = useState(false);
const shareCopy = useCopyFeedback();
const promptCopy = useCopyFeedback();
const loadMedia = useCallback(async (id: string) => {
- setMedia(prev => ({ ...prev, isLoaded: false }));
setMediaRecordLoading(true);
const mediaFilesApi = new MediaFilesApi();
@@ -140,12 +152,17 @@ export default function MediaPage() {
const file = mediaResponse.data;
const url = file.media_links?.cdn_url || null;
- setMedia({
- url,
- token: file.token || id,
- createdAt: file.created_at || null,
- isVideo: url ? isVideoUrl(url) : false,
- isLoaded: false,
+ setMedia((prev) => {
+ const isSameUrl = prev.url === url;
+ return {
+ url,
+ token: file.token || id,
+ createdAt: file.created_at || null,
+ isVideo: url ? isVideoUrl(url) : false,
+ isLoaded: isSameUrl ? prev.isLoaded : false,
+ width: isSameUrl ? prev.width : undefined,
+ height: isSameUrl ? prev.height : undefined,
+ };
});
if (file.maybe_prompt_token) {
@@ -183,30 +200,7 @@ export default function MediaPage() {
}
}, [mediaIdParam, loadMedia]);
- useEffect(() => {
- if (!media.url) return;
-
- if (media.isVideo) {
- setMedia(prev => ({ ...prev, isLoaded: true }));
- return;
- }
-
- const img = new Image();
- img.src = addCorsParam(media.url) || media.url;
- const handleLoad = () => setMedia(prev => ({ ...prev, isLoaded: true }));
-
- if (img.complete) {
- handleLoad();
- } else {
- img.addEventListener("load", handleLoad);
- img.addEventListener("error", handleLoad);
- }
-
- return () => {
- img.removeEventListener("load", handleLoad);
- img.removeEventListener("error", handleLoad);
- };
- }, [media.url, media.isVideo]);
+
const handleCopyPrompt = useCallback(async () => {
if (!promptData.text) return;
@@ -231,49 +225,71 @@ export default function MediaPage() {
}, [media.token, shareCopy]);
const shareButtonIcon = shareCopy.copied ? faCheck : faLink;
- const shareButtonText = shareCopy.copied ? "Share link copied" : "Copy Share Link";
+
+ const getResolutionLabel = (width?: number) => {
+ if (!width) return null;
+ if (width >= 1000) return `${Math.round(width / 1024)}K`;
+ return null;
+ };
return (
-
-
-
-
+
+
+
+ {/* Media Preview Area */}
+
{mediaRecordLoading ? (
-
-
+
+
) : media.url ? (
-
+
{media.isVideo ? (