@interware/content-generator 0.7.1 → 0.7.2

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.
@@ -5,8 +5,8 @@ import { P as PluginProviders } from "./PluginProviders-DWMpcAIh.mjs";
5
5
  import { useMemo, useState, useEffect, useRef, useCallback } from "react";
6
6
  import { Box, Flex, Typography, Button, Badge, TextInput, Loader, Table, Thead, Tr, Th, VisuallyHidden, Tbody, Td, TextButton, IconButton, Link, LinkButton, Field, Radio, Modal, Textarea, Combobox, ComboboxOption, Toggle, Grid } from "@strapi/design-system";
7
7
  import { Plus, Search, Check, Pencil, ExternalLink, ArrowLeft, Image, Clock, WarningCircle, Trash, Sparkle, PlusCircle } from "@strapi/icons";
8
- import { P as PLUGIN_ID, S as STUDIO_PATH, p as pluginPermissions } from "./index-D67xWUPz.mjs";
9
- import { L as LibraryImagePicker, P as PromptComposer, a as LEGACY_ROUTES, S as StudioRedirect, l as legacyRedirect } from "./ImageStudioTabs-B-mOwDfY.mjs";
8
+ import { P as PLUGIN_ID, S as STUDIO_PATH, p as pluginPermissions } from "./index-D6UAvh53.mjs";
9
+ import { L as LibraryImagePicker, P as PromptComposer, a as LEGACY_ROUTES, S as StudioRedirect, l as legacyRedirect } from "./ImageStudioTabs-Umf3GODW.mjs";
10
10
  import { useIntl } from "react-intl";
11
11
  import { useFormik } from "formik";
12
12
  import * as Yup from "yup";
@@ -7,8 +7,8 @@ const PluginProviders = require("./PluginProviders-D79TeGSE.js");
7
7
  const react = require("react");
8
8
  const designSystem = require("@strapi/design-system");
9
9
  const icons = require("@strapi/icons");
10
- const index = require("./index-NA9OuMGs.js");
11
- const ImageStudioTabs = require("./ImageStudioTabs-CG4KTn1S.js");
10
+ const index = require("./index-C2s9Jhcc.js");
11
+ const ImageStudioTabs = require("./ImageStudioTabs-BFEF9ggK.js");
12
12
  const reactIntl = require("react-intl");
13
13
  const formik = require("formik");
14
14
  const Yup = require("yup");
@@ -2,7 +2,7 @@
2
2
  const jsxRuntime = require("react/jsx-runtime");
3
3
  const designSystem = require("@strapi/design-system");
4
4
  const reactRouterDom = require("react-router-dom");
5
- const index = require("./index-NA9OuMGs.js");
5
+ const index = require("./index-C2s9Jhcc.js");
6
6
  const react = require("react");
7
7
  const icons = require("@strapi/icons");
8
8
  const styledComponents = require("styled-components");
@@ -740,6 +740,9 @@ const RemoveBackgroundButton = ({ src, onDone }) => {
740
740
  )
741
741
  ] });
742
742
  };
