From e96eb046a2670cee46dd6acfcb2ab943f7a93ec4 Mon Sep 17 00:00:00 2001 From: WhiteRaven11 <95498438+WhiteRaven11@users.noreply.github.com> Date: Tue, 28 Jul 2026 23:11:42 +0300 Subject: [PATCH] Unify generation card interactions across devices --- .../src/components/AiInfluencerStudio.jsx | 12 +- .../studio/src/components/CinemaStudio.jsx | 73 +++++----- .../studio/src/components/ClippingStudio.jsx | 66 +++++---- .../studio/src/components/ImageStudio.jsx | 45 +++--- .../studio/src/components/LipSyncStudio.jsx | 45 +++--- .../studio/src/components/MarketingStudio.jsx | 54 +++++--- .../components/MobileGenerationActions.jsx | 129 ++++++++++++++++++ .../studio/src/components/RecastStudio.jsx | 45 +++--- .../src/components/VibeMotionStudio.jsx | 53 ++++--- .../studio/src/components/VideoStudio.jsx | 53 ++++--- 10 files changed, 392 insertions(+), 183 deletions(-) create mode 100644 packages/studio/src/components/MobileGenerationActions.jsx diff --git a/packages/studio/src/components/AiInfluencerStudio.jsx b/packages/studio/src/components/AiInfluencerStudio.jsx index 4a7000a..37e7c40 100644 --- a/packages/studio/src/components/AiInfluencerStudio.jsx +++ b/packages/studio/src/components/AiInfluencerStudio.jsx @@ -4,6 +4,7 @@ import { useState, useCallback } from "react"; import toast, { Toaster } from "react-hot-toast"; import { generateImage } from "../muapi.js"; import { formatErrorMessage } from "../utils/formatError.js"; +import MobileGenerationActions from "./MobileGenerationActions.jsx"; const CDN = "https://cdn.muapi.ai/influencer"; @@ -740,7 +741,7 @@ export default function AiInfluencerStudio({ > {`Character {/* Download on hover */} -
+
+ downloadImg(item.url), + }, + ]} + /> {/* Index badge */}
#{history.length - idx} diff --git a/packages/studio/src/components/CinemaStudio.jsx b/packages/studio/src/components/CinemaStudio.jsx index c872018..074aa07 100644 --- a/packages/studio/src/components/CinemaStudio.jsx +++ b/packages/studio/src/components/CinemaStudio.jsx @@ -3,6 +3,7 @@ import { useState, useEffect, useRef, useCallback } from "react"; import { generateImage, uploadFile } from "../muapi.js"; import { scopedPersistKey, migrateLegacyPersistKey } from "../persistKey.js"; +import MobileGenerationActions from "./MobileGenerationActions.jsx"; import { PromptAspectRatioIcon, PromptAction, @@ -724,24 +725,6 @@ export default function CinemaStudio({ [onGenerationError], ); - // ── Load history item ── - const loadHistoryItem = (entry, idx) => { - if (entry.settings) { - setSettings((prev) => ({ - ...prev, - camera: entry.settings.camera ?? prev.camera, - lens: entry.settings.lens ?? prev.lens, - focal: entry.settings.focal ?? prev.focal, - aperture: entry.settings.aperture ?? prev.aperture, - aspect_ratio: entry.settings.aspect_ratio ?? prev.aspect_ratio, - prompt: entry.settings.prompt ?? prev.prompt, - })); - if (entry.settings.resolution) setResolution(entry.settings.resolution); - - } - setCanvasUrl(entry.url); - }; - const resetToPrompt = () => { setCanvasUrl(null); setSettings((prev) => ({ ...prev, prompt: "" })); @@ -762,7 +745,7 @@ export default function CinemaStudio({
loadHistoryItem(entry, idx)} + onClick={() => setFullscreenUrl(entry.url)} > {/* Overlay actions */} -
- +
+ { + try { + const response = await fetch(entry.url); + const blob = await response.blob(); + const blobUrl = URL.createObjectURL(blob); + const anchor = document.createElement("a"); + anchor.href = blobUrl; + anchor.download = `cinema-shot-${entry.id || idx}.jpg`; + document.body.appendChild(anchor); + anchor.click(); + document.body.removeChild(anchor); + URL.revokeObjectURL(blobUrl); + } catch { + window.open(entry.url, "_blank"); + } + }, + }, + { + kind: "delete", + label: "Delete", + danger: true, + onSelect: () => { + if (confirm("Are you sure you want to delete this generated item?")) { + setInternalHistory((prev) => prev.filter((_, i) => i !== idx)); + } + }, + }, + ]} + /> {/* Details */}
diff --git a/packages/studio/src/components/ClippingStudio.jsx b/packages/studio/src/components/ClippingStudio.jsx index a2c15ff..507a67c 100644 --- a/packages/studio/src/components/ClippingStudio.jsx +++ b/packages/studio/src/components/ClippingStudio.jsx @@ -5,6 +5,7 @@ import toast, { Toaster } from "react-hot-toast"; import { runClipping, uploadFile } from "../muapi.js"; import { formatErrorMessage } from "../utils/formatError.js"; import { scopedPersistKey, migrateLegacyPersistKey } from "../persistKey.js"; +import MobileGenerationActions from "./MobileGenerationActions.jsx"; import { PROMPT_CONTROL_LABEL_CLASS, PROMPT_MEDIA_PREVIEW_CLASS, @@ -592,17 +593,17 @@ export default function ClippingStudio({ {history.map((entry, idx) => (
handleSelectHistory(entry)} + className="relative group rounded-lg overflow-hidden border border-white/10 bg-[#0a0a0a] shadow-xl hover:border-primary/50 transition-all duration-300 flex flex-col cursor-pointer" >