@orangecatai/adgen-canvas 0.0.39 → 0.0.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dev/{chunk-E7VZGEUJ.js → chunk-JWNDQ5YS.js} +2 -2
- package/dist/dev/{chunk-5XP2WJAQ.js → chunk-XWMZCKIQ.js} +3 -3
- package/dist/dev/data/{image-PUPXCX7M.js → image-CHTDICZP.js} +3 -3
- package/dist/dev/index.js +494 -446
- package/dist/dev/index.js.map +4 -4
- package/dist/dev/subset-shared.chunk.js +1 -1
- package/dist/dev/subset-worker.chunk.js +1 -1
- package/dist/prod/{chunk-T3ZLBHX4.js → chunk-QG2AQCPN.js} +2 -2
- package/dist/prod/{chunk-WBFDC4WN.js → chunk-VASPG36O.js} +1 -1
- package/dist/prod/data/image-ZEYF7NUD.js +1 -0
- package/dist/prod/index.js +74 -76
- package/dist/prod/subset-shared.chunk.js +1 -1
- package/dist/prod/subset-worker.chunk.js +1 -1
- package/package.json +1 -1
- package/dist/prod/data/image-AG3CTRSJ.js +0 -1
- /package/dist/dev/{chunk-E7VZGEUJ.js.map → chunk-JWNDQ5YS.js.map} +0 -0
- /package/dist/dev/{chunk-5XP2WJAQ.js.map → chunk-XWMZCKIQ.js.map} +0 -0
- /package/dist/dev/data/{image-PUPXCX7M.js.map → image-CHTDICZP.js.map} +0 -0
package/dist/dev/index.js
CHANGED
|
@@ -66,10 +66,10 @@ import {
|
|
|
66
66
|
serializeAsJSON,
|
|
67
67
|
serializeLibraryAsJSON,
|
|
68
68
|
strokeRectWithRotation_simple
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-XWMZCKIQ.js";
|
|
70
70
|
import {
|
|
71
71
|
define_import_meta_env_default
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-JWNDQ5YS.js";
|
|
73
73
|
import {
|
|
74
74
|
en_default
|
|
75
75
|
} from "./chunk-LIELFD5T.js";
|
|
@@ -9733,7 +9733,7 @@ var exportCanvas = async (type, elements, appState, files, {
|
|
|
9733
9733
|
let blob = canvasToBlob(tempCanvas);
|
|
9734
9734
|
if (appState.exportEmbedScene) {
|
|
9735
9735
|
blob = blob.then(
|
|
9736
|
-
(blob2) => import("./data/image-
|
|
9736
|
+
(blob2) => import("./data/image-CHTDICZP.js").then(
|
|
9737
9737
|
({ encodePngMetadata: encodePngMetadata2 }) => encodePngMetadata2({
|
|
9738
9738
|
blob: blob2,
|
|
9739
9739
|
metadata: serializeAsJSON(elements, appState, files, "local")
|
|
@@ -22814,7 +22814,7 @@ function hasPendingGeneration(elementId) {
|
|
|
22814
22814
|
import { useCallback as useCallback17, useEffect as useEffect33, useRef as useRef29, useState as useState31 } from "react";
|
|
22815
22815
|
import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords6 } from "@orangecatai/common";
|
|
22816
22816
|
import { getElementAbsoluteCoords as getElementAbsoluteCoords9 } from "@orangecatai/element";
|
|
22817
|
-
import { ArrowUp as ArrowUp2 } from "lucide-react";
|
|
22817
|
+
import { ArrowUp as ArrowUp2, ImagePlus as ImagePlus2, X as X2 } from "lucide-react";
|
|
22818
22818
|
|
|
22819
22819
|
// utils/imageCompression.ts
|
|
22820
22820
|
var MAX_EDGE_PX = 1280;
|
|
@@ -23354,243 +23354,6 @@ ${referenceManifest}` : promptWithBrandContext;
|
|
|
23354
23354
|
throw new Error("No image was returned by the API.");
|
|
23355
23355
|
}
|
|
23356
23356
|
|
|
23357
|
-
// utils/brandContextUtils.ts
|
|
23358
|
-
var SIZE_SCALE_MAP = {
|
|
23359
|
-
display: "48\u201372px",
|
|
23360
|
-
large: "32\u201348px",
|
|
23361
|
-
medium: "20\u201328px",
|
|
23362
|
-
small: "14\u201318px"
|
|
23363
|
-
};
|
|
23364
|
-
function buildBrandContextMessage(ctx) {
|
|
23365
|
-
const lines = [
|
|
23366
|
-
"## Brand Identity \u2014 you MUST apply every guideline below to all ads you create, by default"
|
|
23367
|
-
];
|
|
23368
|
-
if (ctx.colors) {
|
|
23369
|
-
const { primary, secondary, accent, background } = ctx.colors;
|
|
23370
|
-
const parts = [
|
|
23371
|
-
primary && `Primary: ${primary}`,
|
|
23372
|
-
secondary && `Secondary: ${secondary}`,
|
|
23373
|
-
accent && `Accent/CTA: ${accent}`,
|
|
23374
|
-
background && `Background: ${background}`
|
|
23375
|
-
].filter(Boolean);
|
|
23376
|
-
if (parts.length) {
|
|
23377
|
-
lines.push(`**Colors**: ${parts.join(", ")}`);
|
|
23378
|
-
}
|
|
23379
|
-
}
|
|
23380
|
-
if (ctx.typography) {
|
|
23381
|
-
const { headline, body } = ctx.typography;
|
|
23382
|
-
if (headline?.family) {
|
|
23383
|
-
const sizeHint = headline.sizeScale ? ` (suggested size: ${SIZE_SCALE_MAP[headline.sizeScale] ?? headline.sizeScale})` : "";
|
|
23384
|
-
const fontFileNote = headline.fontFamilyId ? ` \u2014 a brand font; match this typeface closely for the on-image text (use your judgment for which brand font suits headlines vs body copy)` : ` \u2014 render on-image text in a style that matches ${headline.family}`;
|
|
23385
|
-
lines.push(
|
|
23386
|
-
`**Headline font**: ${headline.family}${headline.weight ? ` weight ${headline.weight}` : ""}${sizeHint}${fontFileNote}`
|
|
23387
|
-
);
|
|
23388
|
-
}
|
|
23389
|
-
if (body?.family) {
|
|
23390
|
-
const sizeHint = body.sizeScale ? ` (suggested size: ${SIZE_SCALE_MAP[body.sizeScale] ?? body.sizeScale})` : "";
|
|
23391
|
-
const fontFileNote = body.fontFamilyId ? ` \u2014 a brand font; match this typeface closely for the on-image text (use your judgment for which brand font suits headlines vs body copy)` : ` \u2014 render on-image text in a style that matches ${body.family}`;
|
|
23392
|
-
lines.push(
|
|
23393
|
-
`**Body font**: ${body.family}${body.weight ? ` weight ${body.weight}` : ""}${sizeHint}${fontFileNote}`
|
|
23394
|
-
);
|
|
23395
|
-
}
|
|
23396
|
-
}
|
|
23397
|
-
if (ctx.visualStyle) {
|
|
23398
|
-
lines.push(`**Visual style**: ${ctx.visualStyle}`);
|
|
23399
|
-
}
|
|
23400
|
-
if (ctx.layoutPattern) {
|
|
23401
|
-
lines.push(`**Layout pattern**: ${ctx.layoutPattern}`);
|
|
23402
|
-
}
|
|
23403
|
-
if (ctx.toneOfVoice) {
|
|
23404
|
-
const { register: register2, vocabulary, ctaStyle, sentenceLength, person } = ctx.toneOfVoice;
|
|
23405
|
-
const parts = [
|
|
23406
|
-
register2 && `register: ${register2}`,
|
|
23407
|
-
vocabulary && `vocabulary: ${vocabulary}`,
|
|
23408
|
-
ctaStyle && `CTA style: ${ctaStyle}`,
|
|
23409
|
-
sentenceLength && `sentence length: ${sentenceLength}`,
|
|
23410
|
-
person && `person: ${person}`
|
|
23411
|
-
].filter(Boolean);
|
|
23412
|
-
if (parts.length) {
|
|
23413
|
-
lines.push(`**Tone of voice**: ${parts.join(", ")}`);
|
|
23414
|
-
}
|
|
23415
|
-
}
|
|
23416
|
-
if (ctx.imagery) {
|
|
23417
|
-
const {
|
|
23418
|
-
type,
|
|
23419
|
-
lighting,
|
|
23420
|
-
composition,
|
|
23421
|
-
subjects,
|
|
23422
|
-
grading,
|
|
23423
|
-
depthOfField,
|
|
23424
|
-
environment,
|
|
23425
|
-
negativeSpace
|
|
23426
|
-
} = ctx.imagery;
|
|
23427
|
-
const parts = [
|
|
23428
|
-
type && `type: ${type}`,
|
|
23429
|
-
subjects && `subjects: ${subjects}`,
|
|
23430
|
-
lighting && `lighting: ${lighting}`,
|
|
23431
|
-
grading && `grading: ${grading}`,
|
|
23432
|
-
depthOfField && `depth of field: ${depthOfField}`,
|
|
23433
|
-
environment && `environment: ${environment}`,
|
|
23434
|
-
negativeSpace && `negative space: ${negativeSpace}`,
|
|
23435
|
-
composition && `composition: ${composition}`
|
|
23436
|
-
].filter(Boolean);
|
|
23437
|
-
if (parts.length) {
|
|
23438
|
-
lines.push(`**Imagery direction**: ${parts.join(", ")}`);
|
|
23439
|
-
}
|
|
23440
|
-
}
|
|
23441
|
-
lines.push(
|
|
23442
|
-
"",
|
|
23443
|
-
"**Precedence**: these are defaults, not absolutes. If the user's request explicitly states or clearly implies something different from a guideline above \u2014 a different color, mood, style, subject treatment, or tone \u2014 follow the user's explicit instruction for that ad instead of the brand guideline it conflicts with. Do not silently override what the user asked for in favor of brand consistency; only apply a guideline where the user's request is silent on that point."
|
|
23444
|
-
);
|
|
23445
|
-
return lines.join("\n");
|
|
23446
|
-
}
|
|
23447
|
-
function buildImageGenSafePrompt(prompt, brandContext, opts) {
|
|
23448
|
-
const hasUserReferences = Boolean(opts?.hasUserReferences);
|
|
23449
|
-
const headlineFontName = brandContext.typography?.headline?.family;
|
|
23450
|
-
const bodyFontName = brandContext.typography?.body?.family;
|
|
23451
|
-
const fontNames = [headlineFontName, bodyFontName].filter(
|
|
23452
|
-
(n, i, arr) => Boolean(n) && arr.indexOf(n) === i
|
|
23453
|
-
);
|
|
23454
|
-
const fontHint = fontNames.length ? ` Brand typography: the brand font${fontNames.length > 1 ? "s are" : " is"} ${fontNames.join(
|
|
23455
|
-
" and "
|
|
23456
|
-
)} \u2014 you MUST render ALL on-image text exclusively in this exact typeface as shown in the font reference image${fontNames.length > 1 ? "s" : ""}. Do NOT use any generic, default, or substitute font.` : "";
|
|
23457
|
-
const brandImageInstructions = [];
|
|
23458
|
-
if (brandContext.logoDataUrl) {
|
|
23459
|
-
brandImageInstructions.push(
|
|
23460
|
-
`BRAND LOGO: One of the attached reference images is the exact brand logo graphic \u2014 the reference manifest at the end of this prompt identifies which. Embed it VERBATIM in the ad \u2014 do not redraw, simplify, stylize, or alter it in any way. Do not overlap it with other copy or elements. The logo must appear exactly as it does in the reference image.`
|
|
23461
|
-
);
|
|
23462
|
-
}
|
|
23463
|
-
if (brandContext.headlineFontPreviewDataUrl || brandContext.bodyFontPreviewDataUrl) {
|
|
23464
|
-
const multiple = Boolean(
|
|
23465
|
-
brandContext.headlineFontPreviewDataUrl && brandContext.bodyFontPreviewDataUrl
|
|
23466
|
-
);
|
|
23467
|
-
brandImageInstructions.push(
|
|
23468
|
-
`BRAND FONT: The attached brand font specimen ${multiple ? "images are" : "image is"} the brand's exact typeface${multiple ? "s" : ""}. You MUST render EVERY piece of on-image text \u2014 headlines, subheadlines, CTA, sign-off, and body copy \u2014 EXCLUSIVELY in ${multiple ? "these exact fonts as shown (use the headline specimen for headlines, the body specimen for body/supporting copy)" : "this exact font as shown in the image"}. Do NOT use any generic, default, or substitute font anywhere in the ad.`
|
|
23469
|
-
);
|
|
23470
|
-
}
|
|
23471
|
-
const brandImageHint = brandImageInstructions.length > 0 ? ` ${brandImageInstructions.join(" ")}` : "";
|
|
23472
|
-
const brandNameHint = brandContext.name && !hasUserReferences ? ` This ad is for the brand "${brandContext.name}" \u2014 all visual elements, copy, and style must reflect this brand exclusively.` : "";
|
|
23473
|
-
return `${prompt}${brandNameHint}${fontHint}${brandImageHint} Render all specified copy as crisp, correctly-spelled, legible text within the image.
|
|
23474
|
-
|
|
23475
|
-
${PRECEDENCE_LINE}`;
|
|
23476
|
-
}
|
|
23477
|
-
var clean = (value) => {
|
|
23478
|
-
const trimmed = value?.trim();
|
|
23479
|
-
return trimmed ? trimmed : void 0;
|
|
23480
|
-
};
|
|
23481
|
-
var PRECEDENCE_LINE = "The subject, action, and setting described at the top are authoritative. Apply this brand direction only where the prompt is silent; where they conflict, the prompt wins.";
|
|
23482
|
-
function buildVideoBrandPrompt(prompt, ctx, opts) {
|
|
23483
|
-
const lines = [];
|
|
23484
|
-
const brandName = clean(ctx.name);
|
|
23485
|
-
if (brandName) {
|
|
23486
|
-
lines.push(`This is a brand film for ${brandName}.`);
|
|
23487
|
-
}
|
|
23488
|
-
if (ctx.colors) {
|
|
23489
|
-
const primary = clean(ctx.colors.primary);
|
|
23490
|
-
const secondary = clean(ctx.colors.secondary);
|
|
23491
|
-
const accent = clean(ctx.colors.accent);
|
|
23492
|
-
const background = clean(ctx.colors.background);
|
|
23493
|
-
const parts = [
|
|
23494
|
-
primary && `dominant ${primary}`,
|
|
23495
|
-
secondary && `supporting ${secondary}`,
|
|
23496
|
-
accent && `${accent} reserved for accents and CTA moments`,
|
|
23497
|
-
background && `${background} for backgrounds and negative space`
|
|
23498
|
-
].filter(Boolean);
|
|
23499
|
-
if (parts.length) {
|
|
23500
|
-
lines.push(
|
|
23501
|
-
`Palette: ${parts.join(
|
|
23502
|
-
"; "
|
|
23503
|
-
)}. Grade the footage so these read as the natural colour story of the scene rather than as an overlay.`
|
|
23504
|
-
);
|
|
23505
|
-
}
|
|
23506
|
-
}
|
|
23507
|
-
const visualStyle = clean(ctx.visualStyle);
|
|
23508
|
-
if (visualStyle) {
|
|
23509
|
-
lines.push(`Look: ${visualStyle}.`);
|
|
23510
|
-
}
|
|
23511
|
-
if (ctx.imagery) {
|
|
23512
|
-
const {
|
|
23513
|
-
type,
|
|
23514
|
-
subjects,
|
|
23515
|
-
lighting,
|
|
23516
|
-
grading,
|
|
23517
|
-
depthOfField,
|
|
23518
|
-
environment,
|
|
23519
|
-
composition
|
|
23520
|
-
} = ctx.imagery;
|
|
23521
|
-
const parts = [
|
|
23522
|
-
clean(type) && `${clean(type)} footage`,
|
|
23523
|
-
clean(subjects) && `subjects: ${clean(subjects)}`,
|
|
23524
|
-
clean(lighting) && `lighting: ${clean(lighting)}`,
|
|
23525
|
-
clean(grading) && `grade: ${clean(grading)}`,
|
|
23526
|
-
clean(depthOfField) && `depth of field: ${clean(depthOfField)}`,
|
|
23527
|
-
clean(environment) && `environment: ${clean(environment)}`,
|
|
23528
|
-
clean(composition) && `framing: ${clean(composition)}`
|
|
23529
|
-
].filter(Boolean);
|
|
23530
|
-
if (parts.length) {
|
|
23531
|
-
lines.push(`Cinematography: ${parts.join(", ")}.`);
|
|
23532
|
-
}
|
|
23533
|
-
}
|
|
23534
|
-
if (ctx.toneOfVoice) {
|
|
23535
|
-
const { register: register2, vocabulary, ctaStyle, person } = ctx.toneOfVoice;
|
|
23536
|
-
const parts = [
|
|
23537
|
-
clean(register2),
|
|
23538
|
-
clean(vocabulary) && `${clean(vocabulary)} vocabulary`,
|
|
23539
|
-
clean(ctaStyle) && `${clean(ctaStyle)} calls to action`,
|
|
23540
|
-
clean(person)
|
|
23541
|
-
].filter(Boolean);
|
|
23542
|
-
if (parts.length) {
|
|
23543
|
-
lines.push(
|
|
23544
|
-
`Tone: ${parts.join(
|
|
23545
|
-
", "
|
|
23546
|
-
)} \u2014 applies to any narration, voiceover, or on-screen copy.`
|
|
23547
|
-
);
|
|
23548
|
-
}
|
|
23549
|
-
}
|
|
23550
|
-
const typefaces = [
|
|
23551
|
-
clean(ctx.typography?.headline?.family),
|
|
23552
|
-
clean(ctx.typography?.body?.family)
|
|
23553
|
-
].filter(
|
|
23554
|
-
(name, i, arr) => Boolean(name) && arr.indexOf(name) === i
|
|
23555
|
-
);
|
|
23556
|
-
if (typefaces.length) {
|
|
23557
|
-
lines.push(
|
|
23558
|
-
`On-screen text: keep to a minimum; if any appears it should read as ${typefaces.join(
|
|
23559
|
-
" or "
|
|
23560
|
-
)}, or a close match in spirit. No paragraphs of text.`
|
|
23561
|
-
);
|
|
23562
|
-
}
|
|
23563
|
-
const userReferenceCount = Math.max(0, opts?.userReferenceCount ?? 0);
|
|
23564
|
-
const hasLogo = Boolean(opts?.hasLogoReference && clean(ctx.logoDataUrl));
|
|
23565
|
-
if (hasLogo) {
|
|
23566
|
-
lines.push(
|
|
23567
|
-
userReferenceCount > 0 ? (
|
|
23568
|
-
// With user references present the logo is no longer first — the
|
|
23569
|
-
// manifest appended below states its actual position.
|
|
23570
|
-
"Brand logo: the brand logo is supplied as one of the attached reference images (see the manifest below). If it appears in frame, reproduce it verbatim \u2014 never redraw, restyle, recolour, or animate its glyphs."
|
|
23571
|
-
) : "Brand logo: the first reference image is the exact brand logo. If it appears in frame, reproduce it verbatim \u2014 never redraw, restyle, recolour, or animate its glyphs."
|
|
23572
|
-
);
|
|
23573
|
-
}
|
|
23574
|
-
const manifest = userReferenceCount > 0 ? `
|
|
23575
|
-
|
|
23576
|
-
${buildReferenceManifest(
|
|
23577
|
-
userReferenceCount,
|
|
23578
|
-
hasLogo ? ["the exact brand logo"] : []
|
|
23579
|
-
)}` : "";
|
|
23580
|
-
if (!lines.length) {
|
|
23581
|
-
return manifest ? `${prompt}${manifest}` : prompt;
|
|
23582
|
-
}
|
|
23583
|
-
const header = brandName ? `## Brand direction \u2014 ${brandName}` : "## Brand direction";
|
|
23584
|
-
return `${prompt}
|
|
23585
|
-
|
|
23586
|
-
${header}
|
|
23587
|
-
${lines.join(
|
|
23588
|
-
"\n"
|
|
23589
|
-
)}
|
|
23590
|
-
|
|
23591
|
-
${PRECEDENCE_LINE}${manifest}`;
|
|
23592
|
-
}
|
|
23593
|
-
|
|
23594
23357
|
// components/ImageGeneratorPanel.tsx
|
|
23595
23358
|
import { useCallback as useCallback16, useEffect as useEffect32, useRef as useRef28, useState as useState30 } from "react";
|
|
23596
23359
|
import { sceneCoordsToViewportCoords as sceneCoordsToViewportCoords5 } from "@orangecatai/common";
|
|
@@ -25040,7 +24803,6 @@ var ImageGeneratorPanel = ({
|
|
|
25040
24803
|
};
|
|
25041
24804
|
const appState = app.state;
|
|
25042
24805
|
const imageGenUrl = app.props.imageGenUrl;
|
|
25043
|
-
const brandContext = app.props.brandContext;
|
|
25044
24806
|
const [prompt, setPrompt] = useState30(() => getPendingPrompt(element.id));
|
|
25045
24807
|
const [selectedModel, setSelectedModel] = useState30(() => {
|
|
25046
24808
|
const stored = getStoredSettings(element);
|
|
@@ -25319,39 +25081,20 @@ var ImageGeneratorPanel = ({
|
|
|
25319
25081
|
let genError = null;
|
|
25320
25082
|
try {
|
|
25321
25083
|
const cfg = MODEL_CONFIG[selectedModel];
|
|
25322
|
-
const brandImages = brandContext ? {
|
|
25323
|
-
logo: brandContext.logoDataUrl,
|
|
25324
|
-
fontPreview: brandContext.headlineFontPreviewDataUrl,
|
|
25325
|
-
fontPreviewBody: brandContext.bodyFontPreviewDataUrl,
|
|
25326
|
-
fontUrl: brandContext.headlineFontUrl,
|
|
25327
|
-
brandContextText: buildBrandContextMessage(brandContext)
|
|
25328
|
-
} : void 0;
|
|
25329
|
-
const safePrompt = brandContext ? buildImageGenSafePrompt(prompt, brandContext, {
|
|
25330
|
-
hasUserReferences: referenceImages.length > 0
|
|
25331
|
-
}) : prompt;
|
|
25332
25084
|
const { aspectRatio, imageSize } = resolveRequestSize(
|
|
25333
25085
|
selectedModel,
|
|
25334
25086
|
selectedRatio,
|
|
25335
25087
|
selectedResolution
|
|
25336
25088
|
);
|
|
25337
25089
|
const imageDataUrl = await callOpenRouterImageAPI(
|
|
25338
|
-
|
|
25090
|
+
prompt,
|
|
25339
25091
|
cfg.modelId,
|
|
25340
25092
|
aspectRatio,
|
|
25341
25093
|
imageSize,
|
|
25342
25094
|
cfg.textOutput,
|
|
25343
25095
|
imageGenUrl,
|
|
25344
25096
|
referenceImages,
|
|
25345
|
-
controller.signal
|
|
25346
|
-
brandImages,
|
|
25347
|
-
{
|
|
25348
|
-
// The user picked these references — they lead the array and outrank
|
|
25349
|
-
// the brand kit, which still travels with them behind the logo.
|
|
25350
|
-
referenceMode: "user-priority",
|
|
25351
|
-
protectLogo: true,
|
|
25352
|
-
hostBrandAssetSlots: 2,
|
|
25353
|
-
hostAdReferenceSlots: 2
|
|
25354
|
-
}
|
|
25097
|
+
controller.signal
|
|
25355
25098
|
);
|
|
25356
25099
|
await app.insertGeneratedImageIntoFrame(imageDataUrl, element);
|
|
25357
25100
|
onAfterImageGen?.();
|
|
@@ -25826,7 +25569,6 @@ var ImageQuickEditPanel = ({
|
|
|
25826
25569
|
}) => {
|
|
25827
25570
|
const appState = app.state;
|
|
25828
25571
|
const imageGenUrl = app.props.imageGenUrl;
|
|
25829
|
-
const brandContext = app.props.brandContext;
|
|
25830
25572
|
const [isOpen, setIsOpen] = useState31(
|
|
25831
25573
|
() => forceOpen || hasPendingGeneration(element.id)
|
|
25832
25574
|
);
|
|
@@ -25876,7 +25618,10 @@ var ImageQuickEditPanel = ({
|
|
|
25876
25618
|
const ratioDropdownRef = useRef29(null);
|
|
25877
25619
|
const resolutionDropdownRef = useRef29(null);
|
|
25878
25620
|
const modelDropdownRef = useRef29(null);
|
|
25621
|
+
const fileInputRef = useRef29(null);
|
|
25879
25622
|
const abortControllerRef = useRef29(null);
|
|
25623
|
+
const [referenceImages, setReferenceImages] = useState31([]);
|
|
25624
|
+
const [chipMenu, setChipMenu] = useState31(false);
|
|
25880
25625
|
const applyRatio = useCallback17((ratioLabel) => {
|
|
25881
25626
|
setSelectedRatio(ratioLabel);
|
|
25882
25627
|
setRatioOpen(false);
|
|
@@ -25912,6 +25657,36 @@ var ImageQuickEditPanel = ({
|
|
|
25912
25657
|
const handleStop = useCallback17(() => {
|
|
25913
25658
|
abortPendingGeneration(element.id);
|
|
25914
25659
|
}, [element.id]);
|
|
25660
|
+
const handleImageUpload = useCallback17(
|
|
25661
|
+
(e) => {
|
|
25662
|
+
const files = Array.from(e.target.files ?? []);
|
|
25663
|
+
e.target.value = "";
|
|
25664
|
+
Promise.all(
|
|
25665
|
+
files.map(
|
|
25666
|
+
(file2) => new Promise((resolve) => {
|
|
25667
|
+
const reader = new FileReader();
|
|
25668
|
+
reader.onload = () => resolve(reader.result);
|
|
25669
|
+
reader.onerror = () => resolve(null);
|
|
25670
|
+
reader.readAsDataURL(file2);
|
|
25671
|
+
})
|
|
25672
|
+
)
|
|
25673
|
+
).then((results) => {
|
|
25674
|
+
const added = results.filter(
|
|
25675
|
+
(result) => Boolean(result)
|
|
25676
|
+
);
|
|
25677
|
+
setReferenceImages(
|
|
25678
|
+
(current) => [...current, ...added].slice(0, MAX_USER_REFERENCE_IMAGES)
|
|
25679
|
+
);
|
|
25680
|
+
});
|
|
25681
|
+
},
|
|
25682
|
+
[]
|
|
25683
|
+
);
|
|
25684
|
+
const handlePickResolved = useCallback17((_slot, dataUrl) => {
|
|
25685
|
+
setReferenceImages(
|
|
25686
|
+
(current) => [...current, dataUrl].slice(0, MAX_USER_REFERENCE_IMAGES)
|
|
25687
|
+
);
|
|
25688
|
+
}, []);
|
|
25689
|
+
const picker = useCanvasFramePicker(app, handlePickResolved);
|
|
25915
25690
|
const handleGenerate = useCallback17(async () => {
|
|
25916
25691
|
if (!prompt.trim()) {
|
|
25917
25692
|
setGenerateError("Please enter a prompt.");
|
|
@@ -25955,42 +25730,22 @@ var ImageQuickEditPanel = ({
|
|
|
25955
25730
|
try {
|
|
25956
25731
|
const cfg = MODEL_CONFIG[selectedModel];
|
|
25957
25732
|
const refDataUrl = element.fileId ? app.files[element.fileId]?.dataURL : void 0;
|
|
25958
|
-
const brandImages = brandContext ? {
|
|
25959
|
-
logo: brandContext.logoDataUrl,
|
|
25960
|
-
fontPreview: brandContext.headlineFontPreviewDataUrl,
|
|
25961
|
-
fontPreviewBody: brandContext.bodyFontPreviewDataUrl,
|
|
25962
|
-
fontUrl: brandContext.headlineFontUrl,
|
|
25963
|
-
brandContextText: buildBrandContextMessage(brandContext)
|
|
25964
|
-
} : void 0;
|
|
25965
|
-
const basePrompt = brandContext ? buildImageGenSafePrompt(prompt, brandContext, {
|
|
25966
|
-
hasUserReferences: Boolean(refDataUrl)
|
|
25967
|
-
}) : prompt;
|
|
25968
|
-
const safePrompt = `${basePrompt} CRITICAL PRESERVATION RULE: Apply ONLY the specific change described above. The number of visual elements (text blocks, logos, images, shapes, buttons) must be IDENTICAL before and after this edit \u2014 do NOT add any new element, do NOT remove any existing element, do NOT rearrange the layout or composition. Every element that exists in the source image must appear exactly once in the output, in the same position and arrangement. Only the specific requested change may differ.`;
|
|
25969
25733
|
const { aspectRatio, imageSize } = resolveRequestSize(
|
|
25970
25734
|
selectedModel,
|
|
25971
25735
|
selectedRatio,
|
|
25972
25736
|
selectedResolution
|
|
25973
25737
|
);
|
|
25974
25738
|
const imageDataUrl = await callOpenRouterImageAPI(
|
|
25975
|
-
|
|
25739
|
+
prompt,
|
|
25976
25740
|
cfg.modelId,
|
|
25977
25741
|
aspectRatio,
|
|
25978
25742
|
imageSize,
|
|
25979
25743
|
cfg.textOutput,
|
|
25980
25744
|
imageGenUrl,
|
|
25981
|
-
|
|
25982
|
-
|
|
25983
|
-
|
|
25984
|
-
|
|
25985
|
-
referenceMode: "user-priority",
|
|
25986
|
-
// The image under edit is the subject — it ranks above the brand kit
|
|
25987
|
-
// and is never shed. The logo rides along below it and, uniquely on
|
|
25988
|
-
// this surface, may be dropped if the payload runs out of room.
|
|
25989
|
-
sourceImageDataUrl: refDataUrl,
|
|
25990
|
-
protectLogo: false,
|
|
25991
|
-
hostBrandAssetSlots: 2,
|
|
25992
|
-
hostAdReferenceSlots: 2
|
|
25993
|
-
}
|
|
25745
|
+
[refDataUrl, ...referenceImages].filter(
|
|
25746
|
+
(dataUrl) => Boolean(dataUrl)
|
|
25747
|
+
),
|
|
25748
|
+
controller.signal
|
|
25994
25749
|
);
|
|
25995
25750
|
const dims = getDimensions(
|
|
25996
25751
|
selectedModel,
|
|
@@ -26031,6 +25786,7 @@ var ImageQuickEditPanel = ({
|
|
|
26031
25786
|
selectedModel,
|
|
26032
25787
|
selectedRatio,
|
|
26033
25788
|
selectedResolution,
|
|
25789
|
+
referenceImages,
|
|
26034
25790
|
app,
|
|
26035
25791
|
element,
|
|
26036
25792
|
onBeforeImageGen,
|
|
@@ -26054,6 +25810,13 @@ var ImageQuickEditPanel = ({
|
|
|
26054
25810
|
const panelX = panelVpX - appState.offsetLeft;
|
|
26055
25811
|
const panelY = panelVpY - appState.offsetTop + 16;
|
|
26056
25812
|
return /* @__PURE__ */ jsxs49(Fragment12, { children: [
|
|
25813
|
+
/* @__PURE__ */ jsx89(
|
|
25814
|
+
ElementPickHighlight,
|
|
25815
|
+
{
|
|
25816
|
+
element: picker.pickingSlot ? picker.hoveredElement : null,
|
|
25817
|
+
appState
|
|
25818
|
+
}
|
|
25819
|
+
),
|
|
26057
25820
|
!forceOpen && /* @__PURE__ */ jsx89(
|
|
26058
25821
|
"div",
|
|
26059
25822
|
{
|
|
@@ -26075,172 +25838,250 @@ var ImageQuickEditPanel = ({
|
|
|
26075
25838
|
)
|
|
26076
25839
|
}
|
|
26077
25840
|
),
|
|
26078
|
-
isOpen && /* @__PURE__ */
|
|
25841
|
+
isOpen && /* @__PURE__ */ jsxs49(
|
|
26079
25842
|
"div",
|
|
26080
25843
|
{
|
|
26081
25844
|
className: "igp iqep__panel",
|
|
26082
25845
|
style: { left: `${panelX}px`, top: `${panelY}px` },
|
|
26083
25846
|
onPointerDown: (e) => e.stopPropagation(),
|
|
26084
25847
|
onClick: (e) => e.stopPropagation(),
|
|
26085
|
-
children:
|
|
26086
|
-
|
|
26087
|
-
|
|
26088
|
-
|
|
26089
|
-
|
|
26090
|
-
|
|
26091
|
-
|
|
26092
|
-
|
|
26093
|
-
|
|
26094
|
-
|
|
26095
|
-
|
|
26096
|
-
|
|
26097
|
-
|
|
26098
|
-
|
|
26099
|
-
|
|
26100
|
-
|
|
26101
|
-
|
|
26102
|
-
|
|
26103
|
-
|
|
26104
|
-
|
|
26105
|
-
|
|
25848
|
+
children: [
|
|
25849
|
+
/* @__PURE__ */ jsx89(
|
|
25850
|
+
"input",
|
|
25851
|
+
{
|
|
25852
|
+
ref: fileInputRef,
|
|
25853
|
+
type: "file",
|
|
25854
|
+
accept: "image/*",
|
|
25855
|
+
multiple: true,
|
|
25856
|
+
style: { display: "none" },
|
|
25857
|
+
onChange: handleImageUpload
|
|
25858
|
+
}
|
|
25859
|
+
),
|
|
25860
|
+
/* @__PURE__ */ jsxs49(
|
|
25861
|
+
PromptInput,
|
|
25862
|
+
{
|
|
25863
|
+
isLoading: isGenerating,
|
|
25864
|
+
value: prompt,
|
|
25865
|
+
onValueChange: setPrompt,
|
|
25866
|
+
onSubmit: handleGenerate,
|
|
25867
|
+
className: "igp-container",
|
|
25868
|
+
children: [
|
|
25869
|
+
referenceImages.length > 0 && /* @__PURE__ */ jsx89("div", { className: "igp-ref-chips", children: referenceImages.map((src, i) => /* @__PURE__ */ jsxs49("div", { className: "igp-ref-chip", children: [
|
|
25870
|
+
/* @__PURE__ */ jsx89("img", { src, alt: `Reference ${i + 1}` }),
|
|
25871
|
+
/* @__PURE__ */ jsxs49("span", { children: [
|
|
25872
|
+
"Reference ",
|
|
25873
|
+
i + 1
|
|
25874
|
+
] }),
|
|
25875
|
+
/* @__PURE__ */ jsx89(
|
|
26106
25876
|
"button",
|
|
26107
25877
|
{
|
|
26108
|
-
|
|
26109
|
-
|
|
26110
|
-
|
|
26111
|
-
|
|
26112
|
-
|
|
26113
|
-
},
|
|
26114
|
-
disabled: isGenerating,
|
|
26115
|
-
children: [
|
|
26116
|
-
/* @__PURE__ */ jsx89(ModelIcon2, {}),
|
|
26117
|
-
/* @__PURE__ */ jsx89("span", { children: selectedModel }),
|
|
26118
|
-
/* @__PURE__ */ jsx89(ChevronDownIcon2, {})
|
|
26119
|
-
]
|
|
25878
|
+
onClick: () => setReferenceImages(
|
|
25879
|
+
(current) => current.filter((_, index) => index !== i)
|
|
25880
|
+
),
|
|
25881
|
+
title: "Remove",
|
|
25882
|
+
children: /* @__PURE__ */ jsx89(X2, { size: 10 })
|
|
26120
25883
|
}
|
|
26121
|
-
)
|
|
26122
|
-
|
|
25884
|
+
)
|
|
25885
|
+
] }, `${i}-${src.slice(-24)}`)) }),
|
|
25886
|
+
picker.pickingSlot && /* @__PURE__ */ jsxs49("div", { className: "chip-pick-hint", children: [
|
|
25887
|
+
/* @__PURE__ */ jsx89("span", { children: "Click an image or video on the canvas" }),
|
|
25888
|
+
/* @__PURE__ */ jsx89(
|
|
26123
25889
|
"button",
|
|
26124
25890
|
{
|
|
26125
|
-
className: "
|
|
26126
|
-
onClick:
|
|
26127
|
-
|
|
26128
|
-
|
|
26129
|
-
|
|
26130
|
-
|
|
26131
|
-
|
|
26132
|
-
|
|
26133
|
-
|
|
26134
|
-
|
|
26135
|
-
|
|
26136
|
-
|
|
26137
|
-
|
|
26138
|
-
|
|
26139
|
-
|
|
26140
|
-
|
|
26141
|
-
|
|
26142
|
-
|
|
26143
|
-
|
|
26144
|
-
|
|
26145
|
-
|
|
26146
|
-
|
|
26147
|
-
|
|
26148
|
-
|
|
26149
|
-
|
|
26150
|
-
|
|
26151
|
-
|
|
26152
|
-
|
|
26153
|
-
|
|
26154
|
-
|
|
26155
|
-
|
|
26156
|
-
|
|
26157
|
-
|
|
26158
|
-
|
|
26159
|
-
|
|
26160
|
-
|
|
26161
|
-
|
|
25891
|
+
className: "chip-pick-hint__cancel",
|
|
25892
|
+
onClick: picker.cancel,
|
|
25893
|
+
children: "Cancel"
|
|
25894
|
+
}
|
|
25895
|
+
)
|
|
25896
|
+
] }),
|
|
25897
|
+
picker.isResolving && /* @__PURE__ */ jsx89("div", { className: "chip-pick-hint", children: "Reading video frame\u2026" }),
|
|
25898
|
+
picker.error && /* @__PURE__ */ jsx89("div", { className: "chip-pick-error", children: picker.error }),
|
|
25899
|
+
/* @__PURE__ */ jsx89(
|
|
25900
|
+
PromptInputTextarea,
|
|
25901
|
+
{
|
|
25902
|
+
placeholder: "Describe your edit\u2026",
|
|
25903
|
+
className: "igp-textarea",
|
|
25904
|
+
disableAutosize: false
|
|
25905
|
+
}
|
|
25906
|
+
),
|
|
25907
|
+
generateError && /* @__PURE__ */ jsx89("div", { className: "igp-error", children: generateError }),
|
|
25908
|
+
/* @__PURE__ */ jsxs49(PromptInputActions, { className: "igp-actions", children: [
|
|
25909
|
+
/* @__PURE__ */ jsxs49("div", { className: "igp-actions-left", children: [
|
|
25910
|
+
/* @__PURE__ */ jsxs49("div", { className: "chip-slot", children: [
|
|
25911
|
+
/* @__PURE__ */ jsx89(
|
|
25912
|
+
PromptInputAction,
|
|
25913
|
+
{
|
|
25914
|
+
tooltip: referenceImages.length >= MAX_USER_REFERENCE_IMAGES ? `Maximum ${MAX_USER_REFERENCE_IMAGES} reference images` : "Add reference images",
|
|
25915
|
+
side: "top",
|
|
25916
|
+
children: /* @__PURE__ */ jsx89(
|
|
25917
|
+
"button",
|
|
25918
|
+
{
|
|
25919
|
+
className: `igp-btn igp-btn--icon${referenceImages.length > 0 ? " igp-btn--active" : ""}`,
|
|
25920
|
+
onClick: () => setChipMenu((open) => !open),
|
|
25921
|
+
disabled: isGenerating || referenceImages.length >= MAX_USER_REFERENCE_IMAGES,
|
|
25922
|
+
children: /* @__PURE__ */ jsx89(ImagePlus2, { size: 15 })
|
|
25923
|
+
}
|
|
25924
|
+
)
|
|
25925
|
+
}
|
|
25926
|
+
),
|
|
25927
|
+
chipMenu && /* @__PURE__ */ jsx89(
|
|
25928
|
+
ChipSourceMenu,
|
|
25929
|
+
{
|
|
25930
|
+
onClose: () => setChipMenu(false),
|
|
25931
|
+
onUpload: () => fileInputRef.current?.click(),
|
|
25932
|
+
onPickFromCanvas: () => picker.begin("reference", "imageOrVideo")
|
|
25933
|
+
}
|
|
25934
|
+
),
|
|
25935
|
+
picker.pendingVideo && /* @__PURE__ */ jsx89(
|
|
25936
|
+
VideoFrameChoiceMenu,
|
|
25937
|
+
{
|
|
25938
|
+
onChoose: picker.chooseVideoFrame,
|
|
25939
|
+
onCancel: picker.cancel
|
|
25940
|
+
}
|
|
25941
|
+
)
|
|
25942
|
+
] }),
|
|
25943
|
+
/* @__PURE__ */ jsxs49("div", { className: "igp-dropdown-root", ref: modelDropdownRef, children: [
|
|
25944
|
+
/* @__PURE__ */ jsx89(PromptInputAction, { tooltip: "Select model", side: "top", children: /* @__PURE__ */ jsxs49(
|
|
26162
25945
|
"button",
|
|
26163
25946
|
{
|
|
26164
|
-
className: "igp-
|
|
25947
|
+
className: "igp-btn",
|
|
26165
25948
|
onClick: () => {
|
|
26166
|
-
|
|
25949
|
+
setModelOpen((v) => !v);
|
|
25950
|
+
setRatioOpen(false);
|
|
26167
25951
|
setResolutionOpen(false);
|
|
26168
25952
|
},
|
|
25953
|
+
disabled: isGenerating,
|
|
25954
|
+
children: [
|
|
25955
|
+
/* @__PURE__ */ jsx89(ModelIcon2, {}),
|
|
25956
|
+
/* @__PURE__ */ jsx89("span", { children: selectedModel }),
|
|
25957
|
+
/* @__PURE__ */ jsx89(ChevronDownIcon2, {})
|
|
25958
|
+
]
|
|
25959
|
+
}
|
|
25960
|
+
) }),
|
|
25961
|
+
modelOpen && /* @__PURE__ */ jsx89("div", { className: "igp-dropdown igp-dropdown--up igp-dropdown--left", children: MODEL_NAMES.map((m) => /* @__PURE__ */ jsxs49(
|
|
25962
|
+
"button",
|
|
25963
|
+
{
|
|
25964
|
+
className: "igp-dropdown-item",
|
|
25965
|
+
onClick: () => {
|
|
25966
|
+
setSelectedModel(m);
|
|
25967
|
+
setModelOpen(false);
|
|
25968
|
+
},
|
|
26169
25969
|
children: [
|
|
26170
|
-
/* @__PURE__ */ jsx89("span", { style: { flex: 1 }, children:
|
|
26171
|
-
|
|
25970
|
+
/* @__PURE__ */ jsx89("span", { style: { flex: 1 }, children: m }),
|
|
25971
|
+
m === selectedModel && /* @__PURE__ */ jsx89("span", { className: "igp-check", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) })
|
|
26172
25972
|
]
|
|
26173
25973
|
},
|
|
26174
|
-
|
|
26175
|
-
)
|
|
26176
|
-
|
|
25974
|
+
m
|
|
25975
|
+
)) })
|
|
25976
|
+
] })
|
|
26177
25977
|
] }),
|
|
26178
|
-
/* @__PURE__ */ jsxs49("div", { className: "igp-
|
|
26179
|
-
/* @__PURE__ */ jsxs49(
|
|
25978
|
+
/* @__PURE__ */ jsxs49("div", { className: "igp-actions-right", children: [
|
|
25979
|
+
/* @__PURE__ */ jsxs49("div", { className: "igp-dropdown-root", ref: resolutionDropdownRef, children: [
|
|
25980
|
+
/* @__PURE__ */ jsxs49(
|
|
25981
|
+
"button",
|
|
25982
|
+
{
|
|
25983
|
+
className: "igp-btn igp-btn--compact",
|
|
25984
|
+
onClick: () => {
|
|
25985
|
+
if (availableResolutions.length <= 1) {
|
|
25986
|
+
return;
|
|
25987
|
+
}
|
|
25988
|
+
setResolutionOpen((v) => !v);
|
|
25989
|
+
setRatioOpen(false);
|
|
25990
|
+
setModelOpen(false);
|
|
25991
|
+
},
|
|
25992
|
+
disabled: isGenerating || availableResolutions.length <= 1,
|
|
25993
|
+
title: availableResolutions.length <= 1 ? "Fixed resolution for this model" : void 0,
|
|
25994
|
+
children: [
|
|
25995
|
+
/* @__PURE__ */ jsx89("span", { children: selectedResolution }),
|
|
25996
|
+
availableResolutions.length > 1 && /* @__PURE__ */ jsx89(ChevronDownIcon2, {})
|
|
25997
|
+
]
|
|
25998
|
+
}
|
|
25999
|
+
),
|
|
26000
|
+
resolutionOpen && availableResolutions.length > 1 && /* @__PURE__ */ jsx89("div", { className: "igp-dropdown igp-dropdown--up igp-dropdown--right", children: availableResolutions.map(
|
|
26001
|
+
(r) => /* @__PURE__ */ jsxs49(
|
|
26002
|
+
"button",
|
|
26003
|
+
{
|
|
26004
|
+
className: "igp-dropdown-item",
|
|
26005
|
+
onClick: () => {
|
|
26006
|
+
setSelectedResolution(r);
|
|
26007
|
+
setResolutionOpen(false);
|
|
26008
|
+
},
|
|
26009
|
+
children: [
|
|
26010
|
+
/* @__PURE__ */ jsx89("span", { style: { flex: 1 }, children: r }),
|
|
26011
|
+
r === selectedResolution && /* @__PURE__ */ jsx89("span", { className: "igp-check", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) })
|
|
26012
|
+
]
|
|
26013
|
+
},
|
|
26014
|
+
r
|
|
26015
|
+
)
|
|
26016
|
+
) })
|
|
26017
|
+
] }),
|
|
26018
|
+
/* @__PURE__ */ jsxs49("div", { className: "igp-dropdown-root", ref: ratioDropdownRef, children: [
|
|
26019
|
+
/* @__PURE__ */ jsxs49(
|
|
26020
|
+
"button",
|
|
26021
|
+
{
|
|
26022
|
+
className: "igp-btn igp-btn--compact",
|
|
26023
|
+
onClick: () => {
|
|
26024
|
+
setRatioOpen((v) => !v);
|
|
26025
|
+
setResolutionOpen(false);
|
|
26026
|
+
setModelOpen(false);
|
|
26027
|
+
},
|
|
26028
|
+
disabled: isGenerating,
|
|
26029
|
+
children: [
|
|
26030
|
+
/* @__PURE__ */ jsx89("span", { children: selectedRatio }),
|
|
26031
|
+
/* @__PURE__ */ jsx89(ChevronDownIcon2, {})
|
|
26032
|
+
]
|
|
26033
|
+
}
|
|
26034
|
+
),
|
|
26035
|
+
ratioOpen && /* @__PURE__ */ jsxs49("div", { className: "igp-dropdown igp-dropdown--up igp-dropdown--right igp-dropdown--ratio", children: [
|
|
26036
|
+
/* @__PURE__ */ jsxs49("div", { className: "igp-dropdown-header", children: [
|
|
26037
|
+
/* @__PURE__ */ jsx89("span", { children: "Output format" }),
|
|
26038
|
+
/* @__PURE__ */ jsx89(InfoIcon2, {})
|
|
26039
|
+
] }),
|
|
26040
|
+
availableRatios.map(
|
|
26041
|
+
(ratioLabel) => {
|
|
26042
|
+
const dims = getDimensions(
|
|
26043
|
+
selectedModel,
|
|
26044
|
+
ratioLabel,
|
|
26045
|
+
selectedResolution
|
|
26046
|
+
);
|
|
26047
|
+
return /* @__PURE__ */ jsxs49(
|
|
26048
|
+
"button",
|
|
26049
|
+
{
|
|
26050
|
+
className: "igp-dropdown-item",
|
|
26051
|
+
onClick: () => applyRatio(ratioLabel),
|
|
26052
|
+
children: [
|
|
26053
|
+
/* @__PURE__ */ jsx89(RatioShapeIcon2, { label: ratioLabel }),
|
|
26054
|
+
/* @__PURE__ */ jsx89("span", { style: { flex: 1 }, children: ratioLabel }),
|
|
26055
|
+
/* @__PURE__ */ jsxs49("span", { className: "igp-dims", children: [
|
|
26056
|
+
dims.width,
|
|
26057
|
+
"\xD7",
|
|
26058
|
+
dims.height
|
|
26059
|
+
] }),
|
|
26060
|
+
ratioLabel === selectedRatio && /* @__PURE__ */ jsx89("span", { className: "igp-check", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) })
|
|
26061
|
+
]
|
|
26062
|
+
},
|
|
26063
|
+
ratioLabel
|
|
26064
|
+
);
|
|
26065
|
+
}
|
|
26066
|
+
)
|
|
26067
|
+
] })
|
|
26068
|
+
] }),
|
|
26069
|
+
/* @__PURE__ */ jsx89(
|
|
26180
26070
|
"button",
|
|
26181
26071
|
{
|
|
26182
|
-
className: "igp-
|
|
26183
|
-
onClick:
|
|
26184
|
-
|
|
26185
|
-
|
|
26186
|
-
|
|
26187
|
-
},
|
|
26188
|
-
disabled: isGenerating,
|
|
26189
|
-
children: [
|
|
26190
|
-
/* @__PURE__ */ jsx89("span", { children: selectedRatio }),
|
|
26191
|
-
/* @__PURE__ */ jsx89(ChevronDownIcon2, {})
|
|
26192
|
-
]
|
|
26072
|
+
className: "igp-generate",
|
|
26073
|
+
onClick: isGenerating ? handleStop : handleGenerate,
|
|
26074
|
+
disabled: !isGenerating && !prompt.trim(),
|
|
26075
|
+
title: isGenerating ? "Stop generation" : "Generate edit",
|
|
26076
|
+
children: isGenerating ? /* @__PURE__ */ jsx89(SpinnerIcon3, {}) : /* @__PURE__ */ jsx89(ArrowUp2, { size: 16 })
|
|
26193
26077
|
}
|
|
26194
|
-
)
|
|
26195
|
-
|
|
26196
|
-
/* @__PURE__ */ jsxs49("div", { className: "igp-dropdown-header", children: [
|
|
26197
|
-
/* @__PURE__ */ jsx89("span", { children: "Output format" }),
|
|
26198
|
-
/* @__PURE__ */ jsx89(InfoIcon2, {})
|
|
26199
|
-
] }),
|
|
26200
|
-
availableRatios.map(
|
|
26201
|
-
(ratioLabel) => {
|
|
26202
|
-
const dims = getDimensions(
|
|
26203
|
-
selectedModel,
|
|
26204
|
-
ratioLabel,
|
|
26205
|
-
selectedResolution
|
|
26206
|
-
);
|
|
26207
|
-
return /* @__PURE__ */ jsxs49(
|
|
26208
|
-
"button",
|
|
26209
|
-
{
|
|
26210
|
-
className: "igp-dropdown-item",
|
|
26211
|
-
onClick: () => applyRatio(ratioLabel),
|
|
26212
|
-
children: [
|
|
26213
|
-
/* @__PURE__ */ jsx89(RatioShapeIcon2, { label: ratioLabel }),
|
|
26214
|
-
/* @__PURE__ */ jsx89("span", { style: { flex: 1 }, children: ratioLabel }),
|
|
26215
|
-
/* @__PURE__ */ jsxs49("span", { className: "igp-dims", children: [
|
|
26216
|
-
dims.width,
|
|
26217
|
-
"\xD7",
|
|
26218
|
-
dims.height
|
|
26219
|
-
] }),
|
|
26220
|
-
ratioLabel === selectedRatio && /* @__PURE__ */ jsx89("span", { className: "igp-check", children: /* @__PURE__ */ jsx89(CheckIcon3, {}) })
|
|
26221
|
-
]
|
|
26222
|
-
},
|
|
26223
|
-
ratioLabel
|
|
26224
|
-
);
|
|
26225
|
-
}
|
|
26226
|
-
)
|
|
26227
|
-
] })
|
|
26228
|
-
] }),
|
|
26229
|
-
/* @__PURE__ */ jsx89(
|
|
26230
|
-
"button",
|
|
26231
|
-
{
|
|
26232
|
-
className: "igp-generate",
|
|
26233
|
-
onClick: isGenerating ? handleStop : handleGenerate,
|
|
26234
|
-
disabled: !isGenerating && !prompt.trim(),
|
|
26235
|
-
title: isGenerating ? "Stop generation" : "Generate edit",
|
|
26236
|
-
children: isGenerating ? /* @__PURE__ */ jsx89(SpinnerIcon3, {}) : /* @__PURE__ */ jsx89(ArrowUp2, { size: 16 })
|
|
26237
|
-
}
|
|
26238
|
-
)
|
|
26078
|
+
)
|
|
26079
|
+
] })
|
|
26239
26080
|
] })
|
|
26240
|
-
]
|
|
26241
|
-
|
|
26242
|
-
|
|
26243
|
-
|
|
26081
|
+
]
|
|
26082
|
+
}
|
|
26083
|
+
)
|
|
26084
|
+
]
|
|
26244
26085
|
}
|
|
26245
26086
|
)
|
|
26246
26087
|
] });
|
|
@@ -30703,7 +30544,214 @@ import {
|
|
|
30703
30544
|
CaptureUpdateAction as CaptureUpdateAction39,
|
|
30704
30545
|
getElementAbsoluteCoords as getElementAbsoluteCoords12
|
|
30705
30546
|
} from "@orangecatai/element";
|
|
30706
|
-
import { ArrowUp as ArrowUp3, Volume2, X as
|
|
30547
|
+
import { ArrowUp as ArrowUp3, Volume2, X as X4 } from "lucide-react";
|
|
30548
|
+
|
|
30549
|
+
// utils/brandContextUtils.ts
|
|
30550
|
+
var SIZE_SCALE_MAP = {
|
|
30551
|
+
display: "48\u201372px",
|
|
30552
|
+
large: "32\u201348px",
|
|
30553
|
+
medium: "20\u201328px",
|
|
30554
|
+
small: "14\u201318px"
|
|
30555
|
+
};
|
|
30556
|
+
function buildBrandContextMessage(ctx) {
|
|
30557
|
+
const lines = [
|
|
30558
|
+
"## Brand Identity \u2014 you MUST apply every guideline below to all ads you create, by default"
|
|
30559
|
+
];
|
|
30560
|
+
if (ctx.colors) {
|
|
30561
|
+
const { primary, secondary, accent, background } = ctx.colors;
|
|
30562
|
+
const parts = [
|
|
30563
|
+
primary && `Primary: ${primary}`,
|
|
30564
|
+
secondary && `Secondary: ${secondary}`,
|
|
30565
|
+
accent && `Accent/CTA: ${accent}`,
|
|
30566
|
+
background && `Background: ${background}`
|
|
30567
|
+
].filter(Boolean);
|
|
30568
|
+
if (parts.length) {
|
|
30569
|
+
lines.push(`**Colors**: ${parts.join(", ")}`);
|
|
30570
|
+
}
|
|
30571
|
+
}
|
|
30572
|
+
if (ctx.typography) {
|
|
30573
|
+
const { headline, body } = ctx.typography;
|
|
30574
|
+
if (headline?.family) {
|
|
30575
|
+
const sizeHint = headline.sizeScale ? ` (suggested size: ${SIZE_SCALE_MAP[headline.sizeScale] ?? headline.sizeScale})` : "";
|
|
30576
|
+
const fontFileNote = headline.fontFamilyId ? ` \u2014 a brand font; match this typeface closely for the on-image text (use your judgment for which brand font suits headlines vs body copy)` : ` \u2014 render on-image text in a style that matches ${headline.family}`;
|
|
30577
|
+
lines.push(
|
|
30578
|
+
`**Headline font**: ${headline.family}${headline.weight ? ` weight ${headline.weight}` : ""}${sizeHint}${fontFileNote}`
|
|
30579
|
+
);
|
|
30580
|
+
}
|
|
30581
|
+
if (body?.family) {
|
|
30582
|
+
const sizeHint = body.sizeScale ? ` (suggested size: ${SIZE_SCALE_MAP[body.sizeScale] ?? body.sizeScale})` : "";
|
|
30583
|
+
const fontFileNote = body.fontFamilyId ? ` \u2014 a brand font; match this typeface closely for the on-image text (use your judgment for which brand font suits headlines vs body copy)` : ` \u2014 render on-image text in a style that matches ${body.family}`;
|
|
30584
|
+
lines.push(
|
|
30585
|
+
`**Body font**: ${body.family}${body.weight ? ` weight ${body.weight}` : ""}${sizeHint}${fontFileNote}`
|
|
30586
|
+
);
|
|
30587
|
+
}
|
|
30588
|
+
}
|
|
30589
|
+
if (ctx.visualStyle) {
|
|
30590
|
+
lines.push(`**Visual style**: ${ctx.visualStyle}`);
|
|
30591
|
+
}
|
|
30592
|
+
if (ctx.layoutPattern) {
|
|
30593
|
+
lines.push(`**Layout pattern**: ${ctx.layoutPattern}`);
|
|
30594
|
+
}
|
|
30595
|
+
if (ctx.toneOfVoice) {
|
|
30596
|
+
const { register: register2, vocabulary, ctaStyle, sentenceLength, person } = ctx.toneOfVoice;
|
|
30597
|
+
const parts = [
|
|
30598
|
+
register2 && `register: ${register2}`,
|
|
30599
|
+
vocabulary && `vocabulary: ${vocabulary}`,
|
|
30600
|
+
ctaStyle && `CTA style: ${ctaStyle}`,
|
|
30601
|
+
sentenceLength && `sentence length: ${sentenceLength}`,
|
|
30602
|
+
person && `person: ${person}`
|
|
30603
|
+
].filter(Boolean);
|
|
30604
|
+
if (parts.length) {
|
|
30605
|
+
lines.push(`**Tone of voice**: ${parts.join(", ")}`);
|
|
30606
|
+
}
|
|
30607
|
+
}
|
|
30608
|
+
if (ctx.imagery) {
|
|
30609
|
+
const {
|
|
30610
|
+
type,
|
|
30611
|
+
lighting,
|
|
30612
|
+
composition,
|
|
30613
|
+
subjects,
|
|
30614
|
+
grading,
|
|
30615
|
+
depthOfField,
|
|
30616
|
+
environment,
|
|
30617
|
+
negativeSpace
|
|
30618
|
+
} = ctx.imagery;
|
|
30619
|
+
const parts = [
|
|
30620
|
+
type && `type: ${type}`,
|
|
30621
|
+
subjects && `subjects: ${subjects}`,
|
|
30622
|
+
lighting && `lighting: ${lighting}`,
|
|
30623
|
+
grading && `grading: ${grading}`,
|
|
30624
|
+
depthOfField && `depth of field: ${depthOfField}`,
|
|
30625
|
+
environment && `environment: ${environment}`,
|
|
30626
|
+
negativeSpace && `negative space: ${negativeSpace}`,
|
|
30627
|
+
composition && `composition: ${composition}`
|
|
30628
|
+
].filter(Boolean);
|
|
30629
|
+
if (parts.length) {
|
|
30630
|
+
lines.push(`**Imagery direction**: ${parts.join(", ")}`);
|
|
30631
|
+
}
|
|
30632
|
+
}
|
|
30633
|
+
lines.push(
|
|
30634
|
+
"",
|
|
30635
|
+
"**Precedence**: these are defaults, not absolutes. If the user's request explicitly states or clearly implies something different from a guideline above \u2014 a different color, mood, style, subject treatment, or tone \u2014 follow the user's explicit instruction for that ad instead of the brand guideline it conflicts with. Do not silently override what the user asked for in favor of brand consistency; only apply a guideline where the user's request is silent on that point."
|
|
30636
|
+
);
|
|
30637
|
+
return lines.join("\n");
|
|
30638
|
+
}
|
|
30639
|
+
var clean = (value) => {
|
|
30640
|
+
const trimmed = value?.trim();
|
|
30641
|
+
return trimmed ? trimmed : void 0;
|
|
30642
|
+
};
|
|
30643
|
+
var PRECEDENCE_LINE = "The subject, action, and setting described at the top are authoritative. Apply this brand direction only where the prompt is silent; where they conflict, the prompt wins.";
|
|
30644
|
+
function buildVideoBrandPrompt(prompt, ctx, opts) {
|
|
30645
|
+
const lines = [];
|
|
30646
|
+
const brandName = clean(ctx.name);
|
|
30647
|
+
if (brandName) {
|
|
30648
|
+
lines.push(`This is a brand film for ${brandName}.`);
|
|
30649
|
+
}
|
|
30650
|
+
if (ctx.colors) {
|
|
30651
|
+
const primary = clean(ctx.colors.primary);
|
|
30652
|
+
const secondary = clean(ctx.colors.secondary);
|
|
30653
|
+
const accent = clean(ctx.colors.accent);
|
|
30654
|
+
const background = clean(ctx.colors.background);
|
|
30655
|
+
const parts = [
|
|
30656
|
+
primary && `dominant ${primary}`,
|
|
30657
|
+
secondary && `supporting ${secondary}`,
|
|
30658
|
+
accent && `${accent} reserved for accents and CTA moments`,
|
|
30659
|
+
background && `${background} for backgrounds and negative space`
|
|
30660
|
+
].filter(Boolean);
|
|
30661
|
+
if (parts.length) {
|
|
30662
|
+
lines.push(
|
|
30663
|
+
`Palette: ${parts.join(
|
|
30664
|
+
"; "
|
|
30665
|
+
)}. Grade the footage so these read as the natural colour story of the scene rather than as an overlay.`
|
|
30666
|
+
);
|
|
30667
|
+
}
|
|
30668
|
+
}
|
|
30669
|
+
const visualStyle = clean(ctx.visualStyle);
|
|
30670
|
+
if (visualStyle) {
|
|
30671
|
+
lines.push(`Look: ${visualStyle}.`);
|
|
30672
|
+
}
|
|
30673
|
+
if (ctx.imagery) {
|
|
30674
|
+
const {
|
|
30675
|
+
type,
|
|
30676
|
+
subjects,
|
|
30677
|
+
lighting,
|
|
30678
|
+
grading,
|
|
30679
|
+
depthOfField,
|
|
30680
|
+
environment,
|
|
30681
|
+
composition
|
|
30682
|
+
} = ctx.imagery;
|
|
30683
|
+
const parts = [
|
|
30684
|
+
clean(type) && `${clean(type)} footage`,
|
|
30685
|
+
clean(subjects) && `subjects: ${clean(subjects)}`,
|
|
30686
|
+
clean(lighting) && `lighting: ${clean(lighting)}`,
|
|
30687
|
+
clean(grading) && `grade: ${clean(grading)}`,
|
|
30688
|
+
clean(depthOfField) && `depth of field: ${clean(depthOfField)}`,
|
|
30689
|
+
clean(environment) && `environment: ${clean(environment)}`,
|
|
30690
|
+
clean(composition) && `framing: ${clean(composition)}`
|
|
30691
|
+
].filter(Boolean);
|
|
30692
|
+
if (parts.length) {
|
|
30693
|
+
lines.push(`Cinematography: ${parts.join(", ")}.`);
|
|
30694
|
+
}
|
|
30695
|
+
}
|
|
30696
|
+
if (ctx.toneOfVoice) {
|
|
30697
|
+
const { register: register2, vocabulary, ctaStyle, person } = ctx.toneOfVoice;
|
|
30698
|
+
const parts = [
|
|
30699
|
+
clean(register2),
|
|
30700
|
+
clean(vocabulary) && `${clean(vocabulary)} vocabulary`,
|
|
30701
|
+
clean(ctaStyle) && `${clean(ctaStyle)} calls to action`,
|
|
30702
|
+
clean(person)
|
|
30703
|
+
].filter(Boolean);
|
|
30704
|
+
if (parts.length) {
|
|
30705
|
+
lines.push(
|
|
30706
|
+
`Tone: ${parts.join(
|
|
30707
|
+
", "
|
|
30708
|
+
)} \u2014 applies to any narration, voiceover, or on-screen copy.`
|
|
30709
|
+
);
|
|
30710
|
+
}
|
|
30711
|
+
}
|
|
30712
|
+
const typefaces = [
|
|
30713
|
+
clean(ctx.typography?.headline?.family),
|
|
30714
|
+
clean(ctx.typography?.body?.family)
|
|
30715
|
+
].filter(
|
|
30716
|
+
(name, i, arr) => Boolean(name) && arr.indexOf(name) === i
|
|
30717
|
+
);
|
|
30718
|
+
if (typefaces.length) {
|
|
30719
|
+
lines.push(
|
|
30720
|
+
`On-screen text: keep to a minimum; if any appears it should read as ${typefaces.join(
|
|
30721
|
+
" or "
|
|
30722
|
+
)}, or a close match in spirit. No paragraphs of text.`
|
|
30723
|
+
);
|
|
30724
|
+
}
|
|
30725
|
+
const userReferenceCount = Math.max(0, opts?.userReferenceCount ?? 0);
|
|
30726
|
+
const hasLogo = Boolean(opts?.hasLogoReference && clean(ctx.logoDataUrl));
|
|
30727
|
+
if (hasLogo) {
|
|
30728
|
+
lines.push(
|
|
30729
|
+
userReferenceCount > 0 ? (
|
|
30730
|
+
// With user references present the logo is no longer first — the
|
|
30731
|
+
// manifest appended below states its actual position.
|
|
30732
|
+
"Brand logo: the brand logo is supplied as one of the attached reference images (see the manifest below). If it appears in frame, reproduce it verbatim \u2014 never redraw, restyle, recolour, or animate its glyphs."
|
|
30733
|
+
) : "Brand logo: the first reference image is the exact brand logo. If it appears in frame, reproduce it verbatim \u2014 never redraw, restyle, recolour, or animate its glyphs."
|
|
30734
|
+
);
|
|
30735
|
+
}
|
|
30736
|
+
const manifest = userReferenceCount > 0 ? `
|
|
30737
|
+
|
|
30738
|
+
${buildReferenceManifest(
|
|
30739
|
+
userReferenceCount,
|
|
30740
|
+
hasLogo ? ["the exact brand logo"] : []
|
|
30741
|
+
)}` : "";
|
|
30742
|
+
if (!lines.length) {
|
|
30743
|
+
return manifest ? `${prompt}${manifest}` : prompt;
|
|
30744
|
+
}
|
|
30745
|
+
const header = brandName ? `## Brand direction \u2014 ${brandName}` : "## Brand direction";
|
|
30746
|
+
return `${prompt}
|
|
30747
|
+
|
|
30748
|
+
${header}
|
|
30749
|
+
${lines.join(
|
|
30750
|
+
"\n"
|
|
30751
|
+
)}
|
|
30752
|
+
|
|
30753
|
+
${PRECEDENCE_LINE}${manifest}`;
|
|
30754
|
+
}
|
|
30707
30755
|
|
|
30708
30756
|
// utils/videoApi.ts
|
|
30709
30757
|
async function submitVideoJob(params, videoGenUrl) {
|
|
@@ -30948,7 +30996,7 @@ import {
|
|
|
30948
30996
|
useRef as useRef33,
|
|
30949
30997
|
useState as useState36
|
|
30950
30998
|
} from "react";
|
|
30951
|
-
import { Check, ChevronDown, Loader2, Square, X as
|
|
30999
|
+
import { Check, ChevronDown, Loader2, Square, X as X3 } from "lucide-react";
|
|
30952
31000
|
import { CaptureUpdateAction as CaptureUpdateAction38 } from "@orangecatai/element";
|
|
30953
31001
|
import { Fragment as Fragment17, jsx as jsx97, jsxs as jsxs54 } from "react/jsx-runtime";
|
|
30954
31002
|
var BEAT_LABELS = {
|
|
@@ -31296,7 +31344,7 @@ var VideoChainPanel = forwardRef6(
|
|
|
31296
31344
|
children: [
|
|
31297
31345
|
isRunning && /* @__PURE__ */ jsx97(Loader2, { className: "vgp-spinner", size: 13 }),
|
|
31298
31346
|
phase === "done" && /* @__PURE__ */ jsx97(Check, { size: 13 }),
|
|
31299
|
-
phase === "error" && /* @__PURE__ */ jsx97(
|
|
31347
|
+
phase === "error" && /* @__PURE__ */ jsx97(X3, { size: 13 }),
|
|
31300
31348
|
/* @__PURE__ */ jsx97("span", { className: "vgp-chain-summary-text", children: summaryText }),
|
|
31301
31349
|
isRunning && /* @__PURE__ */ jsx97(
|
|
31302
31350
|
"span",
|
|
@@ -31368,7 +31416,7 @@ var VideoChainPanel = forwardRef6(
|
|
|
31368
31416
|
"%"
|
|
31369
31417
|
] }),
|
|
31370
31418
|
segment.status === "failed" && /* @__PURE__ */ jsxs54(Fragment17, { children: [
|
|
31371
|
-
/* @__PURE__ */ jsx97(
|
|
31419
|
+
/* @__PURE__ */ jsx97(X3, { size: 13 }),
|
|
31372
31420
|
" Failed"
|
|
31373
31421
|
] }),
|
|
31374
31422
|
segment.status === "queued" && "Queued"
|
|
@@ -32538,7 +32586,7 @@ var VideoGeneratorPanel = ({
|
|
|
32538
32586
|
className: "vgp-chip-remove",
|
|
32539
32587
|
onClick: () => setFirstFrame(null),
|
|
32540
32588
|
disabled: isGenerating,
|
|
32541
|
-
children: /* @__PURE__ */ jsx98(
|
|
32589
|
+
children: /* @__PURE__ */ jsx98(X4, { size: 9 })
|
|
32542
32590
|
}
|
|
32543
32591
|
)
|
|
32544
32592
|
] }) : /* @__PURE__ */ jsxs55("div", { className: "chip-slot", children: [
|
|
@@ -32580,7 +32628,7 @@ var VideoGeneratorPanel = ({
|
|
|
32580
32628
|
className: "vgp-chip-remove",
|
|
32581
32629
|
onClick: () => setLastFrame(null),
|
|
32582
32630
|
disabled: isGenerating,
|
|
32583
|
-
children: /* @__PURE__ */ jsx98(
|
|
32631
|
+
children: /* @__PURE__ */ jsx98(X4, { size: 9 })
|
|
32584
32632
|
}
|
|
32585
32633
|
)
|
|
32586
32634
|
] }) : /* @__PURE__ */ jsxs55("div", { className: "chip-slot", children: [
|
|
@@ -32634,7 +32682,7 @@ var VideoGeneratorPanel = ({
|
|
|
32634
32682
|
(prev) => prev.filter((_, j) => j !== i)
|
|
32635
32683
|
),
|
|
32636
32684
|
disabled: isGenerating,
|
|
32637
|
-
children: /* @__PURE__ */ jsx98(
|
|
32685
|
+
children: /* @__PURE__ */ jsx98(X4, { size: 9 })
|
|
32638
32686
|
}
|
|
32639
32687
|
)
|
|
32640
32688
|
]
|
|
@@ -57227,7 +57275,7 @@ var polyfill_default = polyfill;
|
|
|
57227
57275
|
|
|
57228
57276
|
// components/StockImagePanel.tsx
|
|
57229
57277
|
import { useCallback as useCallback33, useEffect as useEffect67, useRef as useRef59, useState as useState59 } from "react";
|
|
57230
|
-
import { Loader2 as Loader22, Search, X as
|
|
57278
|
+
import { Loader2 as Loader22, Search, X as X5 } from "lucide-react";
|
|
57231
57279
|
import { nanoid as nanoid3 } from "nanoid";
|
|
57232
57280
|
import { newImageElement as newImageElement3 } from "@orangecatai/element";
|
|
57233
57281
|
import { Fragment as Fragment40, jsx as jsx190, jsxs as jsxs110 } from "react/jsx-runtime";
|
|
@@ -57595,7 +57643,7 @@ var StockImagePanel = ({
|
|
|
57595
57643
|
return /* @__PURE__ */ jsx190("div", { className: "sip", children: /* @__PURE__ */ jsxs110("div", { className: "sip-panel", children: [
|
|
57596
57644
|
/* @__PURE__ */ jsxs110("div", { className: "sip-header", children: [
|
|
57597
57645
|
/* @__PURE__ */ jsx190("span", { className: "sip-title", children: "Images" }),
|
|
57598
|
-
/* @__PURE__ */ jsx190("button", { className: "sip-icon-btn", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx190(
|
|
57646
|
+
/* @__PURE__ */ jsx190("button", { className: "sip-icon-btn", onClick: onClose, "aria-label": "Close", children: /* @__PURE__ */ jsx190(X5, { size: 15 }) })
|
|
57599
57647
|
] }),
|
|
57600
57648
|
/* @__PURE__ */ jsxs110("div", { className: "sip-tabs", children: [
|
|
57601
57649
|
/* @__PURE__ */ jsxs110(
|
|
@@ -57670,7 +57718,7 @@ var StockImagePanel = ({
|
|
|
57670
57718
|
className: "sip-search-clear",
|
|
57671
57719
|
onClick: handleClearQuery,
|
|
57672
57720
|
"aria-label": "Clear search",
|
|
57673
|
-
children: /* @__PURE__ */ jsx190(
|
|
57721
|
+
children: /* @__PURE__ */ jsx190(X5, { size: 11 })
|
|
57674
57722
|
}
|
|
57675
57723
|
)
|
|
57676
57724
|
] }),
|
|
@@ -57748,7 +57796,7 @@ var StockImagePanel = ({
|
|
|
57748
57796
|
className: "sip-search-clear",
|
|
57749
57797
|
onClick: handleLibraryClearQuery,
|
|
57750
57798
|
"aria-label": "Clear search",
|
|
57751
|
-
children: /* @__PURE__ */ jsx190(
|
|
57799
|
+
children: /* @__PURE__ */ jsx190(X5, { size: 11 })
|
|
57752
57800
|
}
|
|
57753
57801
|
)
|
|
57754
57802
|
] }),
|
|
@@ -58138,7 +58186,7 @@ import {
|
|
|
58138
58186
|
Plus,
|
|
58139
58187
|
Search as Search2,
|
|
58140
58188
|
Wrench,
|
|
58141
|
-
X as
|
|
58189
|
+
X as X6
|
|
58142
58190
|
} from "lucide-react";
|
|
58143
58191
|
|
|
58144
58192
|
// components/ai-chat/canvasTools.ts
|
|
@@ -63251,7 +63299,7 @@ var AIChatPanel = React70.forwardRef(
|
|
|
63251
63299
|
children: /* @__PURE__ */ jsx199(Plus, { size: 15 })
|
|
63252
63300
|
}
|
|
63253
63301
|
),
|
|
63254
|
-
/* @__PURE__ */ jsx199("button", { className: "acp-icon-btn", onClick: onClose, title: "Close", children: /* @__PURE__ */ jsx199(
|
|
63302
|
+
/* @__PURE__ */ jsx199("button", { className: "acp-icon-btn", onClick: onClose, title: "Close", children: /* @__PURE__ */ jsx199(X6, { size: 15 }) })
|
|
63255
63303
|
] }),
|
|
63256
63304
|
historyOpen && /* @__PURE__ */ jsxs112("div", { className: "acp-history-dropdown", children: [
|
|
63257
63305
|
/* @__PURE__ */ jsxs112("div", { className: "acp-history-search", children: [
|
|
@@ -63435,7 +63483,7 @@ var AIChatPanel = React70.forwardRef(
|
|
|
63435
63483
|
className: "acp-ref-remove",
|
|
63436
63484
|
onClick: handleRemoveRef,
|
|
63437
63485
|
title: "Remove reference",
|
|
63438
|
-
children: /* @__PURE__ */ jsx199(
|
|
63486
|
+
children: /* @__PURE__ */ jsx199(X6, { size: 10 })
|
|
63439
63487
|
}
|
|
63440
63488
|
)
|
|
63441
63489
|
] }) }),
|
|
@@ -63455,7 +63503,7 @@ var AIChatPanel = React70.forwardRef(
|
|
|
63455
63503
|
className: "acp-attachment-remove",
|
|
63456
63504
|
onClick: () => handleRemoveFile(f.id),
|
|
63457
63505
|
title: "Remove file",
|
|
63458
|
-
children: /* @__PURE__ */ jsx199(
|
|
63506
|
+
children: /* @__PURE__ */ jsx199(X6, { size: 10 })
|
|
63459
63507
|
}
|
|
63460
63508
|
)
|
|
63461
63509
|
] }, f.id)) }),
|