743
+ const IMAGE_MAX_MB = 30;
744
+ const IMAGE_MAX_BYTES = IMAGE_MAX_MB * 1024 * 1024;
745
+ const IMAGE_FORMATS_HINT = `PNG, JPG o WEBP de hasta ${IMAGE_MAX_MB} MB.`;
743
746
  const NameDialog = ({ open, title, label, initial = "", confirmLabel, validate, onClose, onConfirm }) => {
744
747
  const [name, setName] = react.useState(initial);
745
748
  const [error, setError] = react.useState(null);
@@ -1253,7 +1256,10 @@ const EditEmpty = ({ disabled, onUpload, onOpenLibrary, onOpenRecent }) => {
1253
1256
  style: { width: "100%", maxWidth: 600, border: `2px dashed ${over ? c.primary600 : c.neutral200}` },
1254
1257
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "center", gap: 3, style: { textAlign: "center" }, children: [
1255
1258
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", tag: "h2", children: "Elige la imagen que quieres editar" }),
1256
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: "Arrástrala aquí, súbela o elígela de la biblioteca. PNG, JPG o WEBP de hasta 10 MB." }),
1259
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { textColor: "neutral600", children: [
1260
+ "Arrástrala aquí, súbela o elígela de la biblioteca. ",
1261
+ IMAGE_FORMATS_HINT
1262
+ ] }),
1257
1263
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 3, paddingTop: 2, children: [
1258
1264
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Upload, {}), disabled, onClick: () => input.current?.click(), children: "Subir imagen" }),
1259
1265
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { startIcon: /* @__PURE__ */ jsxRuntime.jsx(icons.Folder, {}), disabled, onClick: onOpenLibrary, children: "Elegir de la biblioteca" })
@@ -1328,7 +1334,7 @@ const ReferencePicker = ({
1328
1334
  onChange,
1329
1335
  onPickFromLibrary,
1330
1336
  label = "Imágenes de referencia",
1331
- hint = "PNG, JPG o WEBP de hasta 10 MB.",
1337
+ hint = IMAGE_FORMATS_HINT,
1332
1338
  noun = REFERENCES
1333
1339
  }) => {
1334
1340
  const input = react.useRef(null);
@@ -1522,8 +1528,8 @@ const GeneratorTab = () => {
1522
1528
  };
1523
1529
  const uploadBase = (file) => {
1524
1530
  if (!file) return;
1525
- if (!IMAGE_MIMES.includes(file.type) || file.size > 10 * 1024 * 1024) {
1526
- notify("warning", "Usa una imagen PNG, JPG o WEBP de hasta 10 MB.");
1531
+ if (!IMAGE_MIMES.includes(file.type) || file.size > IMAGE_MAX_BYTES) {
1532
+ notify("warning", `Usa una imagen ${IMAGE_FORMATS_HINT}`);
1527
1533
  return;
1528
1534
  }
1529
1535
  const reader = new FileReader();
@@ -1598,7 +1604,7 @@ const GeneratorTab = () => {
1598
1604
  ReferencePicker,
1599
1605
  {
1600
1606
  label: "Referencias de estilo",
1601
- hint: "Guían el estilo, no se copian. PNG, JPG o WEBP de hasta 10 MB.",
1607
+ hint: `Guían el estilo, no se copian. ${IMAGE_FORMATS_HINT}`,
1602
1608
  files: references,
1603
1609
  max: model?.maxReferences ?? 0,
1604
1610
  modelLabel: model?.label ?? "Este modelo",
@@ -2187,17 +2193,6 @@ const LibraryTab = () => {
2187
2193
  /* @__PURE__ */ jsxRuntime.jsx(RemoveBackgroundDialog, { open: !!bgTarget, src: bgTarget?.src ?? "", onClose: () => setBgTarget(null), onApply: saveNoBackground })
2188
2194
  ] });
2189
2195
  };
2190
- const PALETTE = [
2191
- { label: "Navy", value: "#1F2A44" },
2192
- { label: "Rojo", value: "#E4002B" },
2193
- { label: "Teal", value: "#00C7B1" },
2194
- { label: "Teal suave", value: "#92CFC7" },
2195
- { label: "Amarillo", value: "#FFC844" },
2196
- { label: "Amarillo suave", value: "#F8DF8D" },
2197
- { label: "Gris", value: "#5B6473" },
2198
- { label: "Papel", value: "#EEF1F5" },
2199
- { label: "Blanco", value: "#FFFFFF" }
2200
- ];
2201
2196
  const NAVY = "#1F2A44";
2202
2197
  const RED$1 = "#E4002B";
2203
2198
  const TEAL$1 = "#00C7B1";
@@ -3937,44 +3932,63 @@ const SaveTemplateDialog = ({ open, defaultName, defaultFolder, folders, onClose
3937
3932
  ] })
3938
3933
  ] }) });
3939
3934
  };
3935
+ const parseHex = (raw) => {
3936
+ const hex = raw.trim().replace(/^#/, "");
3937
+ if (/^[0-9a-f]{3}$/i.test(hex)) return `#${[...hex].map((c) => c + c).join("")}`.toUpperCase();
3938
+ if (/^[0-9a-f]{6}$/i.test(hex)) return `#${hex}`.toUpperCase();
3939
+ return null;
3940
+ };
3940
3941
  const ColorField = ({ label, value, onChange }) => {
3941
3942
  const tc = useThemeColors();
3943
+ const current = parseHex(value ?? "") ?? "#000000";
3944
+ const [draft, setDraft] = react.useState(current);
3945
+ react.useEffect(() => setDraft((d) => parseHex(d) === current ? d : current), [current]);
3946
+ const apply = (text) => {
3947
+ const hex = parseHex(text);
3948
+ if (hex && hex !== current) onChange(hex);
3949
+ };
3950
+ const typeHex = (text) => {
3951
+ setDraft(text);
3952
+ if (text.trim().replace(/^#/, "").length === 6) apply(text);
3953
+ };
3954
+ const leave = () => {
3955
+ apply(draft);
3956
+ setDraft(parseHex(draft) ?? current);
3957
+ };
3942
3958
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 1, children: [
3943
3959
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
3944
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, wrap: "wrap", alignItems: "center", children: [
3945
- PALETTE.map((c) => {
3946
- const active = value?.toUpperCase() === c.value;
3947
- return /* @__PURE__ */ jsxRuntime.jsx(
3948
- designSystem.Box,
3949
- {
3950
- tag: "button",
3951
- color: "neutral800",
3952
- type: "button",
3953
- "aria-label": `${label}: ${c.label}`,
3954
- "aria-pressed": active,
3955
- title: c.label,
3956
- onClick: () => onChange(c.value),
3957
- style: {
3958
- width: 22,
3959
- height: 22,
3960
- borderRadius: 4,
3961
- cursor: "pointer",
3962
- background: c.value,
3963
- border: active ? `2px solid ${tc.primary600}` : `1px solid ${tc.neutral200}`,
3964
- padding: 0
3965
- }
3966
- },
3967
- c.value
3968
- );
3969
- }),
3960
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, alignItems: "center", children: [
3970
3961
  /* @__PURE__ */ jsxRuntime.jsx(
3971
3962
  "input",
3972
3963
  {
3973
3964
  type: "color",
3974
- "aria-label": `${label} personalizado`,
3975
- value: /^#[0-9a-f]{6}$/i.test(value ?? "") ? value : "#000000",
3965
+ "aria-label": `${label}: selector`,
3966
+ title: "Abrir selector de color",
3967
+ value: current.toLowerCase(),
3976
3968
  onChange: (e) => onChange(e.target.value.toUpperCase()),
3977
- style: { width: 26, height: 26, border: "none", padding: 0, background: "none", cursor: "pointer" }
3969
+ style: {
3970
+ flexShrink: 0,
3971
+ width: 32,
3972
+ height: 32,
3973
+ padding: 2,
3974
+ borderRadius: 4,
3975
+ cursor: "pointer",
3976
+ border: `1px solid ${tc.neutral200}`,
3977
+ background: tc.neutral0
3978
+ }
3979
+ }
3980
+ ),
3981
+ /* @__PURE__ */ jsxRuntime.jsx(
3982
+ designSystem.TextInput,
3983
+ {
3984
+ "aria-label": `${label}: hexadecimal`,
3985
+ size: "S",
3986
+ value: draft,
3987
+ placeholder: "#1F2A44",
3988
+ maxLength: 7,
3989
+ spellCheck: false,
3990
+ onChange: (e) => typeHex(e.target.value),
3991
+ onBlur: leave
3978
3992
  }
3979
3993
  )
3980
3994
  ] })
@@ -1,7 +1,7 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { Modal, Flex, Button, Loader, Typography, Grid, Box, lightTheme, Checkbox, Field, TextInput, Dialog, SingleSelect, SingleSelectOption, Link, Badge, IconButtonGroup, IconButton, Toggle, Menu, NumberInput, Divider, Textarea, Tabs } from "@strapi/design-system";
3
3
  import { useLocation, Navigate, useSearchParams } from "react-router-dom";
4
- import { S as STUDIO_PATH } from "./index-D67xWUPz.mjs";
4
+ import { S as STUDIO_PATH } from "./index-D6UAvh53.mjs";
5
5
  import { useMemo, useState, useEffect, useId, useRef, useReducer, useCallback, useSyncExternalStore, useLayoutEffect, memo, forwardRef } from "react";
6
6
  import { ChevronRight, Folder, Magic, Pencil, Upload, Sparkle, Plus, Cross, Download, ArrowClockwise, House, ChevronDown, FilePdf, File as File$1, More, Trash, User, Star, SquaresFour, Quotes, PriceTag, Paragraph, NumberList, Minus, Italic, Image as Image$1, HeadingTwo, HeadingOne, Hashtag, Feather, Drag, BulletList, ArrowLeft, Check, ArrowsCounterClockwise, ArrowLineLeft, ArrowLineRight, Expand, WarningCircle, Play, Phone, Mail, PinMap, Earth, PresentationChart, ChartPie, ChartBubble, Cog, Database, Cloud, Globe, Server, Lightbulb, Crown, SealCheck, Briefcase, Rocket, Shield, CheckCircle, Lightning, Heart, Collapse, Bold, ArrowUp, ArrowDown, Duplicate, Lock, EyeStriked, Eye } from "@strapi/icons";
7
7
  import { useTheme } from "styled-components";
@@ -737,6 +737,9 @@ const RemoveBackgroundButton = ({ src, onDone }) => {
737
737
  )
738
738
  ] });
739
739
  };
740
+ const IMAGE_MAX_MB = 30;
741
+ const IMAGE_MAX_BYTES = IMAGE_MAX_MB * 1024 * 1024;
742
+ const IMAGE_FORMATS_HINT = `PNG, JPG o WEBP de hasta ${IMAGE_MAX_MB} MB.`;
740
743
  const NameDialog = ({ open, title, label, initial = "", confirmLabel, validate, onClose, onConfirm }) => {
741
744
  const [name, setName] = useState(initial);
742
745
  const [error, setError] = useState(null);
@@ -1250,7 +1253,10 @@ const EditEmpty = ({ disabled, onUpload, onOpenLibrary, onOpenRecent }) => {
1250
1253
  style: { width: "100%", maxWidth: 600, border: `2px dashed ${over ? c.primary600 : c.neutral200}` },
1251
1254
  children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 3, style: { textAlign: "center" }, children: [
1252
1255
  /* @__PURE__ */ jsx(Typography, { variant: "beta", tag: "h2", children: "Elige la imagen que quieres editar" }),
1253
- /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: "Arrástrala aquí, súbela o elígela de la biblioteca. PNG, JPG o WEBP de hasta 10 MB." }),
1256
+ /* @__PURE__ */ jsxs(Typography, { textColor: "neutral600", children: [
1257
+ "Arrástrala aquí, súbela o elígela de la biblioteca. ",
1258
+ IMAGE_FORMATS_HINT
1259
+ ] }),
1254
1260
  /* @__PURE__ */ jsxs(Flex, { gap: 3, paddingTop: 2, children: [
1255
1261
  /* @__PURE__ */ jsx(Button, { variant: "tertiary", startIcon: /* @__PURE__ */ jsx(Upload, {}), disabled, onClick: () => input.current?.click(), children: "Subir imagen" }),
1256
1262
  /* @__PURE__ */ jsx(Button, { startIcon: /* @__PURE__ */ jsx(Folder, {}), disabled, onClick: onOpenLibrary, children: "Elegir de la biblioteca" })
@@ -1325,7 +1331,7 @@ const ReferencePicker = ({
1325
1331
  onChange,
1326
1332
  onPickFromLibrary,
1327
1333
  label = "Imágenes de referencia",
1328
- hint = "PNG, JPG o WEBP de hasta 10 MB.",
1334
+ hint = IMAGE_FORMATS_HINT,
1329
1335
  noun = REFERENCES
1330
1336
  }) => {
1331
1337
  const input = useRef(null);
@@ -1519,8 +1525,8 @@ const GeneratorTab = () => {
1519
1525
  };
1520
1526
  const uploadBase = (file) => {
1521
1527
  if (!file) return;
1522
- if (!IMAGE_MIMES.includes(file.type) || file.size > 10 * 1024 * 1024) {
1523
- notify("warning", "Usa una imagen PNG, JPG o WEBP de hasta 10 MB.");
1528
+ if (!IMAGE_MIMES.includes(file.type) || file.size > IMAGE_MAX_BYTES) {
1529
+ notify("warning", `Usa una imagen ${IMAGE_FORMATS_HINT}`);
1524
1530
  return;
1525
1531
  }
1526
1532
  const reader = new FileReader();
@@ -1595,7 +1601,7 @@ const GeneratorTab = () => {
1595
1601
  ReferencePicker,
1596
1602
  {
1597
1603
  label: "Referencias de estilo",
1598
- hint: "Guían el estilo, no se copian. PNG, JPG o WEBP de hasta 10 MB.",
1604
+ hint: `Guían el estilo, no se copian. ${IMAGE_FORMATS_HINT}`,
1599
1605
  files: references,
1600
1606
  max: model?.maxReferences ?? 0,
1601
1607
  modelLabel: model?.label ?? "Este modelo",
@@ -2184,17 +2190,6 @@ const LibraryTab = () => {
2184
2190
  /* @__PURE__ */ jsx(RemoveBackgroundDialog, { open: !!bgTarget, src: bgTarget?.src ?? "", onClose: () => setBgTarget(null), onApply: saveNoBackground })
2185
2191
  ] });
2186
2192
  };
2187
- const PALETTE = [
2188
- { label: "Navy", value: "#1F2A44" },
2189
- { label: "Rojo", value: "#E4002B" },
2190
- { label: "Teal", value: "#00C7B1" },
2191
- { label: "Teal suave", value: "#92CFC7" },
2192
- { label: "Amarillo", value: "#FFC844" },
2193
- { label: "Amarillo suave", value: "#F8DF8D" },
2194
- { label: "Gris", value: "#5B6473" },
2195
- { label: "Papel", value: "#EEF1F5" },
2196
- { label: "Blanco", value: "#FFFFFF" }
2197
- ];
2198
2193
  const NAVY = "#1F2A44";
2199
2194
  const RED$1 = "#E4002B";
2200
2195
  const TEAL$1 = "#00C7B1";
@@ -3934,44 +3929,63 @@ const SaveTemplateDialog = ({ open, defaultName, defaultFolder, folders, onClose
3934
3929
  ] })
3935
3930
  ] }) });
3936
3931
  };
3932
+ const parseHex = (raw) => {
3933
+ const hex = raw.trim().replace(/^#/, "");
3934
+ if (/^[0-9a-f]{3}$/i.test(hex)) return `#${[...hex].map((c) => c + c).join("")}`.toUpperCase();
3935
+ if (/^[0-9a-f]{6}$/i.test(hex)) return `#${hex}`.toUpperCase();
3936
+ return null;
3937
+ };
3937
3938
  const ColorField = ({ label, value, onChange }) => {
3938
3939
  const tc = useThemeColors();
3940
+ const current = parseHex(value ?? "") ?? "#000000";
3941
+ const [draft, setDraft] = useState(current);
3942
+ useEffect(() => setDraft((d) => parseHex(d) === current ? d : current), [current]);
3943
+ const apply = (text) => {
3944
+ const hex = parseHex(text);
3945
+ if (hex && hex !== current) onChange(hex);
3946
+ };
3947
+ const typeHex = (text) => {
3948
+ setDraft(text);
3949
+ if (text.trim().replace(/^#/, "").length === 6) apply(text);
3950
+ };
3951
+ const leave = () => {
3952
+ apply(draft);
3953
+ setDraft(parseHex(draft) ?? current);
3954
+ };
3939
3955
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 1, children: [
3940
3956
  /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", textColor: "neutral800", children: label }),
3941
- /* @__PURE__ */ jsxs(Flex, { gap: 1, wrap: "wrap", alignItems: "center", children: [
3942
- PALETTE.map((c) => {
3943
- const active = value?.toUpperCase() === c.value;
3944
- return /* @__PURE__ */ jsx(
3945
- Box,
3946
- {
3947
- tag: "button",
3948
- color: "neutral800",
3949
- type: "button",
3950
- "aria-label": `${label}: ${c.label}`,
3951
- "aria-pressed": active,
3952
- title: c.label,
3953
- onClick: () => onChange(c.value),
3954
- style: {
3955
- width: 22,
3956
- height: 22,
3957
- borderRadius: 4,
3958
- cursor: "pointer",
3959
- background: c.value,
3960
- border: active ? `2px solid ${tc.primary600}` : `1px solid ${tc.neutral200}`,
3961
- padding: 0
3962
- }
3963
- },
3964
- c.value
3965
- );
3966
- }),
3957
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, alignItems: "center", children: [
3967
3958
  /* @__PURE__ */ jsx(
3968
3959
  "input",
3969
3960
  {
3970
3961
  type: "color",
3971
- "aria-label": `${label} personalizado`,
3972
- value: /^#[0-9a-f]{6}$/i.test(value ?? "") ? value : "#000000",
3962
+ "aria-label": `${label}: selector`,
3963
+ title: "Abrir selector de color",
3964
+ value: current.toLowerCase(),
3973
3965
  onChange: (e) => onChange(e.target.value.toUpperCase()),
3974
- style: { width: 26, height: 26, border: "none", padding: 0, background: "none", cursor: "pointer" }
3966
+ style: {
3967
+ flexShrink: 0,
3968
+ width: 32,
3969
+ height: 32,
3970
+ padding: 2,
3971
+ borderRadius: 4,
3972
+ cursor: "pointer",
3973
+ border: `1px solid ${tc.neutral200}`,
3974
+ background: tc.neutral0
3975
+ }
3976
+ }
3977
+ ),
3978
+ /* @__PURE__ */ jsx(
3979
+ TextInput,
3980
+ {
3981
+ "aria-label": `${label}: hexadecimal`,
3982
+ size: "S",
3983
+ value: draft,
3984
+ placeholder: "#1F2A44",
3985
+ maxLength: 7,
3986
+ spellCheck: false,
3987
+ onChange: (e) => typeHex(e.target.value),
3988
+ onBlur: leave
3975
3989
  }
3976
3990
  )
3977
3991
  ] })
@@ -5,7 +5,7 @@ import { useCallback, useState, useEffect } from "react";
5
5
  import { Box, Grid, Field, Flex, Button, Typography, Textarea } from "@strapi/design-system";
6
6
  import { Formik } from "formik";
7
7
  import { P as PluginProviders } from "./PluginProviders-DWMpcAIh.mjs";
8
- import { P as PLUGIN_ID } from "./index-D67xWUPz.mjs";
8
+ import { P as PLUGIN_ID } from "./index-D6UAvh53.mjs";
9
9
  const useSettings = () => {
10
10
  const { get, post, del } = useFetchClient();
11
11
  const getSettings = useCallback(
@@ -7,7 +7,7 @@ const react = require("react");
7
7
  const designSystem = require("@strapi/design-system");
8
8
  const formik = require("formik");
9
9
  const PluginProviders = require("./PluginProviders-D79TeGSE.js");
10
- const index = require("./index-NA9OuMGs.js");
10
+ const index = require("./index-C2s9Jhcc.js");
11
11
  const useSettings = () => {
12
12
  const { get, post, del } = admin.useFetchClient();
13
13
  const getSettings = react.useCallback(
@@ -2,9 +2,9 @@ import { jsxs, jsx } from "react/jsx-runtime";
2
2
  import { Page } from "@strapi/strapi/admin";
3
3
  import { Routes, Route } from "react-router-dom";
4
4
  import { P as PluginProviders } from "./PluginProviders-DWMpcAIh.mjs";
5
- import { p as pluginPermissions } from "./index-D67xWUPz.mjs";
5
+ import { p as pluginPermissions } from "./index-D6UAvh53.mjs";
6
6
  import { Box } from "@strapi/design-system";
7
- import { I as ImageStudioTabs } from "./ImageStudioTabs-B-mOwDfY.mjs";
7
+ import { I as ImageStudioTabs } from "./ImageStudioTabs-Umf3GODW.mjs";
8
8
  const ImageStudio = () => /* @__PURE__ */ jsxs(Page.Main, { children: [
9
9
  /* @__PURE__ */ jsx(Page.Title, { children: "Estudio de imágenes" }),
10
10
  /* @__PURE__ */ jsx(Box, { style: { height: "100vh" }, children: /* @__PURE__ */ jsx(ImageStudioTabs, {}) })
@@ -4,9 +4,9 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const admin = require("@strapi/strapi/admin");
5
5
  const reactRouterDom = require("react-router-dom");
6
6
  const PluginProviders = require("./PluginProviders-D79TeGSE.js");
7
- const index = require("./index-NA9OuMGs.js");
7
+ const index = require("./index-C2s9Jhcc.js");
8
8
  const designSystem = require("@strapi/design-system");
9
- const ImageStudioTabs = require("./ImageStudioTabs-CG4KTn1S.js");
9
+ const ImageStudioTabs = require("./ImageStudioTabs-BFEF9ggK.js");
10
10
  const ImageStudio = () => /* @__PURE__ */ jsxRuntime.jsxs(admin.Page.Main, { children: [
11
11
  /* @__PURE__ */ jsxRuntime.jsx(admin.Page.Title, { children: "Estudio de imágenes" }),
12
12
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { height: "100vh" }, children: /* @__PURE__ */ jsxRuntime.jsx(ImageStudioTabs.ImageStudioTabs, {}) })
@@ -57,7 +57,7 @@ const index = {
57
57
  defaultMessage: "Generador de contenido"
58
58
  },
59
59
  Component: async () => {
60
- const { App } = await Promise.resolve().then(() => require("./App-Cwr5ra5m.js"));
60
+ const { App } = await Promise.resolve().then(() => require("./App-ugsCmlsC.js"));
61
61
  return App;
62
62
  },
63
63
  permissions: [
@@ -72,7 +72,7 @@ const index = {
72
72
  defaultMessage: "Estudio de imágenes"
73
73
  },
74
74
  Component: async () => {
75
- const { StudioApp } = await Promise.resolve().then(() => require("./StudioApp-_ViSAwCm.js"));
75
+ const { StudioApp } = await Promise.resolve().then(() => require("./StudioApp-DoC0z4eh.js"));
76
76
  return StudioApp;
77
77
  },
78
78
  permissions: [
@@ -92,7 +92,7 @@ const index = {
92
92
  defaultMessage: PLUGIN_ID
93
93
  },
94
94
  Component: async () => {
95
- const component = await Promise.resolve().then(() => require("./Settings-D4NGBTk1.js"));
95
+ const component = await Promise.resolve().then(() => require("./Settings-Sk78JUBS.js"));
96
96
  return component.default;
97
97
  },
98
98
  to: `plugins/${PLUGIN_ID}/settings`,
@@ -56,7 +56,7 @@ const index = {
56
56
  defaultMessage: "Generador de contenido"
57
57
  },
58
58
  Component: async () => {
59
- const { App } = await import("./App-h4_txTsI.mjs");
59
+ const { App } = await import("./App-CTh6owSM.mjs");
60
60
  return App;
61
61
  },
62
62
  permissions: [
@@ -71,7 +71,7 @@ const index = {
71
71
  defaultMessage: "Estudio de imágenes"
72
72
  },
73
73
  Component: async () => {
74
- const { StudioApp } = await import("./StudioApp-xaEy-uIk.mjs");
74
+ const { StudioApp } = await import("./StudioApp-CrGn-9Gg.mjs");
75
75
  return StudioApp;
76
76
  },
77
77
  permissions: [
@@ -91,7 +91,7 @@ const index = {
91
91
  defaultMessage: PLUGIN_ID
92
92
  },
93
93
  Component: async () => {
94
- const component = await import("./Settings-BT-EqvXs.mjs");
94
+ const component = await import("./Settings-CdGW2O8h.mjs");
95
95
  return component.default;
96
96
  },
97
97
  to: `plugins/${PLUGIN_ID}/settings`,
@@ -1,3 +1,3 @@
1
1
  "use strict";
2
- const index = require("../_chunks/index-NA9OuMGs.js");
2
+ const index = require("../_chunks/index-C2s9Jhcc.js");
3
3
  module.exports = index.index;
@@ -1,4 +1,4 @@
1
- import { i } from "../_chunks/index-D67xWUPz.mjs";
1
+ import { i } from "../_chunks/index-D6UAvh53.mjs";
2
2
  export {
3
3
  i as default
4
4
  };
@@ -3,9 +3,11 @@ interface ColorFieldProps {
3
3
  value: string;
4
4
  onChange: (value: string) => void;
5
5
  }
6
+ /** «#0af», «0AF», «00aaff» o «#00AAFF» → «#00AAFF». Cualquier otra cosa → null. */
7
+ export declare const parseHex: (raw: string) => string | null;
6
8
  /**
7
- * Selector de color (snowflake: el DS no tiene uno). Muestras de la paleta InterWare y, para casos
8
- * puntuales, el selector nativo del navegador.
9
+ * Selector de color (snowflake: el DS no tiene uno). La muestra abre el selector de color del
10
+ * navegador y el campo acepta un hexadecimal escrito o pegado; solo se aplica cuando es válido.
9
11
  */
10
12
  export declare const ColorField: ({ label, value, onChange }: ColorFieldProps) => import("react/jsx-runtime").JSX.Element;
11
13
  export {};
@@ -1,6 +1,6 @@
1
1
  /**
2
- * Paleta InterWare (paleta canónica del brochure). Es la única que ofrecen las muestras del
3
- * editor y la única que usan las plantillas base.
2
+ * Paleta InterWare (paleta canónica del brochure). Es la única que usan las plantillas base; en el
3
+ * editor el color es libre (selector o hexadecimal).
4
4
  */
5
5
  export declare const PALETTE: readonly [{
6
6
  readonly label: "Navy";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Tope por imagen de referencia o a editar; lo comparten el panel y el servidor. Medido en Vertex
3
+ * (2026-10-07, `scripts/vertex-diag-size.mjs`): una imagen generada en 2K pesa ~8 MB y en 4K hasta
4
+ * ~24 MB, y Google aceptó editarla en línea pese a los 7 MB que dice su documentación. 30 MB deja
5
+ * iterar sobre una 4K con margen.
6
+ */
7
+ export declare const IMAGE_MAX_MB = 30;
8
+ export declare const IMAGE_MAX_BYTES: number;
9
+ export declare const IMAGE_FORMATS_HINT = "PNG, JPG o WEBP de hasta 30 MB.";
@@ -428,10 +428,11 @@ const imageStudio$1 = ({ strapi }) => createImageStudio(async () => {
428
428
  const { ai, backend } = await strapi.plugin("strapi-content-generator-gemini").service("service").geminiClient();
429
429
  return { models: ai.models, backend };
430
430
  });
431
+ const IMAGE_MAX_MB = 30;
432
+ const IMAGE_MAX_BYTES = IMAGE_MAX_MB * 1024 * 1024;
431
433
  class InputError extends Error {
432
434
  }
433
435
  const ALLOWED = ["image/png", "image/jpeg", "image/webp"];
434
- const MAX_BYTES = 10 * 1024 * 1024;
435
436
  const str = (v) => typeof v === "string" ? v : "";
436
437
  const bool = (v) => v === true || v === "true";
437
438
  const list = (v) => v ? Array.isArray(v) ? v : [v] : [];
@@ -442,7 +443,7 @@ const clean = (text2, labels) => {
442
443
  };
443
444
  const checkImage = (f) => {
444
445
  if (!ALLOWED.includes(f.mimetype ?? "")) throw new InputError("Las imágenes deben ser PNG, JPG o WEBP.");
445
- if (f.size > MAX_BYTES) throw new InputError("Cada imagen puede pesar hasta 10 MB.");
446
+ if (f.size > IMAGE_MAX_BYTES) throw new InputError(`Cada imagen puede pesar hasta ${IMAGE_MAX_MB} MB.`);
446
447
  return f;
447
448
  };
448
449
  const parseGenerateInput = (fields, files) => {
@@ -410,10 +410,11 @@ const imageStudio$1 = ({ strapi }) => createImageStudio(async () => {
410
410
  const { ai, backend } = await strapi.plugin("strapi-content-generator-gemini").service("service").geminiClient();
411
411
  return { models: ai.models, backend };
412
412
  });
413
+ const IMAGE_MAX_MB = 30;
414
+ const IMAGE_MAX_BYTES = IMAGE_MAX_MB * 1024 * 1024;
413
415
  class InputError extends Error {
414
416
  }
415
417
  const ALLOWED = ["image/png", "image/jpeg", "image/webp"];
416
- const MAX_BYTES = 10 * 1024 * 1024;
417
418
  const str = (v) => typeof v === "string" ? v : "";
418
419
  const bool = (v) => v === true || v === "true";
419
420
  const list = (v) => v ? Array.isArray(v) ? v : [v] : [];
@@ -424,7 +425,7 @@ const clean = (text2, labels) => {
424
425
  };
425
426
  const checkImage = (f) => {
426
427
  if (!ALLOWED.includes(f.mimetype ?? "")) throw new InputError("Las imágenes deben ser PNG, JPG o WEBP.");
427
- if (f.size > MAX_BYTES) throw new InputError("Cada imagen puede pesar hasta 10 MB.");
428
+ if (f.size > IMAGE_MAX_BYTES) throw new InputError(`Cada imagen puede pesar hasta ${IMAGE_MAX_MB} MB.`);
428
429
  return f;
429
430
  };
430
431
  const parseGenerateInput = (fields, files) => {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.7.1",
2
+ "version": "0.7.2",
3
3
  "keywords": [],
4
4
  "type": "commonjs",
5
5
  "publishConfig": {