docs-combiner 0.1.12 → 0.1.14

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/renderer.js CHANGED
@@ -2757,6 +2757,29 @@ __webpack_require__.r(__webpack_exports__);
2757
2757
 
2758
2758
  /***/ }),
2759
2759
 
2760
+ /***/ "./node_modules/@mui/icons-material/esm/AttachMoney.js":
2761
+ /*!*************************************************************!*\
2762
+ !*** ./node_modules/@mui/icons-material/esm/AttachMoney.js ***!
2763
+ \*************************************************************/
2764
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
2765
+
2766
+ "use strict";
2767
+ __webpack_require__.r(__webpack_exports__);
2768
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2769
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
2770
+ /* harmony export */ });
2771
+ /* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/esm/utils/createSvgIcon.js");
2772
+ /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
2773
+ "use client";
2774
+
2775
+
2776
+
2777
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__["default"])(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("path", {
2778
+ d: "M11.8 10.9c-2.27-.59-3-1.2-3-2.15 0-1.09 1.01-1.85 2.7-1.85 1.78 0 2.44.85 2.5 2.1h2.21c-.07-1.72-1.12-3.3-3.21-3.81V3h-3v2.16c-1.94.42-3.5 1.68-3.5 3.61 0 2.31 1.91 3.46 4.7 4.13 2.5.6 3 1.48 3 2.41 0 .69-.49 1.79-2.7 1.79-2.06 0-2.87-.92-2.98-2.1h-2.2c.12 2.19 1.76 3.42 3.68 3.83V21h3v-2.15c1.95-.37 3.5-1.5 3.5-3.55 0-2.84-2.43-3.81-4.7-4.4"
2779
+ }), 'AttachMoney'));
2780
+
2781
+ /***/ }),
2782
+
2760
2783
  /***/ "./node_modules/@mui/icons-material/esm/AutoAwesome.js":
2761
2784
  /*!*************************************************************!*\
2762
2785
  !*** ./node_modules/@mui/icons-material/esm/AutoAwesome.js ***!
@@ -2964,6 +2987,29 @@ __webpack_require__.r(__webpack_exports__);
2964
2987
 
2965
2988
  /***/ }),
2966
2989
 
2990
+ /***/ "./node_modules/@mui/icons-material/esm/DeleteOutline.js":
2991
+ /*!***************************************************************!*\
2992
+ !*** ./node_modules/@mui/icons-material/esm/DeleteOutline.js ***!
2993
+ \***************************************************************/
2994
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
2995
+
2996
+ "use strict";
2997
+ __webpack_require__.r(__webpack_exports__);
2998
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
2999
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
3000
+ /* harmony export */ });
3001
+ /* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/esm/utils/createSvgIcon.js");
3002
+ /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
3003
+ "use client";
3004
+
3005
+
3006
+
3007
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = ((0,_utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__["default"])(/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__.jsx)("path", {
3008
+ d: "M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6zM8 9h8v10H8zm7.5-5-1-1h-5l-1 1H5v2h14V4z"
3009
+ }), 'DeleteOutline'));
3010
+
3011
+ /***/ }),
3012
+
2967
3013
  /***/ "./node_modules/@mui/icons-material/esm/Edit.js":
2968
3014
  /*!******************************************************!*\
2969
3015
  !*** ./node_modules/@mui/icons-material/esm/Edit.js ***!
@@ -8295,6 +8341,206 @@ function getCircularProgressUtilityClass(slot) {
8295
8341
  const circularProgressClasses = (0,_mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__["default"])('MuiCircularProgress', ['root', 'determinate', 'indeterminate', 'colorPrimary', 'colorSecondary', 'svg', 'track', 'circle', 'circleDeterminate', 'circleIndeterminate', 'circleDisableShrink']);
8296
8342
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (circularProgressClasses);
8297
8343
 
8344
+ /***/ }),
8345
+
8346
+ /***/ "./node_modules/@mui/material/esm/ClickAwayListener/ClickAwayListener.js":
8347
+ /*!*******************************************************************************!*\
8348
+ !*** ./node_modules/@mui/material/esm/ClickAwayListener/ClickAwayListener.js ***!
8349
+ \*******************************************************************************/
8350
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
8351
+
8352
+ "use strict";
8353
+ __webpack_require__.r(__webpack_exports__);
8354
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
8355
+ /* harmony export */ ClickAwayListener: () => (/* binding */ ClickAwayListener)
8356
+ /* harmony export */ });
8357
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
8358
+ /* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prop-types */ "./node_modules/prop-types/index.js");
8359
+ /* harmony import */ var _mui_utils_ownerDocument__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/utils/ownerDocument */ "./node_modules/@mui/utils/esm/ownerDocument/ownerDocument.js");
8360
+ /* harmony import */ var _mui_utils_useForkRef__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/utils/useForkRef */ "./node_modules/@mui/utils/esm/useForkRef/useForkRef.js");
8361
+ /* harmony import */ var _mui_utils_useEventCallback__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @mui/utils/useEventCallback */ "./node_modules/@mui/utils/esm/useEventCallback/useEventCallback.js");
8362
+ /* harmony import */ var _mui_utils_elementAcceptingRef__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @mui/utils/elementAcceptingRef */ "./node_modules/@mui/utils/esm/elementAcceptingRef/elementAcceptingRef.js");
8363
+ /* harmony import */ var _mui_utils_exactProp__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @mui/utils/exactProp */ "./node_modules/@mui/utils/esm/exactProp/exactProp.js");
8364
+ /* harmony import */ var _mui_utils_getReactElementRef__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! @mui/utils/getReactElementRef */ "./node_modules/@mui/utils/esm/getReactElementRef/getReactElementRef.js");
8365
+ 'use client';
8366
+
8367
+
8368
+
8369
+
8370
+
8371
+
8372
+
8373
+
8374
+
8375
+
8376
+ // TODO: return `EventHandlerName extends `on${infer EventName}` ? Lowercase<EventName> : never` once generatePropTypes runs with TS 4.1
8377
+ function mapEventPropToEvent(eventProp) {
8378
+ return eventProp.substring(2).toLowerCase();
8379
+ }
8380
+ function clickedRootScrollbar(event, doc) {
8381
+ return doc.documentElement.clientWidth < event.clientX || doc.documentElement.clientHeight < event.clientY;
8382
+ }
8383
+ /**
8384
+ * Listen for click events that occur somewhere in the document, outside of the element itself.
8385
+ * For instance, if you need to hide a menu when people click anywhere else on your page.
8386
+ *
8387
+ * Demos:
8388
+ *
8389
+ * - [Click-Away Listener](https://mui.com/material-ui/react-click-away-listener/)
8390
+ * - [Menu](https://mui.com/material-ui/react-menu/)
8391
+ *
8392
+ * API:
8393
+ *
8394
+ * - [ClickAwayListener API](https://mui.com/material-ui/api/click-away-listener/)
8395
+ */
8396
+ function ClickAwayListener(props) {
8397
+ const {
8398
+ children,
8399
+ disableReactTree = false,
8400
+ mouseEvent = 'onClick',
8401
+ onClickAway,
8402
+ touchEvent = 'onTouchEnd'
8403
+ } = props;
8404
+ const movedRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(false);
8405
+ const nodeRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(null);
8406
+ const activatedRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(false);
8407
+ const syntheticEventRef = react__WEBPACK_IMPORTED_MODULE_0__.useRef(false);
8408
+ react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
8409
+ // Ensure that this component is not "activated" synchronously.
8410
+ // https://github.com/facebook/react/issues/20074
8411
+ setTimeout(() => {
8412
+ activatedRef.current = true;
8413
+ }, 0);
8414
+ return () => {
8415
+ activatedRef.current = false;
8416
+ };
8417
+ }, []);
8418
+ const handleRef = (0,_mui_utils_useForkRef__WEBPACK_IMPORTED_MODULE_3__["default"])((0,_mui_utils_getReactElementRef__WEBPACK_IMPORTED_MODULE_7__["default"])(children), nodeRef);
8419
+
8420
+ // The handler doesn't take event.defaultPrevented into account:
8421
+ //
8422
+ // event.preventDefault() is meant to stop default behaviors like
8423
+ // clicking a checkbox to check it, hitting a button to submit a form,
8424
+ // and hitting left arrow to move the cursor in a text input etc.
8425
+ // Only special HTML elements have these default behaviors.
8426
+ const handleClickAway = (0,_mui_utils_useEventCallback__WEBPACK_IMPORTED_MODULE_4__["default"])(event => {
8427
+ // Given developers can stop the propagation of the synthetic event,
8428
+ // we can only be confident with a positive value.
8429
+ const insideReactTree = syntheticEventRef.current;
8430
+ syntheticEventRef.current = false;
8431
+ const doc = (0,_mui_utils_ownerDocument__WEBPACK_IMPORTED_MODULE_2__["default"])(nodeRef.current);
8432
+
8433
+ // 1. IE11 support, which trigger the handleClickAway even after the unbind
8434
+ // 2. The child might render null.
8435
+ // 3. Behave like a blur listener.
8436
+ if (!activatedRef.current || !nodeRef.current || 'clientX' in event && clickedRootScrollbar(event, doc)) {
8437
+ return;
8438
+ }
8439
+
8440
+ // Do not act if user performed touchmove
8441
+ if (movedRef.current) {
8442
+ movedRef.current = false;
8443
+ return;
8444
+ }
8445
+ let insideDOM;
8446
+
8447
+ // If not enough, can use https://github.com/DieterHolvoet/event-propagation-path/blob/master/propagationPath.js
8448
+ if (event.composedPath) {
8449
+ insideDOM = event.composedPath().includes(nodeRef.current);
8450
+ } else {
8451
+ insideDOM = !doc.documentElement.contains(
8452
+ // @ts-expect-error returns `false` as intended when not dispatched from a Node
8453
+ event.target) || nodeRef.current.contains(
8454
+ // @ts-expect-error returns `false` as intended when not dispatched from a Node
8455
+ event.target);
8456
+ }
8457
+ if (!insideDOM && (disableReactTree || !insideReactTree)) {
8458
+ onClickAway(event);
8459
+ }
8460
+ });
8461
+
8462
+ // Keep track of mouse/touch events that bubbled up through the portal.
8463
+ const createHandleSynthetic = handlerName => event => {
8464
+ syntheticEventRef.current = true;
8465
+ const childrenPropsHandler = children.props[handlerName];
8466
+ if (childrenPropsHandler) {
8467
+ childrenPropsHandler(event);
8468
+ }
8469
+ };
8470
+ const childrenProps = {
8471
+ ref: handleRef
8472
+ };
8473
+ if (touchEvent !== false) {
8474
+ childrenProps[touchEvent] = createHandleSynthetic(touchEvent);
8475
+ }
8476
+ react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
8477
+ if (touchEvent !== false) {
8478
+ const mappedTouchEvent = mapEventPropToEvent(touchEvent);
8479
+ const doc = (0,_mui_utils_ownerDocument__WEBPACK_IMPORTED_MODULE_2__["default"])(nodeRef.current);
8480
+ const handleTouchMove = () => {
8481
+ movedRef.current = true;
8482
+ };
8483
+ doc.addEventListener(mappedTouchEvent, handleClickAway);
8484
+ doc.addEventListener('touchmove', handleTouchMove);
8485
+ return () => {
8486
+ doc.removeEventListener(mappedTouchEvent, handleClickAway);
8487
+ doc.removeEventListener('touchmove', handleTouchMove);
8488
+ };
8489
+ }
8490
+ return undefined;
8491
+ }, [handleClickAway, touchEvent]);
8492
+ if (mouseEvent !== false) {
8493
+ childrenProps[mouseEvent] = createHandleSynthetic(mouseEvent);
8494
+ }
8495
+ react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
8496
+ if (mouseEvent !== false) {
8497
+ const mappedMouseEvent = mapEventPropToEvent(mouseEvent);
8498
+ const doc = (0,_mui_utils_ownerDocument__WEBPACK_IMPORTED_MODULE_2__["default"])(nodeRef.current);
8499
+ doc.addEventListener(mappedMouseEvent, handleClickAway);
8500
+ return () => {
8501
+ doc.removeEventListener(mappedMouseEvent, handleClickAway);
8502
+ };
8503
+ }
8504
+ return undefined;
8505
+ }, [handleClickAway, mouseEvent]);
8506
+ return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.cloneElement(children, childrenProps);
8507
+ }
8508
+ true ? ClickAwayListener.propTypes /* remove-proptypes */ = {
8509
+ // ┌────────────────────────────── Warning ──────────────────────────────┐
8510
+ // │ These PropTypes are generated from the TypeScript type definitions. │
8511
+ // │ To update them, edit the TypeScript types and run `pnpm proptypes`. │
8512
+ // └─────────────────────────────────────────────────────────────────────┘
8513
+ /**
8514
+ * The wrapped element.
8515
+ */
8516
+ children: _mui_utils_elementAcceptingRef__WEBPACK_IMPORTED_MODULE_5__["default"].isRequired,
8517
+ /**
8518
+ * If `true`, the React tree is ignored and only the DOM tree is considered.
8519
+ * This prop changes how portaled elements are handled.
8520
+ * @default false
8521
+ */
8522
+ disableReactTree: prop_types__WEBPACK_IMPORTED_MODULE_1__.bool,
8523
+ /**
8524
+ * The mouse event to listen to. You can disable the listener by providing `false`.
8525
+ * @default 'onClick'
8526
+ */
8527
+ mouseEvent: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOf(['onClick', 'onMouseDown', 'onMouseUp', 'onPointerDown', 'onPointerUp', false]),
8528
+ /**
8529
+ * Callback fired when a "click away" event is detected.
8530
+ */
8531
+ onClickAway: prop_types__WEBPACK_IMPORTED_MODULE_1__.func.isRequired,
8532
+ /**
8533
+ * The touch event to listen to. You can disable the listener by providing `false`.
8534
+ * @default 'onTouchEnd'
8535
+ */
8536
+ touchEvent: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOf(['onTouchEnd', 'onTouchStart', false])
8537
+ } : 0;
8538
+ if (true) {
8539
+ // eslint-disable-next-line
8540
+ ClickAwayListener['propTypes' + ''] = (0,_mui_utils_exactProp__WEBPACK_IMPORTED_MODULE_6__["default"])(ClickAwayListener.propTypes);
8541
+ }
8542
+
8543
+
8298
8544
  /***/ }),
8299
8545
 
8300
8546
  /***/ "./node_modules/@mui/material/esm/Collapse/Collapse.js":
@@ -13768,6 +14014,243 @@ const inputClasses = {
13768
14014
 
13769
14015
  /***/ }),
13770
14016
 
14017
+ /***/ "./node_modules/@mui/material/esm/InputAdornment/InputAdornment.js":
14018
+ /*!*************************************************************************!*\
14019
+ !*** ./node_modules/@mui/material/esm/InputAdornment/InputAdornment.js ***!
14020
+ \*************************************************************************/
14021
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
14022
+
14023
+ "use strict";
14024
+ __webpack_require__.r(__webpack_exports__);
14025
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
14026
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
14027
+ /* harmony export */ });
14028
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
14029
+ /* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prop-types */ "./node_modules/prop-types/index.js");
14030
+ /* harmony import */ var clsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! clsx */ "./node_modules/clsx/dist/clsx.mjs");
14031
+ /* harmony import */ var _mui_utils_composeClasses__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/utils/composeClasses */ "./node_modules/@mui/utils/esm/composeClasses/composeClasses.js");
14032
+ /* harmony import */ var _utils_capitalize_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../utils/capitalize.js */ "./node_modules/@mui/material/esm/utils/capitalize.js");
14033
+ /* harmony import */ var _Typography_index_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../Typography/index.js */ "./node_modules/@mui/material/esm/Typography/Typography.js");
14034
+ /* harmony import */ var _FormControl_FormControlContext_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../FormControl/FormControlContext.js */ "./node_modules/@mui/material/esm/FormControl/FormControlContext.js");
14035
+ /* harmony import */ var _FormControl_useFormControl_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../FormControl/useFormControl.js */ "./node_modules/@mui/material/esm/FormControl/useFormControl.js");
14036
+ /* harmony import */ var _zero_styled_index_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../zero-styled/index.js */ "./node_modules/@mui/material/esm/styles/styled.js");
14037
+ /* harmony import */ var _utils_memoTheme_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../utils/memoTheme.js */ "./node_modules/@mui/material/esm/utils/memoTheme.js");
14038
+ /* harmony import */ var _DefaultPropsProvider_index_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../DefaultPropsProvider/index.js */ "./node_modules/@mui/material/esm/DefaultPropsProvider/DefaultPropsProvider.js");
14039
+ /* harmony import */ var _inputAdornmentClasses_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./inputAdornmentClasses.js */ "./node_modules/@mui/material/esm/InputAdornment/inputAdornmentClasses.js");
14040
+ /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
14041
+ 'use client';
14042
+
14043
+ var _span;
14044
+
14045
+
14046
+
14047
+
14048
+
14049
+
14050
+
14051
+
14052
+
14053
+
14054
+
14055
+
14056
+
14057
+ const overridesResolver = (props, styles) => {
14058
+ const {
14059
+ ownerState
14060
+ } = props;
14061
+ return [styles.root, styles[`position${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_4__["default"])(ownerState.position)}`], ownerState.disablePointerEvents === true && styles.disablePointerEvents, styles[ownerState.variant]];
14062
+ };
14063
+ const useUtilityClasses = ownerState => {
14064
+ const {
14065
+ classes,
14066
+ disablePointerEvents,
14067
+ hiddenLabel,
14068
+ position,
14069
+ size,
14070
+ variant
14071
+ } = ownerState;
14072
+ const slots = {
14073
+ root: ['root', disablePointerEvents && 'disablePointerEvents', position && `position${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_4__["default"])(position)}`, variant, hiddenLabel && 'hiddenLabel', size && `size${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_4__["default"])(size)}`]
14074
+ };
14075
+ return (0,_mui_utils_composeClasses__WEBPACK_IMPORTED_MODULE_3__["default"])(slots, _inputAdornmentClasses_js__WEBPACK_IMPORTED_MODULE_11__.getInputAdornmentUtilityClass, classes);
14076
+ };
14077
+ const InputAdornmentRoot = (0,_zero_styled_index_js__WEBPACK_IMPORTED_MODULE_8__["default"])('div', {
14078
+ name: 'MuiInputAdornment',
14079
+ slot: 'Root',
14080
+ overridesResolver
14081
+ })((0,_utils_memoTheme_js__WEBPACK_IMPORTED_MODULE_9__["default"])(({
14082
+ theme
14083
+ }) => ({
14084
+ display: 'flex',
14085
+ maxHeight: '2em',
14086
+ alignItems: 'center',
14087
+ whiteSpace: 'nowrap',
14088
+ color: (theme.vars || theme).palette.action.active,
14089
+ variants: [{
14090
+ props: {
14091
+ variant: 'filled'
14092
+ },
14093
+ style: {
14094
+ [`&.${_inputAdornmentClasses_js__WEBPACK_IMPORTED_MODULE_11__["default"].positionStart}&:not(.${_inputAdornmentClasses_js__WEBPACK_IMPORTED_MODULE_11__["default"].hiddenLabel})`]: {
14095
+ marginTop: 16
14096
+ }
14097
+ }
14098
+ }, {
14099
+ props: {
14100
+ position: 'start'
14101
+ },
14102
+ style: {
14103
+ marginRight: 8
14104
+ }
14105
+ }, {
14106
+ props: {
14107
+ position: 'end'
14108
+ },
14109
+ style: {
14110
+ marginLeft: 8
14111
+ }
14112
+ }, {
14113
+ props: {
14114
+ disablePointerEvents: true
14115
+ },
14116
+ style: {
14117
+ pointerEvents: 'none'
14118
+ }
14119
+ }]
14120
+ })));
14121
+ const InputAdornment = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.forwardRef(function InputAdornment(inProps, ref) {
14122
+ const props = (0,_DefaultPropsProvider_index_js__WEBPACK_IMPORTED_MODULE_10__.useDefaultProps)({
14123
+ props: inProps,
14124
+ name: 'MuiInputAdornment'
14125
+ });
14126
+ const {
14127
+ children,
14128
+ className,
14129
+ component = 'div',
14130
+ disablePointerEvents = false,
14131
+ disableTypography = false,
14132
+ position,
14133
+ variant: variantProp,
14134
+ ...other
14135
+ } = props;
14136
+ const muiFormControl = (0,_FormControl_useFormControl_js__WEBPACK_IMPORTED_MODULE_7__["default"])() || {};
14137
+ let variant = variantProp;
14138
+ if (variantProp && muiFormControl.variant) {
14139
+ if (true) {
14140
+ if (variantProp === muiFormControl.variant) {
14141
+ console.error('MUI: The `InputAdornment` variant infers the variant prop ' + 'you do not have to provide one.');
14142
+ }
14143
+ }
14144
+ }
14145
+ if (muiFormControl && !variant) {
14146
+ variant = muiFormControl.variant;
14147
+ }
14148
+ const ownerState = {
14149
+ ...props,
14150
+ hiddenLabel: muiFormControl.hiddenLabel,
14151
+ size: muiFormControl.size,
14152
+ disablePointerEvents,
14153
+ position,
14154
+ variant
14155
+ };
14156
+ const classes = useUtilityClasses(ownerState);
14157
+ return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_12__.jsx)(_FormControl_FormControlContext_js__WEBPACK_IMPORTED_MODULE_6__["default"].Provider, {
14158
+ value: null,
14159
+ children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_12__.jsx)(InputAdornmentRoot, {
14160
+ as: component,
14161
+ ownerState: ownerState,
14162
+ className: (0,clsx__WEBPACK_IMPORTED_MODULE_2__["default"])(classes.root, className),
14163
+ ref: ref,
14164
+ ...other,
14165
+ children: typeof children === 'string' && !disableTypography ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_12__.jsx)(_Typography_index_js__WEBPACK_IMPORTED_MODULE_5__["default"], {
14166
+ color: "textSecondary",
14167
+ children: children
14168
+ }) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_12__.jsxs)(react__WEBPACK_IMPORTED_MODULE_0__.Fragment, {
14169
+ children: [position === 'start' ? (/* notranslate needed while Google Translate will not fix zero-width space issue */_span || (_span = /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_12__.jsx)("span", {
14170
+ className: "notranslate",
14171
+ "aria-hidden": true,
14172
+ children: "\u200B"
14173
+ }))) : null, children]
14174
+ })
14175
+ })
14176
+ });
14177
+ });
14178
+ true ? InputAdornment.propTypes /* remove-proptypes */ = {
14179
+ // ┌────────────────────────────── Warning ──────────────────────────────┐
14180
+ // │ These PropTypes are generated from the TypeScript type definitions. │
14181
+ // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
14182
+ // └─────────────────────────────────────────────────────────────────────┘
14183
+ /**
14184
+ * The content of the component, normally an `IconButton` or string.
14185
+ */
14186
+ children: prop_types__WEBPACK_IMPORTED_MODULE_1__.node,
14187
+ /**
14188
+ * Override or extend the styles applied to the component.
14189
+ */
14190
+ classes: prop_types__WEBPACK_IMPORTED_MODULE_1__.object,
14191
+ /**
14192
+ * @ignore
14193
+ */
14194
+ className: prop_types__WEBPACK_IMPORTED_MODULE_1__.string,
14195
+ /**
14196
+ * The component used for the root node.
14197
+ * Either a string to use a HTML element or a component.
14198
+ */
14199
+ component: prop_types__WEBPACK_IMPORTED_MODULE_1__.elementType,
14200
+ /**
14201
+ * Disable pointer events on the root.
14202
+ * This allows for the content of the adornment to focus the `input` on click.
14203
+ * @default false
14204
+ */
14205
+ disablePointerEvents: prop_types__WEBPACK_IMPORTED_MODULE_1__.bool,
14206
+ /**
14207
+ * If children is a string then disable wrapping in a Typography component.
14208
+ * @default false
14209
+ */
14210
+ disableTypography: prop_types__WEBPACK_IMPORTED_MODULE_1__.bool,
14211
+ /**
14212
+ * The position this adornment should appear relative to the `Input`.
14213
+ */
14214
+ position: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOf(['end', 'start']).isRequired,
14215
+ /**
14216
+ * The system prop that allows defining system overrides as well as additional CSS styles.
14217
+ */
14218
+ sx: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.arrayOf(prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object, prop_types__WEBPACK_IMPORTED_MODULE_1__.bool])), prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object]),
14219
+ /**
14220
+ * The variant to use.
14221
+ * Note: If you are using the `TextField` component or the `FormControl` component
14222
+ * you do not have to set this manually.
14223
+ */
14224
+ variant: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOf(['filled', 'outlined', 'standard'])
14225
+ } : 0;
14226
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (InputAdornment);
14227
+
14228
+ /***/ }),
14229
+
14230
+ /***/ "./node_modules/@mui/material/esm/InputAdornment/inputAdornmentClasses.js":
14231
+ /*!********************************************************************************!*\
14232
+ !*** ./node_modules/@mui/material/esm/InputAdornment/inputAdornmentClasses.js ***!
14233
+ \********************************************************************************/
14234
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
14235
+
14236
+ "use strict";
14237
+ __webpack_require__.r(__webpack_exports__);
14238
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
14239
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
14240
+ /* harmony export */ getInputAdornmentUtilityClass: () => (/* binding */ getInputAdornmentUtilityClass)
14241
+ /* harmony export */ });
14242
+ /* harmony import */ var _mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @mui/utils/generateUtilityClasses */ "./node_modules/@mui/utils/esm/generateUtilityClasses/generateUtilityClasses.js");
14243
+ /* harmony import */ var _mui_utils_generateUtilityClass__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @mui/utils/generateUtilityClass */ "./node_modules/@mui/utils/esm/generateUtilityClass/generateUtilityClass.js");
14244
+
14245
+
14246
+ function getInputAdornmentUtilityClass(slot) {
14247
+ return (0,_mui_utils_generateUtilityClass__WEBPACK_IMPORTED_MODULE_1__["default"])('MuiInputAdornment', slot);
14248
+ }
14249
+ const inputAdornmentClasses = (0,_mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__["default"])('MuiInputAdornment', ['root', 'filled', 'standard', 'outlined', 'positionStart', 'positionEnd', 'disablePointerEvents', 'hiddenLabel', 'sizeSmall']);
14250
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (inputAdornmentClasses);
14251
+
14252
+ /***/ }),
14253
+
13771
14254
  /***/ "./node_modules/@mui/material/esm/InputBase/InputBase.js":
13772
14255
  /*!***************************************************************!*\
13773
14256
  !*** ./node_modules/@mui/material/esm/InputBase/InputBase.js ***!
@@ -20813,6 +21296,799 @@ const selectClasses = (0,_mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MOD
20813
21296
 
20814
21297
  /***/ }),
20815
21298
 
21299
+ /***/ "./node_modules/@mui/material/esm/Snackbar/Snackbar.js":
21300
+ /*!*************************************************************!*\
21301
+ !*** ./node_modules/@mui/material/esm/Snackbar/Snackbar.js ***!
21302
+ \*************************************************************/
21303
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
21304
+
21305
+ "use strict";
21306
+ __webpack_require__.r(__webpack_exports__);
21307
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
21308
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
21309
+ /* harmony export */ });
21310
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
21311
+ /* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prop-types */ "./node_modules/prop-types/index.js");
21312
+ /* harmony import */ var _mui_utils_composeClasses__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/utils/composeClasses */ "./node_modules/@mui/utils/esm/composeClasses/composeClasses.js");
21313
+ /* harmony import */ var _useSnackbar_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./useSnackbar.js */ "./node_modules/@mui/material/esm/Snackbar/useSnackbar.js");
21314
+ /* harmony import */ var _ClickAwayListener_index_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../ClickAwayListener/index.js */ "./node_modules/@mui/material/esm/ClickAwayListener/ClickAwayListener.js");
21315
+ /* harmony import */ var _zero_styled_index_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../zero-styled/index.js */ "./node_modules/@mui/material/esm/styles/useTheme.js");
21316
+ /* harmony import */ var _zero_styled_index_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../zero-styled/index.js */ "./node_modules/@mui/material/esm/styles/styled.js");
21317
+ /* harmony import */ var _utils_memoTheme_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../utils/memoTheme.js */ "./node_modules/@mui/material/esm/utils/memoTheme.js");
21318
+ /* harmony import */ var _DefaultPropsProvider_index_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../DefaultPropsProvider/index.js */ "./node_modules/@mui/material/esm/DefaultPropsProvider/DefaultPropsProvider.js");
21319
+ /* harmony import */ var _utils_capitalize_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../utils/capitalize.js */ "./node_modules/@mui/material/esm/utils/capitalize.js");
21320
+ /* harmony import */ var _Grow_index_js__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../Grow/index.js */ "./node_modules/@mui/material/esm/Grow/Grow.js");
21321
+ /* harmony import */ var _SnackbarContent_index_js__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../SnackbarContent/index.js */ "./node_modules/@mui/material/esm/SnackbarContent/SnackbarContent.js");
21322
+ /* harmony import */ var _snackbarClasses_js__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./snackbarClasses.js */ "./node_modules/@mui/material/esm/Snackbar/snackbarClasses.js");
21323
+ /* harmony import */ var _utils_useSlot_js__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../utils/useSlot.js */ "./node_modules/@mui/material/esm/utils/useSlot.js");
21324
+ /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
21325
+ 'use client';
21326
+
21327
+
21328
+
21329
+
21330
+
21331
+
21332
+
21333
+
21334
+
21335
+
21336
+
21337
+
21338
+
21339
+
21340
+
21341
+ const useUtilityClasses = ownerState => {
21342
+ const {
21343
+ classes,
21344
+ anchorOrigin
21345
+ } = ownerState;
21346
+ const slots = {
21347
+ root: ['root', `anchorOrigin${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_9__["default"])(anchorOrigin.vertical)}${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_9__["default"])(anchorOrigin.horizontal)}`]
21348
+ };
21349
+ return (0,_mui_utils_composeClasses__WEBPACK_IMPORTED_MODULE_2__["default"])(slots, _snackbarClasses_js__WEBPACK_IMPORTED_MODULE_12__.getSnackbarUtilityClass, classes);
21350
+ };
21351
+ const SnackbarRoot = (0,_zero_styled_index_js__WEBPACK_IMPORTED_MODULE_6__["default"])('div', {
21352
+ name: 'MuiSnackbar',
21353
+ slot: 'Root',
21354
+ overridesResolver: (props, styles) => {
21355
+ const {
21356
+ ownerState
21357
+ } = props;
21358
+ return [styles.root, styles[`anchorOrigin${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_9__["default"])(ownerState.anchorOrigin.vertical)}${(0,_utils_capitalize_js__WEBPACK_IMPORTED_MODULE_9__["default"])(ownerState.anchorOrigin.horizontal)}`]];
21359
+ }
21360
+ })((0,_utils_memoTheme_js__WEBPACK_IMPORTED_MODULE_7__["default"])(({
21361
+ theme
21362
+ }) => ({
21363
+ zIndex: (theme.vars || theme).zIndex.snackbar,
21364
+ position: 'fixed',
21365
+ display: 'flex',
21366
+ left: 8,
21367
+ right: 8,
21368
+ justifyContent: 'center',
21369
+ alignItems: 'center',
21370
+ variants: [{
21371
+ props: ({
21372
+ ownerState
21373
+ }) => ownerState.anchorOrigin.vertical === 'top',
21374
+ style: {
21375
+ top: 8,
21376
+ [theme.breakpoints.up('sm')]: {
21377
+ top: 24
21378
+ }
21379
+ }
21380
+ }, {
21381
+ props: ({
21382
+ ownerState
21383
+ }) => ownerState.anchorOrigin.vertical !== 'top',
21384
+ style: {
21385
+ bottom: 8,
21386
+ [theme.breakpoints.up('sm')]: {
21387
+ bottom: 24
21388
+ }
21389
+ }
21390
+ }, {
21391
+ props: ({
21392
+ ownerState
21393
+ }) => ownerState.anchorOrigin.horizontal === 'left',
21394
+ style: {
21395
+ justifyContent: 'flex-start',
21396
+ [theme.breakpoints.up('sm')]: {
21397
+ left: 24,
21398
+ right: 'auto'
21399
+ }
21400
+ }
21401
+ }, {
21402
+ props: ({
21403
+ ownerState
21404
+ }) => ownerState.anchorOrigin.horizontal === 'right',
21405
+ style: {
21406
+ justifyContent: 'flex-end',
21407
+ [theme.breakpoints.up('sm')]: {
21408
+ right: 24,
21409
+ left: 'auto'
21410
+ }
21411
+ }
21412
+ }, {
21413
+ props: ({
21414
+ ownerState
21415
+ }) => ownerState.anchorOrigin.horizontal === 'center',
21416
+ style: {
21417
+ [theme.breakpoints.up('sm')]: {
21418
+ left: '50%',
21419
+ right: 'auto',
21420
+ transform: 'translateX(-50%)'
21421
+ }
21422
+ }
21423
+ }]
21424
+ })));
21425
+ const Snackbar = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.forwardRef(function Snackbar(inProps, ref) {
21426
+ const props = (0,_DefaultPropsProvider_index_js__WEBPACK_IMPORTED_MODULE_8__.useDefaultProps)({
21427
+ props: inProps,
21428
+ name: 'MuiSnackbar'
21429
+ });
21430
+ const theme = (0,_zero_styled_index_js__WEBPACK_IMPORTED_MODULE_5__["default"])();
21431
+ const defaultTransitionDuration = {
21432
+ enter: theme.transitions.duration.enteringScreen,
21433
+ exit: theme.transitions.duration.leavingScreen
21434
+ };
21435
+ const {
21436
+ action,
21437
+ anchorOrigin: {
21438
+ vertical,
21439
+ horizontal
21440
+ } = {
21441
+ vertical: 'bottom',
21442
+ horizontal: 'left'
21443
+ },
21444
+ autoHideDuration = null,
21445
+ children,
21446
+ className,
21447
+ ClickAwayListenerProps: ClickAwayListenerPropsProp,
21448
+ ContentProps: ContentPropsProp,
21449
+ disableWindowBlurListener = false,
21450
+ message,
21451
+ onBlur,
21452
+ onClose,
21453
+ onFocus,
21454
+ onMouseEnter,
21455
+ onMouseLeave,
21456
+ open,
21457
+ resumeHideDuration,
21458
+ slots = {},
21459
+ slotProps = {},
21460
+ TransitionComponent: TransitionComponentProp,
21461
+ transitionDuration = defaultTransitionDuration,
21462
+ TransitionProps: {
21463
+ onEnter,
21464
+ onExited,
21465
+ ...TransitionPropsProp
21466
+ } = {},
21467
+ ...other
21468
+ } = props;
21469
+ const ownerState = {
21470
+ ...props,
21471
+ anchorOrigin: {
21472
+ vertical,
21473
+ horizontal
21474
+ },
21475
+ autoHideDuration,
21476
+ disableWindowBlurListener,
21477
+ TransitionComponent: TransitionComponentProp,
21478
+ transitionDuration
21479
+ };
21480
+ const classes = useUtilityClasses(ownerState);
21481
+ const {
21482
+ getRootProps,
21483
+ onClickAway
21484
+ } = (0,_useSnackbar_js__WEBPACK_IMPORTED_MODULE_3__["default"])({
21485
+ ...ownerState
21486
+ });
21487
+ const [exited, setExited] = react__WEBPACK_IMPORTED_MODULE_0__.useState(true);
21488
+ const handleExited = node => {
21489
+ setExited(true);
21490
+ if (onExited) {
21491
+ onExited(node);
21492
+ }
21493
+ };
21494
+ const handleEnter = (node, isAppearing) => {
21495
+ setExited(false);
21496
+ if (onEnter) {
21497
+ onEnter(node, isAppearing);
21498
+ }
21499
+ };
21500
+ const externalForwardedProps = {
21501
+ slots: {
21502
+ transition: TransitionComponentProp,
21503
+ ...slots
21504
+ },
21505
+ slotProps: {
21506
+ content: ContentPropsProp,
21507
+ clickAwayListener: ClickAwayListenerPropsProp,
21508
+ transition: TransitionPropsProp,
21509
+ ...slotProps
21510
+ }
21511
+ };
21512
+ const [Root, rootProps] = (0,_utils_useSlot_js__WEBPACK_IMPORTED_MODULE_13__["default"])('root', {
21513
+ ref,
21514
+ className: [classes.root, className],
21515
+ elementType: SnackbarRoot,
21516
+ getSlotProps: getRootProps,
21517
+ externalForwardedProps: {
21518
+ ...externalForwardedProps,
21519
+ ...other
21520
+ },
21521
+ ownerState
21522
+ });
21523
+ const [ClickAwaySlot, {
21524
+ ownerState: clickAwayOwnerStateProp,
21525
+ ...clickAwayListenerProps
21526
+ }] = (0,_utils_useSlot_js__WEBPACK_IMPORTED_MODULE_13__["default"])('clickAwayListener', {
21527
+ elementType: _ClickAwayListener_index_js__WEBPACK_IMPORTED_MODULE_4__.ClickAwayListener,
21528
+ externalForwardedProps,
21529
+ getSlotProps: handlers => ({
21530
+ onClickAway: (...params) => {
21531
+ const event = params[0];
21532
+ handlers.onClickAway?.(...params);
21533
+ if (event?.defaultMuiPrevented) {
21534
+ return;
21535
+ }
21536
+ onClickAway(...params);
21537
+ }
21538
+ }),
21539
+ ownerState
21540
+ });
21541
+ const [ContentSlot, contentSlotProps] = (0,_utils_useSlot_js__WEBPACK_IMPORTED_MODULE_13__["default"])('content', {
21542
+ elementType: _SnackbarContent_index_js__WEBPACK_IMPORTED_MODULE_11__["default"],
21543
+ shouldForwardComponentProp: true,
21544
+ externalForwardedProps,
21545
+ additionalProps: {
21546
+ message,
21547
+ action
21548
+ },
21549
+ ownerState
21550
+ });
21551
+ const [TransitionSlot, transitionProps] = (0,_utils_useSlot_js__WEBPACK_IMPORTED_MODULE_13__["default"])('transition', {
21552
+ elementType: _Grow_index_js__WEBPACK_IMPORTED_MODULE_10__["default"],
21553
+ externalForwardedProps,
21554
+ getSlotProps: handlers => ({
21555
+ onEnter: (...params) => {
21556
+ handlers.onEnter?.(...params);
21557
+ handleEnter(...params);
21558
+ },
21559
+ onExited: (...params) => {
21560
+ handlers.onExited?.(...params);
21561
+ handleExited(...params);
21562
+ }
21563
+ }),
21564
+ additionalProps: {
21565
+ appear: true,
21566
+ in: open,
21567
+ timeout: transitionDuration,
21568
+ direction: vertical === 'top' ? 'down' : 'up'
21569
+ },
21570
+ ownerState
21571
+ });
21572
+
21573
+ // So we only render active snackbars.
21574
+ if (!open && exited) {
21575
+ return null;
21576
+ }
21577
+ return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_14__.jsx)(ClickAwaySlot, {
21578
+ ...clickAwayListenerProps,
21579
+ ...(slots.clickAwayListener && {
21580
+ ownerState: clickAwayOwnerStateProp
21581
+ }),
21582
+ children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_14__.jsx)(Root, {
21583
+ ...rootProps,
21584
+ children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_14__.jsx)(TransitionSlot, {
21585
+ ...transitionProps,
21586
+ children: children || /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_14__.jsx)(ContentSlot, {
21587
+ ...contentSlotProps
21588
+ })
21589
+ })
21590
+ })
21591
+ });
21592
+ });
21593
+ true ? Snackbar.propTypes /* remove-proptypes */ = {
21594
+ // ┌────────────────────────────── Warning ──────────────────────────────┐
21595
+ // │ These PropTypes are generated from the TypeScript type definitions. │
21596
+ // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
21597
+ // └─────────────────────────────────────────────────────────────────────┘
21598
+ /**
21599
+ * The action to display. It renders after the message, at the end of the snackbar.
21600
+ */
21601
+ action: prop_types__WEBPACK_IMPORTED_MODULE_1__.node,
21602
+ /**
21603
+ * The anchor of the `Snackbar`.
21604
+ * On smaller screens, the component grows to occupy all the available width,
21605
+ * the horizontal alignment is ignored.
21606
+ * @default { vertical: 'bottom', horizontal: 'left' }
21607
+ */
21608
+ anchorOrigin: prop_types__WEBPACK_IMPORTED_MODULE_1__.shape({
21609
+ horizontal: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOf(['center', 'left', 'right']).isRequired,
21610
+ vertical: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOf(['bottom', 'top']).isRequired
21611
+ }),
21612
+ /**
21613
+ * The number of milliseconds to wait before automatically calling the
21614
+ * `onClose` function. `onClose` should then set the state of the `open`
21615
+ * prop to hide the Snackbar. This behavior is disabled by default with
21616
+ * the `null` value.
21617
+ * @default null
21618
+ */
21619
+ autoHideDuration: prop_types__WEBPACK_IMPORTED_MODULE_1__.number,
21620
+ /**
21621
+ * Replace the `SnackbarContent` component.
21622
+ */
21623
+ children: prop_types__WEBPACK_IMPORTED_MODULE_1__.element,
21624
+ /**
21625
+ * Override or extend the styles applied to the component.
21626
+ */
21627
+ classes: prop_types__WEBPACK_IMPORTED_MODULE_1__.object,
21628
+ /**
21629
+ * @ignore
21630
+ */
21631
+ className: prop_types__WEBPACK_IMPORTED_MODULE_1__.string,
21632
+ /**
21633
+ * Props applied to the `ClickAwayListener` element.
21634
+ * @deprecated Use `slotProps.clickAwayListener` instead. This prop will be removed in a future major release. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details.
21635
+ */
21636
+ ClickAwayListenerProps: prop_types__WEBPACK_IMPORTED_MODULE_1__.object,
21637
+ /**
21638
+ * Props applied to the [`SnackbarContent`](https://mui.com/material-ui/api/snackbar-content/) element.
21639
+ * @deprecated Use `slotProps.content` instead. This prop will be removed in a future major release. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details.
21640
+ */
21641
+ ContentProps: prop_types__WEBPACK_IMPORTED_MODULE_1__.object,
21642
+ /**
21643
+ * If `true`, the `autoHideDuration` timer will expire even if the window is not focused.
21644
+ * @default false
21645
+ */
21646
+ disableWindowBlurListener: prop_types__WEBPACK_IMPORTED_MODULE_1__.bool,
21647
+ /**
21648
+ * When displaying multiple consecutive snackbars using a single parent-rendered
21649
+ * `<Snackbar/>`, add the `key` prop to ensure independent treatment of each message.
21650
+ * For instance, use `<Snackbar key={message} />`. Otherwise, messages might update
21651
+ * in place, and features like `autoHideDuration` could be affected.
21652
+ */
21653
+ key: () => null,
21654
+ /**
21655
+ * The message to display.
21656
+ */
21657
+ message: prop_types__WEBPACK_IMPORTED_MODULE_1__.node,
21658
+ /**
21659
+ * @ignore
21660
+ */
21661
+ onBlur: prop_types__WEBPACK_IMPORTED_MODULE_1__.func,
21662
+ /**
21663
+ * Callback fired when the component requests to be closed.
21664
+ * Typically `onClose` is used to set state in the parent component,
21665
+ * which is used to control the `Snackbar` `open` prop.
21666
+ * The `reason` parameter can optionally be used to control the response to `onClose`,
21667
+ * for example ignoring `clickaway`.
21668
+ *
21669
+ * @param {React.SyntheticEvent<any> | Event} event The event source of the callback.
21670
+ * @param {string} reason Can be: `"timeout"` (`autoHideDuration` expired), `"clickaway"`, or `"escapeKeyDown"`.
21671
+ */
21672
+ onClose: prop_types__WEBPACK_IMPORTED_MODULE_1__.func,
21673
+ /**
21674
+ * @ignore
21675
+ */
21676
+ onFocus: prop_types__WEBPACK_IMPORTED_MODULE_1__.func,
21677
+ /**
21678
+ * @ignore
21679
+ */
21680
+ onMouseEnter: prop_types__WEBPACK_IMPORTED_MODULE_1__.func,
21681
+ /**
21682
+ * @ignore
21683
+ */
21684
+ onMouseLeave: prop_types__WEBPACK_IMPORTED_MODULE_1__.func,
21685
+ /**
21686
+ * If `true`, the component is shown.
21687
+ */
21688
+ open: prop_types__WEBPACK_IMPORTED_MODULE_1__.bool,
21689
+ /**
21690
+ * The number of milliseconds to wait before dismissing after user interaction.
21691
+ * If `autoHideDuration` prop isn't specified, it does nothing.
21692
+ * If `autoHideDuration` prop is specified but `resumeHideDuration` isn't,
21693
+ * we default to `autoHideDuration / 2` ms.
21694
+ */
21695
+ resumeHideDuration: prop_types__WEBPACK_IMPORTED_MODULE_1__.number,
21696
+ /**
21697
+ * The props used for each slot inside.
21698
+ * @default {}
21699
+ */
21700
+ slotProps: prop_types__WEBPACK_IMPORTED_MODULE_1__.shape({
21701
+ clickAwayListener: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object]),
21702
+ content: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object]),
21703
+ root: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object]),
21704
+ transition: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object])
21705
+ }),
21706
+ /**
21707
+ * The components used for each slot inside.
21708
+ * @default {}
21709
+ */
21710
+ slots: prop_types__WEBPACK_IMPORTED_MODULE_1__.shape({
21711
+ clickAwayListener: prop_types__WEBPACK_IMPORTED_MODULE_1__.elementType,
21712
+ content: prop_types__WEBPACK_IMPORTED_MODULE_1__.elementType,
21713
+ root: prop_types__WEBPACK_IMPORTED_MODULE_1__.elementType,
21714
+ transition: prop_types__WEBPACK_IMPORTED_MODULE_1__.elementType
21715
+ }),
21716
+ /**
21717
+ * The system prop that allows defining system overrides as well as additional CSS styles.
21718
+ */
21719
+ sx: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.arrayOf(prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object, prop_types__WEBPACK_IMPORTED_MODULE_1__.bool])), prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object]),
21720
+ /**
21721
+ * The component used for the transition.
21722
+ * [Follow this guide](https://mui.com/material-ui/transitions/#transitioncomponent-prop) to learn more about the requirements for this component.
21723
+ * @deprecated Use `slots.transition` instead. This prop will be removed in a future major release. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details.
21724
+ * @default Grow
21725
+ */
21726
+ TransitionComponent: prop_types__WEBPACK_IMPORTED_MODULE_1__.elementType,
21727
+ /**
21728
+ * The duration for the transition, in milliseconds.
21729
+ * You may specify a single timeout for all transitions, or individually with an object.
21730
+ * @default {
21731
+ * enter: theme.transitions.duration.enteringScreen,
21732
+ * exit: theme.transitions.duration.leavingScreen,
21733
+ * }
21734
+ */
21735
+ transitionDuration: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.number, prop_types__WEBPACK_IMPORTED_MODULE_1__.shape({
21736
+ appear: prop_types__WEBPACK_IMPORTED_MODULE_1__.number,
21737
+ enter: prop_types__WEBPACK_IMPORTED_MODULE_1__.number,
21738
+ exit: prop_types__WEBPACK_IMPORTED_MODULE_1__.number
21739
+ })]),
21740
+ /**
21741
+ * Props applied to the transition element.
21742
+ * By default, the element is based on this [`Transition`](https://reactcommunity.org/react-transition-group/transition/) component.
21743
+ * @deprecated Use `slotProps.transition` instead. This prop will be removed in a future major release. See [Migrating from deprecated APIs](/material-ui/migration/migrating-from-deprecated-apis/) for more details.
21744
+ * @default {}
21745
+ */
21746
+ TransitionProps: prop_types__WEBPACK_IMPORTED_MODULE_1__.object
21747
+ } : 0;
21748
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (Snackbar);
21749
+
21750
+ /***/ }),
21751
+
21752
+ /***/ "./node_modules/@mui/material/esm/Snackbar/snackbarClasses.js":
21753
+ /*!********************************************************************!*\
21754
+ !*** ./node_modules/@mui/material/esm/Snackbar/snackbarClasses.js ***!
21755
+ \********************************************************************/
21756
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
21757
+
21758
+ "use strict";
21759
+ __webpack_require__.r(__webpack_exports__);
21760
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
21761
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
21762
+ /* harmony export */ getSnackbarUtilityClass: () => (/* binding */ getSnackbarUtilityClass)
21763
+ /* harmony export */ });
21764
+ /* harmony import */ var _mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @mui/utils/generateUtilityClasses */ "./node_modules/@mui/utils/esm/generateUtilityClasses/generateUtilityClasses.js");
21765
+ /* harmony import */ var _mui_utils_generateUtilityClass__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @mui/utils/generateUtilityClass */ "./node_modules/@mui/utils/esm/generateUtilityClass/generateUtilityClass.js");
21766
+
21767
+
21768
+ function getSnackbarUtilityClass(slot) {
21769
+ return (0,_mui_utils_generateUtilityClass__WEBPACK_IMPORTED_MODULE_1__["default"])('MuiSnackbar', slot);
21770
+ }
21771
+ const snackbarClasses = (0,_mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__["default"])('MuiSnackbar', ['root', 'anchorOriginTopCenter', 'anchorOriginBottomCenter', 'anchorOriginTopRight', 'anchorOriginBottomRight', 'anchorOriginTopLeft', 'anchorOriginBottomLeft']);
21772
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (snackbarClasses);
21773
+
21774
+ /***/ }),
21775
+
21776
+ /***/ "./node_modules/@mui/material/esm/Snackbar/useSnackbar.js":
21777
+ /*!****************************************************************!*\
21778
+ !*** ./node_modules/@mui/material/esm/Snackbar/useSnackbar.js ***!
21779
+ \****************************************************************/
21780
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
21781
+
21782
+ "use strict";
21783
+ __webpack_require__.r(__webpack_exports__);
21784
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
21785
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
21786
+ /* harmony export */ });
21787
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
21788
+ /* harmony import */ var _mui_utils_useEventCallback__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @mui/utils/useEventCallback */ "./node_modules/@mui/utils/esm/useEventCallback/useEventCallback.js");
21789
+ /* harmony import */ var _mui_utils_useTimeout__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/utils/useTimeout */ "./node_modules/@mui/utils/esm/useTimeout/useTimeout.js");
21790
+ /* harmony import */ var _mui_utils_extractEventHandlers__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/utils/extractEventHandlers */ "./node_modules/@mui/utils/esm/extractEventHandlers/extractEventHandlers.js");
21791
+ 'use client';
21792
+
21793
+
21794
+
21795
+
21796
+
21797
+ function useSnackbar(parameters = {}) {
21798
+ const {
21799
+ autoHideDuration = null,
21800
+ disableWindowBlurListener = false,
21801
+ onClose,
21802
+ open,
21803
+ resumeHideDuration
21804
+ } = parameters;
21805
+ const timerAutoHide = (0,_mui_utils_useTimeout__WEBPACK_IMPORTED_MODULE_2__["default"])();
21806
+ react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
21807
+ if (!open) {
21808
+ return undefined;
21809
+ }
21810
+
21811
+ /**
21812
+ * @param {KeyboardEvent} nativeEvent
21813
+ */
21814
+ function handleKeyDown(nativeEvent) {
21815
+ if (!nativeEvent.defaultPrevented) {
21816
+ if (nativeEvent.key === 'Escape') {
21817
+ // not calling `preventDefault` since we don't know if people may ignore this event e.g. a permanently open snackbar
21818
+ onClose?.(nativeEvent, 'escapeKeyDown');
21819
+ }
21820
+ }
21821
+ }
21822
+ document.addEventListener('keydown', handleKeyDown);
21823
+ return () => {
21824
+ document.removeEventListener('keydown', handleKeyDown);
21825
+ };
21826
+ }, [open, onClose]);
21827
+ const handleClose = (0,_mui_utils_useEventCallback__WEBPACK_IMPORTED_MODULE_1__["default"])((event, reason) => {
21828
+ onClose?.(event, reason);
21829
+ });
21830
+ const setAutoHideTimer = (0,_mui_utils_useEventCallback__WEBPACK_IMPORTED_MODULE_1__["default"])(autoHideDurationParam => {
21831
+ if (!onClose || autoHideDurationParam == null) {
21832
+ return;
21833
+ }
21834
+ timerAutoHide.start(autoHideDurationParam, () => {
21835
+ handleClose(null, 'timeout');
21836
+ });
21837
+ });
21838
+ react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
21839
+ if (open) {
21840
+ setAutoHideTimer(autoHideDuration);
21841
+ }
21842
+ return timerAutoHide.clear;
21843
+ }, [open, autoHideDuration, setAutoHideTimer, timerAutoHide]);
21844
+ const handleClickAway = event => {
21845
+ onClose?.(event, 'clickaway');
21846
+ };
21847
+
21848
+ // Pause the timer when the user is interacting with the Snackbar
21849
+ // or when the user hide the window.
21850
+ const handlePause = timerAutoHide.clear;
21851
+
21852
+ // Restart the timer when the user is no longer interacting with the Snackbar
21853
+ // or when the window is shown back.
21854
+ const handleResume = react__WEBPACK_IMPORTED_MODULE_0__.useCallback(() => {
21855
+ if (autoHideDuration != null) {
21856
+ setAutoHideTimer(resumeHideDuration != null ? resumeHideDuration : autoHideDuration * 0.5);
21857
+ }
21858
+ }, [autoHideDuration, resumeHideDuration, setAutoHideTimer]);
21859
+ const createHandleBlur = otherHandlers => event => {
21860
+ const onBlurCallback = otherHandlers.onBlur;
21861
+ onBlurCallback?.(event);
21862
+ handleResume();
21863
+ };
21864
+ const createHandleFocus = otherHandlers => event => {
21865
+ const onFocusCallback = otherHandlers.onFocus;
21866
+ onFocusCallback?.(event);
21867
+ handlePause();
21868
+ };
21869
+ const createMouseEnter = otherHandlers => event => {
21870
+ const onMouseEnterCallback = otherHandlers.onMouseEnter;
21871
+ onMouseEnterCallback?.(event);
21872
+ handlePause();
21873
+ };
21874
+ const createMouseLeave = otherHandlers => event => {
21875
+ const onMouseLeaveCallback = otherHandlers.onMouseLeave;
21876
+ onMouseLeaveCallback?.(event);
21877
+ handleResume();
21878
+ };
21879
+ react__WEBPACK_IMPORTED_MODULE_0__.useEffect(() => {
21880
+ // TODO: window global should be refactored here
21881
+ if (!disableWindowBlurListener && open) {
21882
+ window.addEventListener('focus', handleResume);
21883
+ window.addEventListener('blur', handlePause);
21884
+ return () => {
21885
+ window.removeEventListener('focus', handleResume);
21886
+ window.removeEventListener('blur', handlePause);
21887
+ };
21888
+ }
21889
+ return undefined;
21890
+ }, [disableWindowBlurListener, open, handleResume, handlePause]);
21891
+ const getRootProps = (externalProps = {}) => {
21892
+ const externalEventHandlers = {
21893
+ ...(0,_mui_utils_extractEventHandlers__WEBPACK_IMPORTED_MODULE_3__["default"])(parameters),
21894
+ ...(0,_mui_utils_extractEventHandlers__WEBPACK_IMPORTED_MODULE_3__["default"])(externalProps)
21895
+ };
21896
+ return {
21897
+ // ClickAwayListener adds an `onClick` prop which results in the alert not being announced.
21898
+ // See https://github.com/mui/material-ui/issues/29080
21899
+ role: 'presentation',
21900
+ ...externalProps,
21901
+ ...externalEventHandlers,
21902
+ onBlur: createHandleBlur(externalEventHandlers),
21903
+ onFocus: createHandleFocus(externalEventHandlers),
21904
+ onMouseEnter: createMouseEnter(externalEventHandlers),
21905
+ onMouseLeave: createMouseLeave(externalEventHandlers)
21906
+ };
21907
+ };
21908
+ return {
21909
+ getRootProps,
21910
+ onClickAway: handleClickAway
21911
+ };
21912
+ }
21913
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (useSnackbar);
21914
+
21915
+ /***/ }),
21916
+
21917
+ /***/ "./node_modules/@mui/material/esm/SnackbarContent/SnackbarContent.js":
21918
+ /*!***************************************************************************!*\
21919
+ !*** ./node_modules/@mui/material/esm/SnackbarContent/SnackbarContent.js ***!
21920
+ \***************************************************************************/
21921
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
21922
+
21923
+ "use strict";
21924
+ __webpack_require__.r(__webpack_exports__);
21925
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
21926
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
21927
+ /* harmony export */ });
21928
+ /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
21929
+ /* harmony import */ var prop_types__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! prop-types */ "./node_modules/prop-types/index.js");
21930
+ /* harmony import */ var clsx__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! clsx */ "./node_modules/clsx/dist/clsx.mjs");
21931
+ /* harmony import */ var _mui_utils_composeClasses__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/utils/composeClasses */ "./node_modules/@mui/utils/esm/composeClasses/composeClasses.js");
21932
+ /* harmony import */ var _mui_system_colorManipulator__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @mui/system/colorManipulator */ "./node_modules/@mui/system/esm/colorManipulator/colorManipulator.js");
21933
+ /* harmony import */ var _zero_styled_index_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../zero-styled/index.js */ "./node_modules/@mui/material/esm/styles/styled.js");
21934
+ /* harmony import */ var _utils_memoTheme_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../utils/memoTheme.js */ "./node_modules/@mui/material/esm/utils/memoTheme.js");
21935
+ /* harmony import */ var _DefaultPropsProvider_index_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../DefaultPropsProvider/index.js */ "./node_modules/@mui/material/esm/DefaultPropsProvider/DefaultPropsProvider.js");
21936
+ /* harmony import */ var _Paper_index_js__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../Paper/index.js */ "./node_modules/@mui/material/esm/Paper/Paper.js");
21937
+ /* harmony import */ var _snackbarContentClasses_js__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./snackbarContentClasses.js */ "./node_modules/@mui/material/esm/SnackbarContent/snackbarContentClasses.js");
21938
+ /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
21939
+ 'use client';
21940
+
21941
+
21942
+
21943
+
21944
+
21945
+
21946
+
21947
+
21948
+
21949
+
21950
+
21951
+
21952
+ const useUtilityClasses = ownerState => {
21953
+ const {
21954
+ classes
21955
+ } = ownerState;
21956
+ const slots = {
21957
+ root: ['root'],
21958
+ action: ['action'],
21959
+ message: ['message']
21960
+ };
21961
+ return (0,_mui_utils_composeClasses__WEBPACK_IMPORTED_MODULE_3__["default"])(slots, _snackbarContentClasses_js__WEBPACK_IMPORTED_MODULE_9__.getSnackbarContentUtilityClass, classes);
21962
+ };
21963
+ const SnackbarContentRoot = (0,_zero_styled_index_js__WEBPACK_IMPORTED_MODULE_5__["default"])(_Paper_index_js__WEBPACK_IMPORTED_MODULE_8__["default"], {
21964
+ name: 'MuiSnackbarContent',
21965
+ slot: 'Root'
21966
+ })((0,_utils_memoTheme_js__WEBPACK_IMPORTED_MODULE_6__["default"])(({
21967
+ theme
21968
+ }) => {
21969
+ const emphasis = theme.palette.mode === 'light' ? 0.8 : 0.98;
21970
+ return {
21971
+ ...theme.typography.body2,
21972
+ color: theme.vars ? theme.vars.palette.SnackbarContent.color : theme.palette.getContrastText((0,_mui_system_colorManipulator__WEBPACK_IMPORTED_MODULE_4__.emphasize)(theme.palette.background.default, emphasis)),
21973
+ backgroundColor: theme.vars ? theme.vars.palette.SnackbarContent.bg : (0,_mui_system_colorManipulator__WEBPACK_IMPORTED_MODULE_4__.emphasize)(theme.palette.background.default, emphasis),
21974
+ display: 'flex',
21975
+ alignItems: 'center',
21976
+ flexWrap: 'wrap',
21977
+ padding: '6px 16px',
21978
+ flexGrow: 1,
21979
+ [theme.breakpoints.up('sm')]: {
21980
+ flexGrow: 'initial',
21981
+ minWidth: 288
21982
+ }
21983
+ };
21984
+ }));
21985
+ const SnackbarContentMessage = (0,_zero_styled_index_js__WEBPACK_IMPORTED_MODULE_5__["default"])('div', {
21986
+ name: 'MuiSnackbarContent',
21987
+ slot: 'Message'
21988
+ })({
21989
+ padding: '8px 0'
21990
+ });
21991
+ const SnackbarContentAction = (0,_zero_styled_index_js__WEBPACK_IMPORTED_MODULE_5__["default"])('div', {
21992
+ name: 'MuiSnackbarContent',
21993
+ slot: 'Action'
21994
+ })({
21995
+ display: 'flex',
21996
+ alignItems: 'center',
21997
+ marginLeft: 'auto',
21998
+ paddingLeft: 16,
21999
+ marginRight: -8
22000
+ });
22001
+ const SnackbarContent = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.forwardRef(function SnackbarContent(inProps, ref) {
22002
+ const props = (0,_DefaultPropsProvider_index_js__WEBPACK_IMPORTED_MODULE_7__.useDefaultProps)({
22003
+ props: inProps,
22004
+ name: 'MuiSnackbarContent'
22005
+ });
22006
+ const {
22007
+ action,
22008
+ className,
22009
+ message,
22010
+ role = 'alert',
22011
+ ...other
22012
+ } = props;
22013
+ const ownerState = props;
22014
+ const classes = useUtilityClasses(ownerState);
22015
+ return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_10__.jsxs)(SnackbarContentRoot, {
22016
+ role: role,
22017
+ elevation: 6,
22018
+ className: (0,clsx__WEBPACK_IMPORTED_MODULE_2__["default"])(classes.root, className),
22019
+ ownerState: ownerState,
22020
+ ref: ref,
22021
+ ...other,
22022
+ children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_10__.jsx)(SnackbarContentMessage, {
22023
+ className: classes.message,
22024
+ ownerState: ownerState,
22025
+ children: message
22026
+ }), action ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_10__.jsx)(SnackbarContentAction, {
22027
+ className: classes.action,
22028
+ ownerState: ownerState,
22029
+ children: action
22030
+ }) : null]
22031
+ });
22032
+ });
22033
+ true ? SnackbarContent.propTypes /* remove-proptypes */ = {
22034
+ // ┌────────────────────────────── Warning ──────────────────────────────┐
22035
+ // │ These PropTypes are generated from the TypeScript type definitions. │
22036
+ // │ To update them, edit the d.ts file and run `pnpm proptypes`. │
22037
+ // └─────────────────────────────────────────────────────────────────────┘
22038
+ /**
22039
+ * The action to display. It renders after the message, at the end of the snackbar.
22040
+ */
22041
+ action: prop_types__WEBPACK_IMPORTED_MODULE_1__.node,
22042
+ /**
22043
+ * Override or extend the styles applied to the component.
22044
+ */
22045
+ classes: prop_types__WEBPACK_IMPORTED_MODULE_1__.object,
22046
+ /**
22047
+ * @ignore
22048
+ */
22049
+ className: prop_types__WEBPACK_IMPORTED_MODULE_1__.string,
22050
+ /**
22051
+ * The message to display.
22052
+ */
22053
+ message: prop_types__WEBPACK_IMPORTED_MODULE_1__.node,
22054
+ /**
22055
+ * The ARIA role attribute of the element.
22056
+ * @default 'alert'
22057
+ */
22058
+ role: prop_types__WEBPACK_IMPORTED_MODULE_1__.string,
22059
+ /**
22060
+ * The system prop that allows defining system overrides as well as additional CSS styles.
22061
+ */
22062
+ sx: prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.arrayOf(prop_types__WEBPACK_IMPORTED_MODULE_1__.oneOfType([prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object, prop_types__WEBPACK_IMPORTED_MODULE_1__.bool])), prop_types__WEBPACK_IMPORTED_MODULE_1__.func, prop_types__WEBPACK_IMPORTED_MODULE_1__.object])
22063
+ } : 0;
22064
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (SnackbarContent);
22065
+
22066
+ /***/ }),
22067
+
22068
+ /***/ "./node_modules/@mui/material/esm/SnackbarContent/snackbarContentClasses.js":
22069
+ /*!**********************************************************************************!*\
22070
+ !*** ./node_modules/@mui/material/esm/SnackbarContent/snackbarContentClasses.js ***!
22071
+ \**********************************************************************************/
22072
+ /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
22073
+
22074
+ "use strict";
22075
+ __webpack_require__.r(__webpack_exports__);
22076
+ /* harmony export */ __webpack_require__.d(__webpack_exports__, {
22077
+ /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__),
22078
+ /* harmony export */ getSnackbarContentUtilityClass: () => (/* binding */ getSnackbarContentUtilityClass)
22079
+ /* harmony export */ });
22080
+ /* harmony import */ var _mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @mui/utils/generateUtilityClasses */ "./node_modules/@mui/utils/esm/generateUtilityClasses/generateUtilityClasses.js");
22081
+ /* harmony import */ var _mui_utils_generateUtilityClass__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @mui/utils/generateUtilityClass */ "./node_modules/@mui/utils/esm/generateUtilityClass/generateUtilityClass.js");
22082
+
22083
+
22084
+ function getSnackbarContentUtilityClass(slot) {
22085
+ return (0,_mui_utils_generateUtilityClass__WEBPACK_IMPORTED_MODULE_1__["default"])('MuiSnackbarContent', slot);
22086
+ }
22087
+ const snackbarContentClasses = (0,_mui_utils_generateUtilityClasses__WEBPACK_IMPORTED_MODULE_0__["default"])('MuiSnackbarContent', ['root', 'message', 'action']);
22088
+ /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (snackbarContentClasses);
22089
+
22090
+ /***/ }),
22091
+
20816
22092
  /***/ "./node_modules/@mui/material/esm/Stack/Stack.js":
20817
22093
  /*!*******************************************************!*\
20818
22094
  !*** ./node_modules/@mui/material/esm/Stack/Stack.js ***!
@@ -99612,38 +100888,41 @@ __webpack_require__.r(__webpack_exports__);
99612
100888
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CircularProgress/CircularProgress.js");
99613
100889
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormHelperText/FormHelperText.js");
99614
100890
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Alert/Alert.js");
99615
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControl/FormControl.js");
99616
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputLabel/InputLabel.js");
99617
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Select/Select.js");
99618
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/MenuItem/MenuItem.js");
99619
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControlLabel/FormControlLabel.js");
99620
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
99621
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tooltip/Tooltip.js");
99622
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButtonGroup/ToggleButtonGroup.js");
99623
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButton/ToggleButton.js");
99624
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Paper/Paper.js");
99625
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/createTheme.js");
99626
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/ThemeProvider.js");
99627
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AccountBalance.js");
99628
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AutoAwesome.js");
99629
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness4.js");
99630
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness7.js");
99631
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CheckCircle.js");
99632
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CloudDownload.js");
99633
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ContentCopy.js");
99634
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
99635
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/InfoOutlined.js");
99636
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Login.js");
99637
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Logout.js");
99638
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/NoteAdd.js");
99639
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Replay.js");
99640
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
99641
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Visibility.js");
99642
- /* harmony import */ var _PromptManagerDialog__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! ./PromptManagerDialog */ "./src/PromptManagerDialog.tsx");
99643
- /* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
99644
- /* harmony import */ var xlsx__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! xlsx */ "./node_modules/xlsx/xlsx.mjs");
99645
- /* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! jszip */ "./node_modules/jszip/dist/jszip.min.js");
99646
- /* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_51___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_51__);
100891
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputAdornment/InputAdornment.js");
100892
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tooltip/Tooltip.js");
100893
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControl/FormControl.js");
100894
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputLabel/InputLabel.js");
100895
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Select/Select.js");
100896
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/MenuItem/MenuItem.js");
100897
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControlLabel/FormControlLabel.js");
100898
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
100899
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButtonGroup/ToggleButtonGroup.js");
100900
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButton/ToggleButton.js");
100901
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Paper/Paper.js");
100902
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/createTheme.js");
100903
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/ThemeProvider.js");
100904
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AccountBalance.js");
100905
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AttachMoney.js");
100906
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AutoAwesome.js");
100907
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness4.js");
100908
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness7.js");
100909
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CheckCircle.js");
100910
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CloudDownload.js");
100911
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ContentCopy.js");
100912
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/DeleteOutline.js");
100913
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
100914
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/InfoOutlined.js");
100915
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Login.js");
100916
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Logout.js");
100917
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/NoteAdd.js");
100918
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Replay.js");
100919
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
100920
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Visibility.js");
100921
+ /* harmony import */ var _PromptManagerDialog__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! ./PromptManagerDialog */ "./src/PromptManagerDialog.tsx");
100922
+ /* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
100923
+ /* harmony import */ var xlsx__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! xlsx */ "./node_modules/xlsx/xlsx.mjs");
100924
+ /* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! jszip */ "./node_modules/jszip/dist/jszip.min.js");
100925
+ /* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_54___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_54__);
99647
100926
 
99648
100927
 
99649
100928
 
@@ -99704,6 +100983,183 @@ const INSTRUCTION_ROW = [
99704
100983
  "# Обязательно | The URL for the main image of your item. Images must be in a supported format (JPG/GIF/PNG) and at least 500 x 500 pixels.",
99705
100984
  "# Обязательно | Фирменное название товара. Не более 100 символов."
99706
100985
  ];
100986
+ /** Хвост ссылки для каталога: sub/utm и макросы Meta (не URL-encode — подстановка на стороне FB). */
100987
+ const CATALOG_LINK_TRACKING_SUFFIX = 'sub1={{ad.id}}&sub2={{adset.id}}&sub3={{campaign.id}}&sub4={{ad.name}}&sub5={{adset.name}}&sub6={{campaign.name}}&sub7={{placement}}&sub8={{site_source_name}}&utm_source=facebook&utm_medium=paid';
100988
+ /** Добавляет к URL лендинга creative_id и трекинговые параметры для строки каталога. */
100989
+ function appendCreativeIdToCatalogLink(baseUrl, creativeId) {
100990
+ const u = baseUrl.trim();
100991
+ if (!u)
100992
+ return u;
100993
+ const sep = u.includes('?') ? '&' : '?';
100994
+ return `${u}${sep}creative_id=${encodeURIComponent(creativeId)}&${CATALOG_LINK_TRACKING_SUFFIX}`;
100995
+ }
100996
+ /** Текст ответа из OpenRouter/OpenAI chat completion (string или массив частей). */
100997
+ function extractChatCompletionText(choice) {
100998
+ const msg = choice?.message;
100999
+ if (!msg)
101000
+ return '';
101001
+ const c = msg.content;
101002
+ if (typeof c === 'string')
101003
+ return c;
101004
+ if (Array.isArray(c)) {
101005
+ return c
101006
+ .map((part) => (typeof part === 'string' ? part : part?.text ?? part?.content ?? ''))
101007
+ .filter(Boolean)
101008
+ .join('');
101009
+ }
101010
+ if (c != null && typeof c === 'object' && typeof c.text === 'string') {
101011
+ return c.text;
101012
+ }
101013
+ return '';
101014
+ }
101015
+ function stripMarkdownJsonFence(raw) {
101016
+ let s = raw.trim();
101017
+ if (!s.startsWith('```'))
101018
+ return s;
101019
+ s = s.replace(/^```(?:json)?\s*/i, '');
101020
+ const end = s.lastIndexOf('```');
101021
+ if (end >= 0)
101022
+ s = s.slice(0, end).trim();
101023
+ return s;
101024
+ }
101025
+ /** Парсит JSON-массив переводов из ответа модели (с ```json или мусором вокруг). */
101026
+ function parsePairTranslationsJson(raw) {
101027
+ const cleaned = stripMarkdownJsonFence(raw);
101028
+ try {
101029
+ const parsed = JSON.parse(cleaned);
101030
+ if (Array.isArray(parsed))
101031
+ return parsed;
101032
+ }
101033
+ catch {
101034
+ /* далее — вырезка по скобкам */
101035
+ }
101036
+ const jsonMatch = cleaned.match(/\[[\s\S]*\]/);
101037
+ if (!jsonMatch)
101038
+ return null;
101039
+ try {
101040
+ const parsed = JSON.parse(jsonMatch[0]);
101041
+ return Array.isArray(parsed) ? parsed : null;
101042
+ }
101043
+ catch {
101044
+ return null;
101045
+ }
101046
+ }
101047
+ /** Убирает повторяющиеся префиксы «ОШИБКА:» и лишние пробелы в строке из ответа валидатора. */
101048
+ function normalizeValidationErrorText(s) {
101049
+ let t = s.trim().replace(/\s+/g, ' ');
101050
+ while (/^ОШИБКА[:\s]+/i.test(t)) {
101051
+ t = t.replace(/^ОШИБКА[:\s]+/i, '').trim();
101052
+ }
101053
+ return t;
101054
+ }
101055
+ /** Одна и та же формулировка из ответа модели не дублируется в UI и в промпте переделки. */
101056
+ function dedupeValidationErrors(errors) {
101057
+ const seen = new Set();
101058
+ const out = [];
101059
+ for (const raw of errors) {
101060
+ const n = normalizeValidationErrorText(raw);
101061
+ if (!n)
101062
+ continue;
101063
+ const key = n.toLowerCase();
101064
+ if (seen.has(key))
101065
+ continue;
101066
+ seen.add(key);
101067
+ out.push(n);
101068
+ }
101069
+ return out;
101070
+ }
101071
+ /** Строка «ОШИБКА: нет» при статусе пересборки — противоречие; не считать содержательной ошибкой. */
101072
+ function isValidationNegationLine(s) {
101073
+ const t = normalizeValidationErrorText(s).toLowerCase();
101074
+ if (!t)
101075
+ return true;
101076
+ if (t === 'нет')
101077
+ return true;
101078
+ if (t.includes('нет ошибок') || t.includes('ошибок нет'))
101079
+ return true;
101080
+ if (t === 'none' || /^no errors?\.?$/i.test(t))
101081
+ return true;
101082
+ return false;
101083
+ }
101084
+ /** Все подписанные строки ОШИБКА:/ERROR: (модель иногда пишет по-английски). */
101085
+ function extractLabeledValidationErrors(content) {
101086
+ const out = [];
101087
+ const patterns = [
101088
+ /(?:^|\n)\s*ОШИБКА\s*[:\s]\s*([^\n]+)/gi,
101089
+ /(?:^|\n)\s*ERROR\s*[:\s]\s*([^\n]+)/gi,
101090
+ ];
101091
+ for (const re of patterns) {
101092
+ let m;
101093
+ const r = new RegExp(re.source, re.flags);
101094
+ while ((m = r.exec(content)) !== null) {
101095
+ const t = normalizeValidationErrorText(m[1]);
101096
+ if (t)
101097
+ out.push(t);
101098
+ }
101099
+ }
101100
+ return out;
101101
+ }
101102
+ /**
101103
+ * Если модель поставила НУЖНА ПЕРЕСБОРКА, но не оформила список как ОШИБКА: — забираем осмысленные строки
101104
+ * между статусом и блоком РЕКОМЕНДАЦИЯ (часто там остаётся описание причин).
101105
+ */
101106
+ function extractFallbackValidationErrorsBetweenStatusAndRecommendations(content) {
101107
+ const statusNeed = /СТАТУС\s*:\s*НУЖНА\s+ПЕРЕСБОРКА/i;
101108
+ const idx = content.search(statusNeed);
101109
+ if (idx < 0)
101110
+ return [];
101111
+ const tail = content.slice(idx);
101112
+ const firstNl = tail.indexOf('\n');
101113
+ const blockStart = firstNl >= 0 ? idx + firstNl + 1 : content.length;
101114
+ const rest = content.slice(blockStart);
101115
+ const recIdx = rest.search(/\nРЕКОМЕНДАЦИЯ\s*:/i);
101116
+ const block = recIdx >= 0 ? rest.slice(0, recIdx) : rest.slice(0, 3500);
101117
+ const lines = block.split('\n').map(l => l.trim()).filter(l => {
101118
+ if (l.length < 12)
101119
+ return false;
101120
+ if (/^(затем|список|каждая)\s/i.test(l))
101121
+ return false;
101122
+ if (/^ОШИБКА\s*[:\s]*нет\s*\.?$/i.test(l))
101123
+ return false;
101124
+ if (/^РЕКОМЕНДАЦИЯ\s*:/i.test(l))
101125
+ return false;
101126
+ if (/^ШАГ\s+[\dP]/i.test(l))
101127
+ return false;
101128
+ if (/^(?:HOOK|HEADLINE|PRICE|DISCOUNT|CTA|OTHER_TEXT)\s*:/i.test(l))
101129
+ return false;
101130
+ if (/^СТАТУС\s*:/i.test(l))
101131
+ return false;
101132
+ return true;
101133
+ });
101134
+ return lines
101135
+ .map(l => normalizeValidationErrorText(l.replace(/^ОШИБКА\s*[:\s]+/i, '')))
101136
+ .filter(Boolean);
101137
+ }
101138
+ /** Короткий фрагмент блока ФИНАЛ для подсказки, если структура ответа нестандартная. */
101139
+ function extractValidationFinalSnippet(content, maxLen) {
101140
+ const fi = content.search(/\bФИНАЛ\s*:/i);
101141
+ if (fi < 0)
101142
+ return null;
101143
+ let sn = content.slice(fi, fi + maxLen).replace(/\s+/g, ' ').trim();
101144
+ if (sn.length < 50)
101145
+ return null;
101146
+ if (sn.length > maxLen)
101147
+ sn = `${sn.slice(0, maxLen - 1)}…`;
101148
+ return sn;
101149
+ }
101150
+ /**
101151
+ * Разбор строк «ЗАГОЛОВОК n:» / «ТЕКСТ n:» из ответа модели.
101152
+ * Иногда модель пишет ZAGОЛОВОК (латиница ZAG + кириллица ОЛОВОК) или ZAGOLOVOK — без этого парсер не видит заголовки.
101153
+ */
101154
+ const PAIRS_TITLE_LINE_RE = /^[\s\uFEFF]*(?:\*{1,2})?\s*(?:ЗАГОЛОВОК|ZAG[ОOо][ЛLl][ОOо][ВBb][ОOо][КKk]|ZAGOLOVOK)\s+(\d+)\s*:\s*(.+)$/iu;
101155
+ const PAIRS_TEXT_LINE_RE = /^[\s\uFEFF]*(?:\*{1,2})?\s*(?:ТЕКСТ|TEKST)\s+(\d+)\s*:\s*(.*)$/iu;
101156
+ /** Число из поля цены для быстрого переключения валюты; если нет — 99 */
101157
+ function extractLeadingPriceNumber(value) {
101158
+ const m = value.trim().match(/(\d+(?:[.,]\d+)?)/);
101159
+ if (m)
101160
+ return m[1].replace(',', '.');
101161
+ return '99';
101162
+ }
99707
101163
  function App() {
99708
101164
  const [clientId, setClientId] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
99709
101165
  const [clientSecret, setClientSecret] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
@@ -99946,9 +101402,11 @@ function App() {
99946
101402
  const [uploadedLink, setUploadedLink] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
99947
101403
  const [testLoading, setTestLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
99948
101404
  const [linkCopied, setLinkCopied] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101405
+ const [pairsJsonCopied, setPairsJsonCopied] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
99949
101406
  const [openRouterKeyCopied, setOpenRouterKeyCopied] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
99950
101407
  const [loadingContentFromDrive, setLoadingContentFromDrive] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
99951
101408
  const [driveFilesFound, setDriveFilesFound] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({ content: false });
101409
+ const syncDriveAfterPromptSaveRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(() => { });
99952
101410
  // Theme state
99953
101411
  const [darkMode, setDarkMode] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
99954
101412
  const saved = localStorage.getItem('themeMode');
@@ -99995,7 +101453,7 @@ function App() {
99995
101453
  }
99996
101454
  };
99997
101455
  // Create theme based on mode
99998
- const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"])({
101456
+ const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"])({
99999
101457
  palette: {
100000
101458
  mode: darkMode ? 'dark' : 'light',
100001
101459
  ...(darkMode
@@ -100087,7 +101545,7 @@ function App() {
100087
101545
  };
100088
101546
  loadKey();
100089
101547
  // Load prompt overrides from Electron config
100090
- (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_49__.loadOverridesFromElectron)();
101548
+ (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.loadOverridesFromElectron)();
100091
101549
  }, []);
100092
101550
  // Save form fields to localStorage whenever they change
100093
101551
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
@@ -100143,6 +101601,8 @@ function App() {
100143
101601
  setTitles('');
100144
101602
  setTexts(['']);
100145
101603
  setLink('');
101604
+ setUploadedLink('');
101605
+ setPairTranslations({});
100146
101606
  return;
100147
101607
  }
100148
101608
  const folderId = extractFolderId(driveFolderUrl);
@@ -100157,6 +101617,8 @@ function App() {
100157
101617
  setTitles('');
100158
101618
  setTexts(['']);
100159
101619
  setLink('');
101620
+ setUploadedLink('');
101621
+ setPairTranslations({});
100160
101622
  return;
100161
101623
  }
100162
101624
  logToTerminal('log', '[Load] driveFolderUrl changed, clearing old data and loading from folderId:', folderId);
@@ -100167,6 +101629,8 @@ function App() {
100167
101629
  setTitles('');
100168
101630
  setTexts(['']);
100169
101631
  setLink('');
101632
+ setUploadedLink('');
101633
+ setPairTranslations({});
100170
101634
  setLoadingContentFromDrive(true);
100171
101635
  setDriveFilesFound({ content: false });
100172
101636
  // Load content from Google Drive
@@ -100437,11 +101901,11 @@ function App() {
100437
101901
  const data = await response.json();
100438
101902
  const hasProduct = data.files.some((f) => {
100439
101903
  const name = f.name?.toLowerCase() || '';
100440
- return name === 'product.png' || name === 'product.jpg';
101904
+ return name === 'product.png' || name === 'product.jpg' || name === 'product.webp';
100441
101905
  });
100442
101906
  const hasCreativeImages = data.files.some((f) => {
100443
101907
  const name = f.name?.toLowerCase() || '';
100444
- return name !== 'product.png' && name !== 'product.jpg';
101908
+ return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
100445
101909
  });
100446
101910
  if (!cancelled) {
100447
101911
  setFolderFilesInfo({ hasProduct, hasCreativeImages });
@@ -101416,7 +102880,7 @@ function App() {
101416
102880
  for (let li = 0; li < lines.length; li++) {
101417
102881
  // Trim for matching (handles leading spaces, tabs, zero-width chars from model)
101418
102882
  const trimmed = lines[li].trim();
101419
- const titleMatch = trimmed.match(/^ЗАГОЛОВОК\s+(\d+)\s*:\s*(.+)/i);
102883
+ const titleMatch = trimmed.match(PAIRS_TITLE_LINE_RE);
101420
102884
  if (titleMatch) {
101421
102885
  // flush pending text
101422
102886
  if (currentTextNum > 0) {
@@ -101427,7 +102891,7 @@ function App() {
101427
102891
  titleMap[parseInt(titleMatch[1])] = titleMatch[2].trim();
101428
102892
  continue;
101429
102893
  }
101430
- const textMatch = trimmed.match(/^ТЕКСТ\s+(\d+)\s*:\s*(.*)/i);
102894
+ const textMatch = trimmed.match(PAIRS_TEXT_LINE_RE);
101431
102895
  if (textMatch) {
101432
102896
  // flush previous text if any
101433
102897
  if (currentTextNum > 0) {
@@ -101495,27 +102959,73 @@ function App() {
101495
102959
  },
101496
102960
  body: JSON.stringify(requestBody)
101497
102961
  });
101498
- if (!response.ok)
102962
+ if (!response.ok) {
102963
+ logToTerminal('warn', '[Translate RU] HTTP', response.status, '— перевод пар пропущен');
101499
102964
  return;
102965
+ }
101500
102966
  const data = await response.json();
101501
- const raw = data.choices?.[0]?.message?.content || '';
101502
- const jsonMatch = raw.match(/\[[\s\S]*\]/);
101503
- if (!jsonMatch)
102967
+ const choice = data.choices?.[0];
102968
+ let raw = extractChatCompletionText(choice) ||
102969
+ (typeof choice?.text === 'string' ? choice.text : '') ||
102970
+ '';
102971
+ if (!raw.trim()) {
102972
+ logToTerminal('warn', '[Translate RU] Пустой ответ модели (content), перевод не выполнен');
102973
+ return;
102974
+ }
102975
+ const parsed = parsePairTranslationsJson(raw);
102976
+ if (!parsed || parsed.length === 0) {
102977
+ logToTerminal('warn', '[Translate RU] Не удалось разобрать JSON-массив переводов, превью:', raw.substring(0, 280));
101504
102978
  return;
101505
- const parsed = JSON.parse(jsonMatch[0]);
102979
+ }
101506
102980
  const translations = {};
101507
102981
  parsed.forEach((item, idx) => {
101508
102982
  translations[idx] = { titleRu: item.titleRu || '', textRu: item.textRu || '' };
101509
102983
  });
101510
102984
  setPairTranslations(translations);
102985
+ logToTerminal('log', '[Translate RU] OK, пар переведено:', parsed.length);
101511
102986
  }
101512
102987
  catch {
101513
- // тихо игнорируем ошибки переводаэто вспомогательная функция
102988
+ logToTerminal('warn', '[Translate RU] Ошибка запроса или разбора см. консоль / лог');
101514
102989
  }
101515
102990
  finally {
101516
102991
  setTranslatingPairs(false);
101517
102992
  }
101518
102993
  };
102994
+ /** Удалить одну сгенерированную пару (заголовок + текст) и сдвинуть индексы. */
102995
+ const handleDeleteGeneratedPair = (pairIndex) => {
102996
+ if (!window.confirm(`Удалить пару ${pairIndex + 1}?`))
102997
+ return;
102998
+ setGeneratedTitlesData(prev => {
102999
+ const next = prev.filter((_, idx) => idx !== pairIndex).map((t, idx) => ({ ...t, index: idx + 1 }));
103000
+ setTitles(next.map(t => t.title).filter(Boolean).join('\n'));
103001
+ return next;
103002
+ });
103003
+ setGeneratedTextsData(prev => {
103004
+ const next = prev.filter((_, idx) => idx !== pairIndex).map((t, idx) => ({ ...t, index: idx + 1 }));
103005
+ setTexts(next.length ? next.map(t => t.text) : ['']);
103006
+ return next;
103007
+ });
103008
+ setLastUsedApproachIndices(prev => prev.filter((_, idx) => idx !== pairIndex));
103009
+ setPairTranslations(prev => {
103010
+ const next = {};
103011
+ Object.entries(prev).forEach(([k, v]) => {
103012
+ const n = Number(k);
103013
+ if (Number.isNaN(n))
103014
+ return;
103015
+ if (n < pairIndex)
103016
+ next[n] = v;
103017
+ else if (n > pairIndex)
103018
+ next[n - 1] = v;
103019
+ });
103020
+ return next;
103021
+ });
103022
+ };
103023
+ /** Удалить один сгенерированный креатив и перенумеровать слоты. */
103024
+ const handleDeleteGeneratedImage = (imageIndex) => {
103025
+ if (!window.confirm(`Удалить креатив ${imageIndex}?`))
103026
+ return;
103027
+ setGeneratedImagesData(prev => prev.filter(img => img.index !== imageIndex).map((img, idx) => ({ ...img, index: idx + 1 })));
103028
+ };
101519
103029
  const handleGenerateContent = async () => {
101520
103030
  if (!generateProduct.trim() || !generateGeo.trim()) {
101521
103031
  alert('Please fill in Product and Geo fields');
@@ -101531,7 +103041,7 @@ function App() {
101531
103041
  setTexts(['']);
101532
103042
  setPairTranslations({});
101533
103043
  // Read pairs count from settings (3–10, default 3)
101534
- const pairsCountInit = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_49__.getPairsCount)();
103044
+ const pairsCountInit = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getPairsCount)();
101535
103045
  // Initialize placeholders
101536
103046
  const initialTitles = Array.from({ length: pairsCountInit }, (_, index) => ({
101537
103047
  index: index + 1,
@@ -101560,7 +103070,7 @@ function App() {
101560
103070
  }
101561
103071
  // Generate all pairs (title + text) in a single request
101562
103072
  addLog(formatLogMessage('log', '📋 Generating title+text pairs in a single request...'));
101563
- const selectedIndices = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_49__.getSelectedPairApproaches)();
103073
+ const selectedIndices = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getSelectedPairApproaches)();
101564
103074
  setLastUsedApproachIndices(selectedIndices);
101565
103075
  const pairsCount = selectedIndices.length;
101566
103076
  addLog(formatLogMessage('log', `⚙️ Generating ${pairsCount} pairs (approaches: ${selectedIndices.join(', ')})`));
@@ -101997,7 +103507,21 @@ function App() {
101997
103507
  };
101998
103508
  const keywords = geoKeywords[geo.toUpperCase()] || ['продукт', 'проблема'];
101999
103509
  logMsg('log', `🔑 Ключевые слова: ${keywords.join(', ')}`);
102000
- const validationPrompt = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getValidationPrompt)(product, geo, keywords, approachName);
103510
+ const { price: briefPrice, currency: briefCurrency, currencySymbol } = parsePriceAndCurrency(generatePriceWithCurrency);
103511
+ let priceBriefForValidation = '';
103512
+ if (briefPrice && briefCurrency) {
103513
+ const nv = parseFloat(String(briefPrice).replace(',', '.'));
103514
+ const oldNum = Number.isFinite(nv) && nv > 0 ? nv * 2 : NaN;
103515
+ const oldStr = Number.isFinite(oldNum)
103516
+ ? (Number.isInteger(oldNum) ? String(oldNum) : (Math.round(oldNum * 100) / 100).toString().replace(/\.?0+$/, ''))
103517
+ : '';
103518
+ priceBriefForValidation = `Новая цена по брифу (после скидки -50%): ${briefPrice} ${briefCurrency}${currencySymbol ? `, символ валюты: ${currencySymbol}` : ''}. ${Number.isFinite(oldNum) ? `Ожидаемая старая цена до скидки: ${oldStr} ${briefCurrency} (2× новой).` : 'Старая цена на макете должна быть в 2 раза больше новой.'} Любые другие суммы — ошибка «не совпадает с брифом».`;
103519
+ logMsg('log', `💶 Эталон цен для валидации: новая ${briefPrice} ${briefCurrency}${oldStr ? `, старая ${oldStr}` : ''}`);
103520
+ }
103521
+ else {
103522
+ logMsg('log', '💶 Поле цены в приложении пустое — валидатор сверяет только визуал двух цен');
103523
+ }
103524
+ const validationPrompt = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getValidationPrompt)(product, geo, keywords, approachName, undefined, priceBriefForValidation);
102001
103525
  const requestBody = {
102002
103526
  model: selectedValidationModel,
102003
103527
  messages: [
@@ -102136,25 +103660,28 @@ function App() {
102136
103660
  }
102137
103661
  // Update balance after successful API call
102138
103662
  fetchOpenRouterBalance();
102139
- // Парсим результат
102140
- const statusMatch = content.match(/СТАТУС:\s*(OK|НУЖНА ПЕРЕСБОРКА)/i);
102141
- const status = statusMatch ? (statusMatch[1].toUpperCase() === 'OK' ? 'ok' : 'needs_rebuild') : 'needs_rebuild';
102142
- // Извлекаем ошибки
102143
- const errors = [];
102144
- const errorMatches = content.match(/ОШИБКА[:\s]+([^\n]+)/gi);
102145
- if (errorMatches) {
102146
- errors.push(...errorMatches
102147
- .map(m => m.replace(/ОШИБКА[:\s]+/i, '').trim())
102148
- .filter(err => {
102149
- const lowerErr = err.toLowerCase();
102150
- // Игнорируем "нет", "нет ошибок", "ошибок нет" и подобные
102151
- return lowerErr !== 'нет' &&
102152
- !lowerErr.includes('нет ошибок') &&
102153
- !lowerErr.includes('ошибок нет') &&
102154
- err.length > 0;
102155
- }));
103663
+ // Парсим результат (английский STATUS — на случай ответа модели не по шаблону)
103664
+ const statusMatchRu = content.match(/СТАТУС\s*:\s*(OK|НУЖНА\s+ПЕРЕСБОРКА)/i);
103665
+ const statusMatchEn = content.match(/\bSTATUS\s*:\s*(OK|NEEDS?\s+REBUILD|FAIL|FAILED)\b/i);
103666
+ const statusToken = statusMatchRu?.[1] ?? statusMatchEn?.[1] ?? '';
103667
+ const status = (() => {
103668
+ if (!statusToken)
103669
+ return 'needs_rebuild';
103670
+ const u = statusToken.toUpperCase().replace(/\s+/g, ' ');
103671
+ if (u === 'OK')
103672
+ return 'ok';
103673
+ if (u.includes('NEED') || u === 'FAIL' || u === 'FAILED')
103674
+ return 'needs_rebuild';
103675
+ if (u.includes('НУЖНА') || u.includes('ПЕРЕСБОРКА'))
103676
+ return 'needs_rebuild';
103677
+ return 'needs_rebuild';
103678
+ })();
103679
+ let errors = extractLabeledValidationErrors(content).filter(e => !isValidationNegationLine(e));
103680
+ errors = dedupeValidationErrors(errors);
103681
+ // Противоречие: пересборка, а единственная строка была «ОШИБКА: нет» — тянем текст из хвоста ответа
103682
+ if (status === 'needs_rebuild' && errors.length === 0) {
103683
+ errors = dedupeValidationErrors(extractFallbackValidationErrorsBetweenStatusAndRecommendations(content));
102156
103684
  }
102157
- // Если статус "НУЖНА ПЕРЕСБОРКА", но ошибок нет в формате ОШИБКА, ищем в тексте
102158
103685
  if (status === 'needs_rebuild' && errors.length === 0) {
102159
103686
  const lines = content.split('\n').filter(line => line.includes('нарушено') ||
102160
103687
  line.includes('проблема') ||
@@ -102162,10 +103689,20 @@ function App() {
102162
103689
  line.includes('не хватает'));
102163
103690
  if (lines.length > 0) {
102164
103691
  errors.push(...lines.map(l => l.trim()).filter(l => l.length > 0));
103692
+ errors = dedupeValidationErrors(errors);
102165
103693
  }
102166
103694
  }
102167
103695
  const totalElapsed = Date.now() - validationStartTime;
102168
- const finalErrors = errors.length > 0 ? errors : (status === 'needs_rebuild' ? ['Обнаружены нарушения в креативе'] : []);
103696
+ const snippet = status === 'needs_rebuild' && errors.length === 0
103697
+ ? extractValidationFinalSnippet(content, 900)
103698
+ : null;
103699
+ const finalErrors = errors.length > 0
103700
+ ? errors
103701
+ : status === 'needs_rebuild'
103702
+ ? (snippet
103703
+ ? [`Валидатор не выписал строки «ОШИБКА:». Фрагмент ответа: ${snippet}`]
103704
+ : ['Валидатор указал пересборку, но не перечислил причины (нет строк «ОШИБКА:»). Откройте полный текст ответа модели в логе или повторите проверку.'])
103705
+ : [];
102169
103706
  logMsg('log', `✅ === Валидация завершена ===`);
102170
103707
  logMsg('log', `⏱️ Общее время: ${Math.round(totalElapsed / 1000)}s`);
102171
103708
  logMsg('log', `📊 Статус: ${status === 'ok' ? '✅ OK' : '❌ НУЖНА ПЕРЕСБОРКА'}`);
@@ -102194,8 +103731,8 @@ function App() {
102194
103731
  return;
102195
103732
  e.target.value = '';
102196
103733
  const ext = file.name.toLowerCase().split('.').pop();
102197
- if (ext !== 'png' && ext !== 'jpg' && ext !== 'jpeg') {
102198
- alert('Выберите изображение PNG или JPG');
103734
+ if (ext !== 'png' && ext !== 'jpg' && ext !== 'jpeg' && ext !== 'webp') {
103735
+ alert('Выберите изображение PNG, JPG или WebP');
102199
103736
  return;
102200
103737
  }
102201
103738
  setUploadingProduct(true);
@@ -102219,12 +103756,12 @@ function App() {
102219
103756
  reader.onerror = reject;
102220
103757
  reader.readAsDataURL(file);
102221
103758
  });
102222
- const filename = ext === 'png' ? 'product.png' : 'product.jpg';
102223
- logToTerminal('log', '📤 Загрузка product.png/jpg...');
103759
+ const filename = ext === 'png' ? 'product.png' : ext === 'webp' ? 'product.webp' : 'product.jpg';
103760
+ logToTerminal('log', `📤 Загрузка ${filename}...`);
102224
103761
  await uploadImageToDrive(dataUrl, filename, folderId, addLog);
102225
- logToTerminal('log', '✅ product.png/jpg загружен');
103762
+ logToTerminal('log', `✅ ${filename} загружен`);
102226
103763
  setFolderFilesInfo(prev => prev ? { ...prev, hasProduct: true } : { hasProduct: true });
102227
- alert('product.png/jpg успешно загружен в папку!');
103764
+ alert(`${filename} успешно загружен в папку!`);
102228
103765
  }
102229
103766
  catch (err) {
102230
103767
  const errorMsg = 'Ошибка загрузки: ' + err.message;
@@ -102465,17 +104002,19 @@ function App() {
102465
104002
  fetchOpenRouterBalance();
102466
104003
  return html;
102467
104004
  };
102468
- const createZipArchive = async (htmlContent, productImageBlob, addLog) => {
104005
+ const createZipArchive = async (htmlContent, productImageBlob, productImageName, addLog) => {
102469
104006
  const logMsg = (level, ...args) => {
102470
104007
  logToTerminal(level, ...args);
102471
104008
  if (addLog)
102472
104009
  addLog(formatLogMessage(level, ...args));
102473
104010
  };
102474
104011
  logMsg('log', '📦 Creating ZIP archive with HTML and product image...');
102475
- const zip = new (jszip__WEBPACK_IMPORTED_MODULE_51___default())();
102476
- zip.file('index.html', htmlContent);
102477
- zip.file('product.png', productImageBlob);
102478
- logMsg('log', '✅ Files added to archive: index.html, product.png');
104012
+ const zip = new (jszip__WEBPACK_IMPORTED_MODULE_54___default())();
104013
+ // Replace product image path in HTML to match actual filename (png/jpg/webp)
104014
+ const htmlWithProductPath = htmlContent.replace(/src=["']product\.(png|jpe?g|webp)["']/gi, `src="${productImageName}"`);
104015
+ zip.file('index.html', htmlWithProductPath);
104016
+ zip.file(productImageName, productImageBlob);
104017
+ logMsg('log', `✅ Files added to archive: index.html, ${productImageName}`);
102479
104018
  return await zip.generateAsync({ type: 'blob' });
102480
104019
  };
102481
104020
  const uploadZipToDrive = async (zipBlob, filename, folderId, addLog) => {
@@ -102612,7 +104151,7 @@ function App() {
102612
104151
  };
102613
104152
  const handleCreateLanding = async () => {
102614
104153
  if (!folderFilesInfo?.hasProduct || !driveFolderUrl.trim()) {
102615
- alert('product.png/jpg не найден в папке. Сначала сгенерируйте его с помощью кнопки "Generate Product from Banka"');
104154
+ alert('product.png/jpg/webp не найден в папке. Сначала сгенерируйте его с помощью кнопки "Generate Product from Banka"');
102616
104155
  return;
102617
104156
  }
102618
104157
  if (!openaiApiKey) {
@@ -102642,11 +104181,11 @@ function App() {
102642
104181
  logToTerminal('log', '🔍 Получение изображения продукта...');
102643
104182
  const productImage = await fetchProductImage(folderId);
102644
104183
  if (!productImage) {
102645
- throw new Error('product.png/jpg not found in the folder');
104184
+ throw new Error('product.png/jpg/webp not found in the folder');
102646
104185
  }
102647
104186
  // Download product image as blob
102648
- addLog(formatLogMessage('log', '📥 Скачивание product.png...'));
102649
- logToTerminal('log', '📥 Скачивание product.png...');
104187
+ addLog(formatLogMessage('log', '📥 Скачивание изображения продукта...'));
104188
+ logToTerminal('log', '📥 Скачивание изображения продукта...');
102650
104189
  let token = await getValidAccessToken();
102651
104190
  if (!token) {
102652
104191
  throw new Error('Not logged in to Google Drive');
@@ -102702,7 +104241,7 @@ function App() {
102702
104241
  reader.readAsDataURL(productImageBlob);
102703
104242
  });
102704
104243
  // Replace relative image path with base64 data URL in HTML
102705
- const htmlWithImage = htmlContent.replace(/src=["']product\.(png|jpe?g)["']/gi, `src="${imageBase64}"`);
104244
+ const htmlWithImage = htmlContent.replace(/src=["']product\.(png|jpe?g|webp)["']/gi, `src="${imageBase64}"`);
102706
104245
  // Create blob URL and open in new window
102707
104246
  const blob = new Blob([htmlWithImage], { type: 'text/html' });
102708
104247
  const url = URL.createObjectURL(blob);
@@ -102721,7 +104260,7 @@ function App() {
102721
104260
  // Create ZIP archive with HTML and product image
102722
104261
  addLog(formatLogMessage('log', '📦 Создание ZIP архива с HTML и изображением...'));
102723
104262
  logToTerminal('log', '📦 Создание ZIP архива...');
102724
- const zipBlob = await createZipArchive(htmlContent, productImageBlob, addLog);
104263
+ const zipBlob = await createZipArchive(htmlContent, productImageBlob, productImage.name, addLog);
102725
104264
  addLog(formatLogMessage('log', '✅ ZIP архив создан'));
102726
104265
  // Upload ZIP to Google Drive
102727
104266
  const zipFilename = `landing_${Date.now()}.zip`;
@@ -102792,15 +104331,15 @@ function App() {
102792
104331
  throw new Error(errorMsg);
102793
104332
  }
102794
104333
  addLog(formatLogMessage('log', '✅ Folder ID extracted:', folderId));
102795
- // Check for product.png
102796
- addLog(formatLogMessage('log', '🔍 Checking for product.png...'));
104334
+ // Check for product image (png/jpg/webp)
104335
+ addLog(formatLogMessage('log', '🔍 Checking for product image...'));
102797
104336
  const productImage = await fetchProductImage(folderId);
102798
104337
  if (!productImage) {
102799
- const errorMsg = 'product.png/jpg not found in the folder. Please generate it first using "Generate Product from Banka" button.';
104338
+ const errorMsg = 'product.png/jpg/webp not found in the folder. Please generate it first using "Generate Product from Banka" button.';
102800
104339
  addLog(formatLogMessage('error', errorMsg));
102801
104340
  throw new Error(errorMsg);
102802
104341
  }
102803
- addLog(formatLogMessage('log', '✅ product.png found'));
104342
+ addLog(formatLogMessage('log', '✅ Product image found'));
102804
104343
  // Generate images with different approaches (количество по каждому подходу)
102805
104344
  const approaches = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getCreoApproaches)();
102806
104345
  if (approaches.length === 0) {
@@ -102828,7 +104367,7 @@ function App() {
102828
104367
  const [b1, b2, b3] = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.pickRandomBullets)(t.approach.name);
102829
104368
  return `ОБЯЗАТЕЛЬНЫЕ БУЛЛЕТЫ (используй именно эти 3, в указанном порядке; переведи на язык ${generateGeo}): 1) ${b1} 2) ${b2} 3) ${b3}`;
102830
104369
  })();
102831
- return `🏷️ ПРОДУКТ: ${generateProduct}${additionalInfoLine}\n\n${basePromptStructure}🏷️ ПРОДУКТ (повторение для ясности): ${generateProduct}${additionalInfoLine}\n🎯 ПОДХОД: ${t.approach.name}\n\n${t.approach.prompt}\n\n${t.approach.headlineAngle}\n\n${bulletsLine}\n\nТекст — строго следуй правилам этого подхода (HOOK обязателен; буллиты добавляй только если они разрешены для подхода).`;
104370
+ return `🏷️ ПРОДУКТ: ${generateProduct}${additionalInfoLine}\n\n${basePromptStructure}🏷️ ПРОДУКТ (повторение для ясности): ${generateProduct}${additionalInfoLine}\n🎯 ПОДХОД: ${t.approach.name}\n\n${t.approach.prompt}\n\n${t.approach.headlineAngle}\n\n${bulletsLine}\n\nТекст — строго следуй правилам этого подхода (верхний заголовок обязателен; на макете не пиши слова HOOK/CTA/CAPS; буллиты добавляй только если они разрешены для подхода).`;
102832
104371
  });
102833
104372
  // Initialize placeholders for all images
102834
104373
  const initialPlaceholders = tasks.map((t, index) => ({
@@ -103112,8 +104651,7 @@ function App() {
103112
104651
  ...img,
103113
104652
  regenerating: true,
103114
104653
  regenerateStartTime: Date.now(),
103115
- checkStatus: 'pending',
103116
- imageUrl: undefined // Clear old image URL to force re-render with new one
104654
+ checkStatus: 'pending'
103117
104655
  }
103118
104656
  : img));
103119
104657
  addLog(formatLogMessage('log', `🔄 Переделка изображения ${imageData.index} (${imageData.approach})...`));
@@ -103339,8 +104877,7 @@ ${imageData.originalPrompt}
103339
104877
  checkResult: undefined,
103340
104878
  checkErrors: undefined,
103341
104879
  // Explicitly ignore any previous comments
103342
- customRegeneratePrompt: '',
103343
- imageUrl: undefined // Clear old image URL to force re-render with new one
104880
+ customRegeneratePrompt: ''
103344
104881
  }
103345
104882
  : img));
103346
104883
  addLog(formatLogMessage('log', `🔁 Переделка заново (с нуля) изображения ${imageData.index} (${imageData.approach})...`));
@@ -103606,8 +105143,12 @@ ${imageData.originalPrompt}
103606
105143
  try {
103607
105144
  const parsed = new URL(toParse);
103608
105145
  let path = parsed.pathname || '/';
103609
- if (!path.endsWith('/'))
103610
- path += '/';
105146
+ // Корень сайта — оставляем как `/`. Если есть «тело» пути (не один домен), завершающий `/` убираем, не добавляем.
105147
+ if (path !== '/' && path.length > 1) {
105148
+ while (path.length > 1 && path.endsWith('/')) {
105149
+ path = path.slice(0, -1);
105150
+ }
105151
+ }
103611
105152
  const result = `https://${parsed.host}${path}${parsed.search}${parsed.hash}`;
103612
105153
  setLink(result);
103613
105154
  setLinkError('');
@@ -103657,10 +105198,10 @@ ${imageData.originalPrompt}
103657
105198
  throw new Error(err.error?.message || 'Failed to fetch Drive files');
103658
105199
  }
103659
105200
  const data = await response.json();
103660
- // Filter out product.png/jpg (used for product reference, not creative images)
105201
+ // Filter out product.png/jpg/webp (used for product reference, not creative images)
103661
105202
  const filteredFiles = data.files.filter((f) => {
103662
105203
  const name = f.name?.toLowerCase() || '';
103663
- return name !== 'product.png' && name !== 'product.jpg';
105204
+ return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
103664
105205
  });
103665
105206
  return filteredFiles.map((f) => f.id ? `https://drive.google.com/file/d/${f.id}/view?usp=sharing` : '');
103666
105207
  };
@@ -103668,7 +105209,7 @@ ${imageData.originalPrompt}
103668
105209
  const validToken = await getValidAccessToken();
103669
105210
  if (!validToken)
103670
105211
  throw new Error('Not logged in');
103671
- const q = `'${folderId}' in parents and trashed = false and (name = 'product.png' or name = 'product.jpg')`;
105212
+ const q = `'${folderId}' in parents and trashed = false and (name = 'product.png' or name = 'product.jpg' or name = 'product.webp')`;
103672
105213
  const fields = 'files(id, name)';
103673
105214
  const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
103674
105215
  const response = await fetch(url, {
@@ -103682,9 +105223,10 @@ ${imageData.originalPrompt}
103682
105223
  }
103683
105224
  const data = await response.json();
103684
105225
  if (data.files && data.files.length > 0) {
103685
- // Prefer product.png over product.jpg if both exist
105226
+ // Prefer product.png > product.webp > product.jpg if multiple exist
103686
105227
  const pngFile = data.files.find((f) => f.name?.toLowerCase() === 'product.png');
103687
- const file = pngFile || data.files[0];
105228
+ const webpFile = data.files.find((f) => f.name?.toLowerCase() === 'product.webp');
105229
+ const file = pngFile || webpFile || data.files[0];
103688
105230
  return {
103689
105231
  id: file.id,
103690
105232
  name: file.name,
@@ -103693,104 +105235,61 @@ ${imageData.originalPrompt}
103693
105235
  }
103694
105236
  return null;
103695
105237
  };
103696
- // Track ongoing folder creation promises to prevent race conditions
103697
- const envFolderCreationPromises = new Map();
103698
- // Get or create 'env' folder inside the main folder
103699
- const getOrCreateEnvFolder = async (parentFolderId) => {
103700
- // If there's already a creation in progress for this folder, wait for it
103701
- const existingPromise = envFolderCreationPromises.get(parentFolderId);
103702
- if (existingPromise) {
103703
- logToTerminal('log', '[Env Folder] Waiting for ongoing creation for parent folder:', parentFolderId);
103704
- return existingPromise;
103705
- }
103706
- // Create a new promise for this folder creation
103707
- const creationPromise = (async () => {
103708
- try {
103709
- return await getOrCreateEnvFolderImpl(parentFolderId);
103710
- }
103711
- finally {
103712
- // Remove from map when done (success or failure)
103713
- envFolderCreationPromises.delete(parentFolderId);
103714
- }
103715
- })();
103716
- envFolderCreationPromises.set(parentFolderId, creationPromise);
103717
- return creationPromise;
103718
- };
103719
- // Implementation of getOrCreateEnvFolder
103720
- const getOrCreateEnvFolderImpl = async (parentFolderId) => {
105238
+ const PROJECT_SETTINGS_FILENAME = 'project-settings.json';
105239
+ /** Старое имя файла — всё ещё ищем при загрузке; при сохранении переименуем в project-settings.json. */
105240
+ const LEGACY_PROJECT_SETTINGS_FILENAME = 'temp-generated-content.json';
105241
+ /** Папки `env` внутри проекта (только поиск, без создания) для обратной совместимости и удаления после миграции. */
105242
+ const findEnvFolderIds = async (parentFolderId) => {
103721
105243
  const validToken = await getValidAccessToken();
103722
- if (!validToken) {
103723
- throw new Error('Not logged in to Google Drive');
103724
- }
103725
- // Check if 'env' folder exists
105244
+ if (!validToken)
105245
+ return [];
103726
105246
  const q = `'${parentFolderId}' in parents and trashed = false and name = 'env' and mimeType = 'application/vnd.google-apps.folder'`;
103727
105247
  const fields = 'files(id, name)';
103728
105248
  const searchUrl = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
103729
105249
  const searchResponse = await fetch(searchUrl, {
103730
- headers: {
103731
- 'Authorization': `Bearer ${validToken}`
103732
- }
105250
+ headers: { 'Authorization': `Bearer ${validToken}` }
103733
105251
  });
103734
- if (searchResponse.ok) {
105252
+ if (!searchResponse.ok)
105253
+ return [];
105254
+ const searchData = await searchResponse.json();
105255
+ return (searchData.files || []).map((f) => f.id).filter(Boolean);
105256
+ };
105257
+ /** Ищет JSON настроек в папке: сначала project-settings.json, иначе legacy temp-generated-content.json. */
105258
+ const findSettingsFileInFolder = async (parentFolderId) => {
105259
+ const validToken = await getValidAccessToken();
105260
+ if (!validToken)
105261
+ return null;
105262
+ const fields = 'files(id, name)';
105263
+ for (const fileName of [PROJECT_SETTINGS_FILENAME, LEGACY_PROJECT_SETTINGS_FILENAME]) {
105264
+ const q = `'${parentFolderId}' in parents and trashed = false and name = '${fileName}' and mimeType != 'application/vnd.google-apps.folder'`;
105265
+ const searchUrl = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
105266
+ const searchResponse = await fetch(searchUrl, {
105267
+ headers: { 'Authorization': `Bearer ${validToken}` }
105268
+ });
105269
+ if (!searchResponse.ok)
105270
+ continue;
103735
105271
  const searchData = await searchResponse.json();
103736
105272
  if (searchData.files && searchData.files.length > 0) {
103737
- // If multiple folders found, use the first one (shouldn't happen, but handle it)
103738
- const envFolderId = searchData.files[0].id;
103739
- logToTerminal('log', '[Env Folder] Found existing env folder, id:', envFolderId);
103740
105273
  if (searchData.files.length > 1) {
103741
- logToTerminal('warn', '[Env Folder] Multiple env folders found, using first one. Total:', searchData.files.length);
105274
+ logToTerminal('warn', '[Drive Settings] Multiple JSON with same name, using first:', fileName);
103742
105275
  }
103743
- return envFolderId;
105276
+ return searchData.files[0].id;
103744
105277
  }
103745
105278
  }
103746
- else {
103747
- // If search failed, log error but continue to try creating
103748
- const errorText = await searchResponse.text();
103749
- logToTerminal('warn', '[Env Folder] Search failed, will try to create. Status:', searchResponse.status, 'Error:', errorText);
103750
- }
103751
- // Create 'env' folder if it doesn't exist
103752
- logToTerminal('log', '[Env Folder] Creating env folder in parent folder:', parentFolderId);
103753
- const createMetadata = {
103754
- name: 'env',
103755
- mimeType: 'application/vnd.google-apps.folder',
103756
- parents: [parentFolderId]
103757
- };
103758
- const createResponse = await fetch('https://www.googleapis.com/drive/v3/files', {
103759
- method: 'POST',
103760
- headers: {
103761
- 'Authorization': `Bearer ${validToken}`,
103762
- 'Content-Type': 'application/json'
103763
- },
103764
- body: JSON.stringify(createMetadata)
105279
+ return null;
105280
+ };
105281
+ const trashDriveFile = async (fileId) => {
105282
+ const validToken = await getValidAccessToken();
105283
+ if (!validToken)
105284
+ return;
105285
+ const res = await fetch(`https://www.googleapis.com/drive/v3/files/${fileId}`, {
105286
+ method: 'DELETE',
105287
+ headers: { 'Authorization': `Bearer ${validToken}` }
103765
105288
  });
103766
- if (!createResponse.ok) {
103767
- const err = await createResponse.json();
103768
- const errorMessage = err.error?.message || '';
103769
- // If folder already exists (race condition), try to find it again
103770
- if (errorMessage.includes('already exists') || errorMessage.includes('duplicate') || createResponse.status === 409) {
103771
- logToTerminal('log', '[Env Folder] Folder creation failed (likely already exists), searching again...');
103772
- // Retry search after a short delay to allow for eventual consistency
103773
- await new Promise(resolve => setTimeout(resolve, 500));
103774
- const retrySearchResponse = await fetch(searchUrl, {
103775
- headers: {
103776
- 'Authorization': `Bearer ${validToken}`
103777
- }
103778
- });
103779
- if (retrySearchResponse.ok) {
103780
- const retrySearchData = await retrySearchResponse.json();
103781
- if (retrySearchData.files && retrySearchData.files.length > 0) {
103782
- const envFolderId = retrySearchData.files[0].id;
103783
- logToTerminal('log', '[Env Folder] Found existing env folder after retry, id:', envFolderId);
103784
- return envFolderId;
103785
- }
103786
- }
103787
- }
103788
- logToTerminal('error', '[Env Folder] Failed to create env folder:', JSON.stringify(err));
103789
- throw new Error(errorMessage || 'Failed to create env folder in Google Drive');
105289
+ if (!res.ok) {
105290
+ const t = await res.text();
105291
+ logToTerminal('warn', '[Drive Settings] Failed to trash/delete file:', fileId, res.status, t);
103790
105292
  }
103791
- const result = await createResponse.json();
103792
- logToTerminal('log', '[Env Folder] Successfully created env folder, id:', result.id);
103793
- return result.id;
103794
105293
  };
103795
105294
  const sanitizeGeneratedTitlesData = (titlesData) => {
103796
105295
  if (!Array.isArray(titlesData))
@@ -103828,8 +105327,6 @@ ${imageData.originalPrompt}
103828
105327
  logToTerminal('error', '[Save Content] No valid token');
103829
105328
  throw new Error('Not logged in to Google Drive');
103830
105329
  }
103831
- // Get or create 'env' folder
103832
- const envFolderId = await getOrCreateEnvFolder(folderId);
103833
105330
  const dataToSave = {
103834
105331
  aiGenerationSettings: aiSettings || {
103835
105332
  generateProduct: generateProduct || '',
@@ -103839,35 +105336,20 @@ ${imageData.originalPrompt}
103839
105336
  },
103840
105337
  brand: brandValue !== undefined ? brandValue : brand || '',
103841
105338
  link: linkValue !== undefined ? linkValue : link || '',
105339
+ selectedPairApproaches: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getSelectedPairApproaches)(),
105340
+ imageApproachCounts: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getImageApproachCounts)(),
103842
105341
  savedAt: new Date().toISOString()
103843
105342
  };
103844
105343
  const jsonContent = JSON.stringify(dataToSave, null, 2);
103845
- const filename = 'temp-generated-content.json';
103846
- logToTerminal('log', '[Save Content] Filename:', filename, 'content length:', jsonContent.length);
103847
- // Check if file already exists in 'env' folder
103848
- const q = `'${envFolderId}' in parents and trashed = false and name = '${filename}'`;
103849
- const fields = 'files(id, name)';
103850
- const searchUrl = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
103851
- const searchResponse = await fetch(searchUrl, {
103852
- headers: {
103853
- 'Authorization': `Bearer ${validToken}`
103854
- }
103855
- });
103856
- let fileId = null;
103857
- if (searchResponse.ok) {
103858
- const searchData = await searchResponse.json();
103859
- logToTerminal('log', '[Save Content] Search response, files found:', searchData.files?.length || 0);
103860
- if (searchData.files && searchData.files.length > 0) {
103861
- fileId = searchData.files[0].id;
103862
- logToTerminal('log', '[Save Content] File exists, will update, fileId:', fileId);
103863
- }
103864
- else {
103865
- logToTerminal('log', '[Save Content] File does not exist, will create new');
103866
- }
105344
+ const filename = PROJECT_SETTINGS_FILENAME;
105345
+ logToTerminal('log', '[Save Content] Filename (project root):', filename, 'content length:', jsonContent.length);
105346
+ // Файл в корне папки проекта (не в env)
105347
+ let fileId = await findSettingsFileInFolder(folderId);
105348
+ if (fileId) {
105349
+ logToTerminal('log', '[Save Content] File exists in folder root, will update, fileId:', fileId);
103867
105350
  }
103868
105351
  else {
103869
- const errorText = await searchResponse.text();
103870
- logToTerminal('warn', '[Save Content] Search failed, status:', searchResponse.status);
105352
+ logToTerminal('log', '[Save Content] No file in root yet, will create new at project root');
103871
105353
  }
103872
105354
  if (fileId) {
103873
105355
  // Update existing file - don't include parents in metadata for updates
@@ -103895,12 +105377,11 @@ ${imageData.originalPrompt}
103895
105377
  logToTerminal('log', '[Save Content] Successfully updated file');
103896
105378
  }
103897
105379
  else {
103898
- // Create new file - include parents for new files (in 'env' folder)
103899
- logToTerminal('log', '[Save Content] Creating new file in env folder');
105380
+ logToTerminal('log', '[Save Content] Creating new file in project folder root');
103900
105381
  const createMetadata = {
103901
105382
  name: filename,
103902
105383
  mimeType: 'application/json',
103903
- parents: [envFolderId]
105384
+ parents: [folderId]
103904
105385
  };
103905
105386
  const createForm = new FormData();
103906
105387
  createForm.append('metadata', new Blob([JSON.stringify(createMetadata)], { type: 'application/json' }));
@@ -103921,6 +105402,12 @@ ${imageData.originalPrompt}
103921
105402
  const result = await createResponse.json();
103922
105403
  logToTerminal('log', '[Save Content] Successfully created file, id:', result.id);
103923
105404
  }
105405
+ // После успешного сохранения в корень — убираем устаревшую папку env (и дубликаты, если были)
105406
+ const envIds = await findEnvFolderIds(folderId);
105407
+ for (const envId of envIds) {
105408
+ logToTerminal('log', '[Save Content] Removing legacy env folder:', envId);
105409
+ await trashDriveFile(envId);
105410
+ }
103924
105411
  };
103925
105412
  // Load generated content from Google Drive
103926
105413
  const loadGeneratedContentFromDrive = async (folderId) => {
@@ -103931,40 +105418,28 @@ ${imageData.originalPrompt}
103931
105418
  setDriveFilesFound(prev => ({ ...prev, content: false }));
103932
105419
  return { found: false };
103933
105420
  }
103934
- // Get 'env' folder
103935
- let envFolderId;
103936
- try {
103937
- envFolderId = await getOrCreateEnvFolder(folderId);
103938
- }
103939
- catch (err) {
103940
- logToTerminal('warn', '[Load Content] Failed to get env folder:', err.message || 'Unknown error');
103941
- return { found: false };
105421
+ // 1) Корень папки проекта; 2) иначе legacy: папка env (без создания env)
105422
+ let fileId = await findSettingsFileInFolder(folderId);
105423
+ if (fileId) {
105424
+ logToTerminal('log', '[Load Content] Found settings in project root');
103942
105425
  }
103943
- const filename = 'temp-generated-content.json';
103944
- const q = `'${envFolderId}' in parents and trashed = false and name = '${filename}'`;
103945
- const fields = 'files(id, name)';
103946
- const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
103947
- logToTerminal('log', '[Load Content] Searching for file:', filename);
103948
- const response = await fetch(url, {
103949
- headers: {
103950
- 'Authorization': `Bearer ${validToken}`
105426
+ else {
105427
+ const envIds = await findEnvFolderIds(folderId);
105428
+ for (const envFolderId of envIds) {
105429
+ const id = await findSettingsFileInFolder(envFolderId);
105430
+ if (id) {
105431
+ fileId = id;
105432
+ logToTerminal('log', '[Load Content] Found settings in legacy env folder:', envFolderId);
105433
+ break;
105434
+ }
103951
105435
  }
103952
- });
103953
- if (!response.ok) {
103954
- const errorText = await response.text();
103955
- logToTerminal('warn', '[Load Content] Search failed, status:', response.status, 'error:', errorText);
103956
- setDriveFilesFound(prev => ({ ...prev, content: false }));
103957
- return { found: false };
103958
105436
  }
103959
- const data = await response.json();
103960
- logToTerminal('log', '[Load Content] Search response:', JSON.stringify(data));
103961
- if (!data.files || data.files.length === 0) {
103962
- logToTerminal('log', '[Load Content] File not found - no temp-generated-content.json in folder');
105437
+ if (!fileId) {
105438
+ logToTerminal('log', `[Load Content] No settings file (${PROJECT_SETTINGS_FILENAME} or ${LEGACY_PROJECT_SETTINGS_FILENAME}) in root or env`);
103963
105439
  setDriveFilesFound(prev => ({ ...prev, content: false }));
103964
105440
  return { found: false };
103965
105441
  }
103966
105442
  setDriveFilesFound(prev => ({ ...prev, content: true }));
103967
- const fileId = data.files[0].id;
103968
105443
  logToTerminal('log', '[Load Content] File found, id:', fileId);
103969
105444
  // Download file content
103970
105445
  const downloadUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?alt=media`;
@@ -104011,6 +105486,10 @@ ${imageData.originalPrompt}
104011
105486
  setLink(loadedData.link || '');
104012
105487
  logToTerminal('log', '[Load Content] Loaded link:', loadedData.link || '(empty)');
104013
105488
  }
105489
+ const mergedApproaches = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.mergePromptApproachesFromDriveFile)(loadedData);
105490
+ if (mergedApproaches) {
105491
+ logToTerminal('log', '[Load Content] Applied text + image approach settings from Drive JSON');
105492
+ }
104014
105493
  logToTerminal('log', '[Load Content] Successfully loaded content');
104015
105494
  setDriveFilesFound(prev => ({ ...prev, content: false }));
104016
105495
  return { found: true };
@@ -104021,6 +105500,27 @@ ${imageData.originalPrompt}
104021
105500
  return { found: false };
104022
105501
  }
104023
105502
  };
105503
+ syncDriveAfterPromptSaveRef.current = () => {
105504
+ if (!driveFolderUrl || loadingContentFromDrive)
105505
+ return;
105506
+ const folderId = extractFolderId(driveFolderUrl);
105507
+ if (!folderId)
105508
+ return;
105509
+ logToTerminal('log', '[Drive Sync] Prompt overrides saved locally — updating JSON on Drive');
105510
+ void saveGeneratedContentToDrive(folderId, {
105511
+ generateProduct,
105512
+ generateGeo,
105513
+ generateAdditionalInfo,
105514
+ generatePriceWithCurrency
105515
+ }, brand, link).catch((err) => {
105516
+ logToTerminal('warn', '[Drive Sync] Failed to update Drive after prompt save:', err?.message || err);
105517
+ });
105518
+ };
105519
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
105520
+ const listener = () => syncDriveAfterPromptSaveRef.current();
105521
+ window.addEventListener(_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.PROMPT_OVERRIDES_SAVED_EVENT, listener);
105522
+ return () => window.removeEventListener(_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.PROMPT_OVERRIDES_SAVED_EVENT, listener);
105523
+ }, []);
104024
105524
  const handleGenerate = async () => {
104025
105525
  if (!driveFolderUrl || !brand || !link) {
104026
105526
  alert('Please fill all required fields');
@@ -104076,6 +105576,7 @@ ${imageData.originalPrompt}
104076
105576
  const text = textList[i];
104077
105577
  for (const image of images) {
104078
105578
  const id = `${brand}${idCounter++}`;
105579
+ const rowLink = appendCreativeIdToCatalogLink(link, id);
104079
105580
  rows.push([
104080
105581
  id,
104081
105582
  title,
@@ -104083,7 +105584,7 @@ ${imageData.originalPrompt}
104083
105584
  'in stock',
104084
105585
  'new',
104085
105586
  '10,00 USD',
104086
- link,
105587
+ rowLink,
104087
105588
  image,
104088
105589
  brand
104089
105590
  ]);
@@ -104091,8 +105592,8 @@ ${imageData.originalPrompt}
104091
105592
  }
104092
105593
  setGeneratedData(rows);
104093
105594
  // Create workbook
104094
- const wb = xlsx__WEBPACK_IMPORTED_MODULE_50__.utils.book_new();
104095
- const ws = xlsx__WEBPACK_IMPORTED_MODULE_50__.utils.aoa_to_sheet(rows);
105595
+ const wb = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_new();
105596
+ const ws = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.aoa_to_sheet(rows);
104096
105597
  // Set column widths (approximate pixel width / 7)
104097
105598
  ws['!cols'] = [
104098
105599
  { wch: 20 }, // id
@@ -104105,9 +105606,9 @@ ${imageData.originalPrompt}
104105
105606
  { wch: 40 }, // image_link
104106
105607
  { wch: 20 } // brand
104107
105608
  ];
104108
- xlsx__WEBPACK_IMPORTED_MODULE_50__.utils.book_append_sheet(wb, ws, "Products");
105609
+ xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_append_sheet(wb, ws, "Products");
104109
105610
  // Generate buffer
104110
- const wbout = xlsx__WEBPACK_IMPORTED_MODULE_50__.write(wb, { bookType: 'xlsx', type: 'array' });
105611
+ const wbout = xlsx__WEBPACK_IMPORTED_MODULE_53__.write(wb, { bookType: 'xlsx', type: 'array' });
104111
105612
  // Upload to Drive (имя файла по бренду)
104112
105613
  const dateStr = new Date().toISOString().split('T')[0];
104113
105614
  const fileName = `${brand}-${dateStr}.xlsx`;
@@ -104229,13 +105730,13 @@ ${imageData.originalPrompt}
104229
105730
  setTestLoading(true);
104230
105731
  try {
104231
105732
  // Create simple test workbook with structure
104232
- const wb = xlsx__WEBPACK_IMPORTED_MODULE_50__.utils.book_new();
105733
+ const wb = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_new();
104233
105734
  const rows = [
104234
105735
  INSTRUCTION_ROW,
104235
105736
  ['id', 'title', 'description', 'availability', 'condition', 'price', 'link', 'image_link', 'brand'],
104236
105737
  ['test1', 'Test Title', 'Test Description', 'in stock', 'new', '10.00 USD', 'http://test.com', 'http://test.com/img.jpg', 'TestBrand']
104237
105738
  ];
104238
- const ws = xlsx__WEBPACK_IMPORTED_MODULE_50__.utils.aoa_to_sheet(rows);
105739
+ const ws = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.aoa_to_sheet(rows);
104239
105740
  // Set column widths
104240
105741
  ws['!cols'] = [
104241
105742
  { wch: 20 }, // id
@@ -104248,8 +105749,8 @@ ${imageData.originalPrompt}
104248
105749
  { wch: 40 }, // image_link
104249
105750
  { wch: 20 } // brand
104250
105751
  ];
104251
- xlsx__WEBPACK_IMPORTED_MODULE_50__.utils.book_append_sheet(wb, ws, "Test");
104252
- const wbout = xlsx__WEBPACK_IMPORTED_MODULE_50__.write(wb, { bookType: 'xlsx', type: 'array' });
105752
+ xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_append_sheet(wb, ws, "Test");
105753
+ const wbout = xlsx__WEBPACK_IMPORTED_MODULE_53__.write(wb, { bookType: 'xlsx', type: 'array' });
104253
105754
  // Try to extract folder ID if available, otherwise upload to root
104254
105755
  const folderId = driveFolderUrl ? extractFolderId(driveFolderUrl) : undefined;
104255
105756
  const result = await uploadFileToDrive(wbout, 'test_table.xlsx', folderId || undefined);
@@ -104281,9 +105782,27 @@ ${imageData.originalPrompt}
104281
105782
  alert('Failed to copy link');
104282
105783
  }
104283
105784
  };
105785
+ const copyGeneratedPairsAsJson = async () => {
105786
+ const n = Math.max(generatedTitlesData.length, generatedTextsData.length);
105787
+ if (n === 0)
105788
+ return;
105789
+ const pairs = Array.from({ length: n }, (_, i) => ({
105790
+ title: generatedTitlesData[i]?.title ?? '',
105791
+ text: generatedTextsData[i]?.text ?? '',
105792
+ }));
105793
+ const json = JSON.stringify(pairs, null, 2);
105794
+ try {
105795
+ await navigator.clipboard.writeText(json);
105796
+ setPairsJsonCopied(true);
105797
+ setTimeout(() => setPairsJsonCopied(false), 2000);
105798
+ }
105799
+ catch {
105800
+ alert('Не удалось скопировать в буфер обмена');
105801
+ }
105802
+ };
104284
105803
  // Show lock screen if not unlocked
104285
105804
  if (!unlocked) {
104286
- return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { theme: theme },
105805
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], { theme: theme },
104287
105806
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
104288
105807
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { onClick: handleSecretClick, sx: {
104289
105808
  width: '100vw',
@@ -104323,24 +105842,24 @@ ${imageData.originalPrompt}
104323
105842
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null),
104324
105843
  "Please contact system administrator"))));
104325
105844
  }
104326
- return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { theme: theme },
105845
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], { theme: theme },
104327
105846
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
104328
105847
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { maxWidth: "lg", sx: { py: 4 } },
104329
105848
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 } },
104330
105849
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h4", component: "h1", sx: { fontWeight: 'bold', color: 'primary.main' } }, "Docs Combiner"),
104331
105850
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
104332
105851
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { onClick: () => setPromptManagerOpen(true), color: "inherit", "aria-label": "manage prompts", sx: { mr: 1 } },
104333
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], null)),
104334
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { onClick: toggleTheme, color: "inherit", "aria-label": "toggle theme" }, darkMode ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_36__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_35__["default"], null)))),
105852
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null)),
105853
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { onClick: toggleTheme, color: "inherit", "aria-label": "toggle theme" }, darkMode ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_37__["default"], null)))),
104335
105854
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { variant: "outlined", sx: { mb: 4 } },
104336
105855
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], null,
104337
105856
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 3 },
104338
105857
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
104339
105858
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Authentication"),
104340
105859
  accessToken ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], null,
104341
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null) },
105860
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null) },
104342
105861
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', color: 'success.main' } },
104343
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_37__["default"], { sx: { mr: 1 } }),
105862
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], { sx: { mr: 1 } }),
104344
105863
  " Logged In (Credentials Hidden)")),
104345
105864
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], null,
104346
105865
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
@@ -104351,7 +105870,7 @@ ${imageData.originalPrompt}
104351
105870
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Client ID", variant: "outlined", fullWidth: true, value: clientId, onChange: (e) => handleClientIdChange(e.target.value), helperText: "From Google Cloud Console (OAuth 2.0 Client ID)" }),
104352
105871
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }))),
104353
105872
  openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 2, mt: 2 } },
104354
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_33__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
105873
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
104355
105874
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: openRouterAccountBalance !== null ? 'text.primary' : 'text.secondary' },
104356
105875
  "\u0411\u0430\u043B\u0430\u043D\u0441: ",
104357
105876
  openRouterBalanceLoading ? 'Loading...' : (openRouterAccountBalance !== null ? `$${openRouterAccountBalance.toFixed(2)}` : 'N/A')),
@@ -104360,8 +105879,8 @@ ${imageData.originalPrompt}
104360
105879
  "\u041B\u0438\u043C\u0438\u0442 \u043A\u043B\u044E\u0447\u0430: ",
104361
105880
  openRouterBalanceLoading ? 'Loading...' : (openRouterBalance === -1 ? 'Без лимита' : (openRouterBalance !== null ? `${openRouterBalance.toFixed(4)}` : 'N/A'))))),
104362
105881
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mt: 2 } },
104363
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: accessToken ? "success" : "primary", onClick: handleLogin, disabled: authLoading || !clientId || !clientSecret, startIcon: authLoading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : (accessToken ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_37__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_42__["default"], null)), sx: { flexGrow: 1 } }, authLoading ? 'Logging in...' : (accessToken ? 'Logged In' : 'Login with Google')),
104364
- accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null) }, "Logout")))),
105882
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: accessToken ? "success" : "primary", onClick: handleLogin, disabled: authLoading || !clientId || !clientSecret, startIcon: authLoading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : (accessToken ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], null)), sx: { flexGrow: 1 } }, authLoading ? 'Logging in...' : (accessToken ? 'Logged In' : 'Login with Google')),
105883
+ accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], null) }, "Logout")))),
104365
105884
  !accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
104366
105885
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], null),
104367
105886
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
@@ -104377,7 +105896,7 @@ ${imageData.originalPrompt}
104377
105896
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 14 }),
104378
105897
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u043E\u0432...")))),
104379
105898
  !checkingFolderFiles && folderFilesInfo && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null,
104380
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'block' } }, folderFilesInfo.hasProduct ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "span", sx: { color: 'success.main' } }, "\u2713 product.png/jpg \u043D\u0430\u0439\u0434\u0435\u043D")) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "span", sx: { color: 'info.main' } }, "\u2139 product.png/jpg \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0447\u0435\u0440\u0435\u0437 \u043A\u043D\u043E\u043F\u043A\u0443 \u043D\u0438\u0436\u0435"))))),
105899
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'block' } }, folderFilesInfo.hasProduct ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "span", sx: { color: 'success.main' } }, "\u2713 product.png/jpg/webp \u043D\u0430\u0439\u0434\u0435\u043D")) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "span", sx: { color: 'info.main' } }, "\u2139 product.png/jpg/webp \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D \u2014 \u0437\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0447\u0435\u0440\u0435\u0437 \u043A\u043D\u043E\u043F\u043A\u0443 \u043D\u0438\u0436\u0435"))))),
104381
105900
  !checkingFolderFiles && !folderFilesInfo && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null, "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u0443\u044E \u0441\u0441\u044B\u043B\u043A\u0443 \u043D\u0430 \u043F\u0430\u043F\u043A\u0443 Google Drive"))))),
104382
105901
  !driveFolderUrl.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "info", sx: { mt: 2 } },
104383
105902
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { fontWeight: 'bold', mb: 1 } }, "\u0423\u043A\u0430\u0436\u0438\u0442\u0435 \u043F\u0430\u043F\u043A\u0443 Google Drive \u0434\u043B\u044F \u043F\u0440\u043E\u0434\u043E\u043B\u0436\u0435\u043D\u0438\u044F"),
@@ -104409,39 +105928,58 @@ ${imageData.originalPrompt}
104409
105928
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "\u0422\u043E\u0432\u0430\u0440", variant: "outlined", fullWidth: true, value: generateProduct, onChange: (e) => setGenerateProduct(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u043A\u0430\u043F\u043B\u0438 \u043E\u0442 \u043F\u0430\u0440\u0430\u0437\u0438\u0442\u043E\u0432 Detoxil Water", sx: { mb: 2 } })),
104410
105929
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
104411
105930
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "\u0413\u0435\u043E", variant: "outlined", fullWidth: true, value: generateGeo, onChange: (e) => setGenerateGeo(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: \u0420\u0443\u043C\u044B\u043D\u0438\u044F" }),
104412
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "\u0426\u0435\u043D\u0430 \u0438 \u0432\u0430\u043B\u044E\u0442\u0430", variant: "outlined", fullWidth: true, value: generatePriceWithCurrency, onChange: (e) => setGeneratePriceWithCurrency(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: 29 euro, 11400 HUF, 149 RON \u0438\u043B\u0438 \u043B\u044E\u0431\u043E\u0439 \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u0430\u0442", helperText: "\u041B\u044E\u0431\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u043C\u043F\u0442\u0435 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439" })),
105931
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "\u0426\u0435\u043D\u0430 \u0438 \u0432\u0430\u043B\u044E\u0442\u0430", variant: "outlined", fullWidth: true, value: generatePriceWithCurrency, onChange: (e) => setGeneratePriceWithCurrency(e.target.value), placeholder: "\u043D\u0430\u043F\u0440\u0438\u043C\u0435\u0440: 29 euro, 11400 HUF, 149 RON \u0438\u043B\u0438 \u043B\u044E\u0431\u043E\u0439 \u0434\u0440\u0443\u0433\u043E\u0439 \u0444\u043E\u0440\u043C\u0430\u0442", helperText: "\u041B\u044E\u0431\u043E\u0435 \u0437\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u0434\u043B\u044F \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u043D\u0438\u044F \u0432 \u043F\u0440\u043E\u043C\u043F\u0442\u0435 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439. \u041A\u043D\u043E\u043F\u043A\u0438 \u0441\u043F\u0440\u0430\u0432\u0430 \u043F\u043E\u0434\u0441\u0442\u0430\u0432\u043B\u044F\u044E\u0442 \u0441\u0438\u043C\u0432\u043E\u043B \u0432\u0430\u043B\u044E\u0442\u044B, \u0446\u0438\u0444\u0440\u0443 \u0431\u0435\u0440\u0443\u0442 \u0438\u0437 \u043F\u043E\u043B\u044F (\u0438\u043B\u0438 99).", InputProps: {
105932
+ endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { position: "end" },
105933
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 0.25, mr: -0.5 } },
105934
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C $ (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
105935
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0434\u043E\u043B\u043B\u0430\u0440", onClick: () => {
105936
+ const n = extractLeadingPriceNumber(generatePriceWithCurrency);
105937
+ setGeneratePriceWithCurrency(`$${n}`);
105938
+ }, edge: "end" },
105939
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_35__["default"], { sx: { fontSize: 20 } }))),
105940
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u20AC (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
105941
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0435\u0432\u0440\u043E", onClick: () => {
105942
+ const n = extractLeadingPriceNumber(generatePriceWithCurrency);
105943
+ setGeneratePriceWithCurrency(`€${n}`);
105944
+ }, edge: "end", sx: { minWidth: 34, fontSize: '1rem', fontWeight: 700 } }, "\u20AC")),
105945
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: "\u041F\u043E\u0434\u0441\u0442\u0430\u0432\u0438\u0442\u044C z\u0142 (\u0446\u0438\u0444\u0440\u0430 \u0438\u0437 \u043F\u043E\u043B\u044F \u0438\u043B\u0438 99)" },
105946
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0411\u044B\u0441\u0442\u0440\u043E \u0437\u043B\u043E\u0442\u044B\u0435", onClick: () => {
105947
+ const n = extractLeadingPriceNumber(generatePriceWithCurrency);
105948
+ setGeneratePriceWithCurrency(`${n} zł`);
105949
+ }, edge: "end", sx: { minWidth: 36, fontSize: '0.8rem', fontWeight: 700, letterSpacing: -0.3 } }, "z\u0142"))))),
105950
+ } })),
104413
105951
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
104414
105952
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "\u0414\u043E\u043F\u043E\u043B\u043D\u0438\u0442\u0435\u043B\u044C\u043D\u0430\u044F \u0438\u043D\u0444\u043E\u0440\u043C\u0430\u0446\u0438\u044F (\u043D\u0435 \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u044C\u043D\u043E)", variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: generateAdditionalInfo, onChange: (e) => setGenerateAdditionalInfo(e.target.value), placeholder: "\u0418\u043D\u0433\u0440\u0435\u0434\u0438\u0435\u043D\u0442\u044B, \u0443\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u044F \u043A \u043F\u0440\u043E\u043C\u043F\u0442\u0443 \u0438 \u0442.\u0434.", sx: { mb: 2 } })),
104415
105953
  openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
104416
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { fullWidth: true, variant: "outlined" },
104417
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439"),
104418
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { value: selectedImageModel, onChange: (e) => handleImageModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { disabled: true },
105954
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { fullWidth: true, variant: "outlined" },
105955
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439"),
105956
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { value: selectedImageModel, onChange: (e) => handleImageModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439", disabled: loadingImageModels || imageModels.length === 0 }, loadingImageModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { disabled: true },
104419
105957
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
104420
105958
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }),
104421
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { key: model.id, value: model.id }, model.name))))),
105959
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : imageModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (imageModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { key: model.id, value: model.id }, model.name))))),
104422
105960
  !loadingImageModels && imageModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null, selectedImageModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.imageGeneration
104423
105961
  ? 'Используется модель по умолчанию'
104424
105962
  : 'Выбрана модель: ' + (imageModels.find(m => m.id === selectedImageModel)?.name || selectedImageModel)))),
104425
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { fullWidth: true, variant: "outlined" },
104426
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
104427
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { value: selectedValidationModel, onChange: (e) => handleValidationModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432", disabled: loadingValidationModels || validationModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { disabled: true },
105963
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { fullWidth: true, variant: "outlined" },
105964
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], null, "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
105965
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { value: selectedValidationModel, onChange: (e) => handleValidationModelChange(e.target.value), label: "\u041C\u043E\u0434\u0435\u043B\u044C \u0434\u043B\u044F \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432", disabled: loadingValidationModels || validationModels.length === 0 }, loadingValidationModels ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { disabled: true },
104428
105966
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
104429
105967
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }),
104430
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : validationModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (validationModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { key: model.id, value: model.id }, model.name))))),
105968
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043C\u043E\u0434\u0435\u043B\u0435\u0439...")))) : validationModels.length === 0 ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { disabled: true }, "\u041D\u0435\u0442 \u0434\u043E\u0441\u0442\u0443\u043F\u043D\u044B\u0445 \u043C\u043E\u0434\u0435\u043B\u0435\u0439")) : (validationModels.map((model) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { key: model.id, value: model.id }, model.name))))),
104431
105969
  !loadingValidationModels && validationModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null, selectedValidationModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.creativeValidation
104432
105970
  ? 'Используется модель по умолчанию'
104433
105971
  : 'Выбрана модель: ' + (validationModels.find(m => m.id === selectedValidationModel)?.name || selectedValidationModel))),
104434
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["default"], { checked: validationDisabled, onChange: (e) => handleValidationDisabledChange(e.target.checked), color: "primary" }), label: "\u041E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443", sx: { mt: 1 } })))),
105972
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { checked: validationDisabled, onChange: (e) => handleValidationDisabledChange(e.target.checked), color: "primary" }), label: "\u041E\u0442\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443", sx: { mt: 1 } })))),
104435
105973
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
104436
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], null), onClick: handleGenerateContent, disabled: generating || loadingContentFromDrive || !openaiApiKey || !generateProduct.trim() || !generateGeo.trim(), sx: { flexGrow: 1 }, size: "large" }, generating ? 'Generating...' : 'Generate Titles & Descriptions'),
105974
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_36__["default"], null), onClick: handleGenerateContent, disabled: generating || loadingContentFromDrive || !openaiApiKey || !generateProduct.trim() || !generateGeo.trim(), sx: { flexGrow: 1 }, size: "large" }, generating ? 'Generating...' : 'Generate Titles & Descriptions'),
104437
105975
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { flexGrow: 1 } },
104438
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { title: imageAspectRatio === '1:1'
105976
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: imageAspectRatio === '1:1'
104439
105977
  ? '1:1 — квадрат (1024×1024 px)'
104440
105978
  : imageAspectRatio === '2:3'
104441
105979
  ? '2:3 — портрет (1024×1536 px)'
104442
105980
  : 'Оба — квадрат и портрет на каждый подход', placement: "top" },
104443
105981
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
104444
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_28__["default"], { value: imageAspectRatio, exclusive: true, onChange: (_e, val) => {
105982
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: imageAspectRatio, exclusive: true, onChange: (_e, val) => {
104445
105983
  if (val && val !== imageAspectRatio) {
104446
105984
  if (generatedImagesData.length > 0) {
104447
105985
  const label = val === 'both' ? 'оба (1:1 + 2:3)' : val;
@@ -104457,10 +105995,10 @@ ${imageData.originalPrompt}
104457
105995
  }
104458
105996
  }
104459
105997
  }, size: "small", disabled: generatingImages, sx: { height: 42 } },
104460
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "1:1", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "1:1"),
104461
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "2:3", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "2:3"),
104462
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_29__["default"], { value: "both", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "\u041E\u0431\u0430")))),
104463
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], null), onClick: handleGenerateImages, disabled: generatingImages ||
105998
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { value: "1:1", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "1:1"),
105999
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { value: "2:3", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "2:3"),
106000
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { value: "both", sx: { px: 1.5, fontWeight: 600, fontSize: '0.8rem' } }, "\u041E\u0431\u0430")))),
106001
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_36__["default"], null), onClick: handleGenerateImages, disabled: generatingImages ||
104464
106002
  !openaiApiKey ||
104465
106003
  (!accessToken && !refreshToken) ||
104466
106004
  !generateProduct.trim() ||
@@ -104478,9 +106016,9 @@ ${imageData.originalPrompt}
104478
106016
  : !driveFolderUrl.trim()
104479
106017
  ? 'Заполните URL папки Google Drive'
104480
106018
  : undefined }, generatingImages ? 'Generating Images...' : 'Generate Images')),
104481
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "success", size: "large", onClick: handleGenerate, disabled: loading, startIcon: loading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], null), sx: { py: 1.5, fontSize: '1.1rem', flexGrow: 1 } }, loading ? 'Generating...' : 'Generate Catalog'),
106019
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "success", size: "large", onClick: handleGenerate, disabled: loading, startIcon: loading ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), sx: { py: 1.5, fontSize: '1.1rem', flexGrow: 1 } }, loading ? 'Generating...' : 'Generate Catalog'),
104482
106020
  uploadedLink && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "success", sx: { flexGrow: 1, minWidth: 0 }, action: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { "aria-label": "copy link", color: "inherit", size: "small", onClick: handleCopyLink, sx: { ml: 1 } },
104483
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], { fontSize: "small" })) },
106021
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], { fontSize: "small" })) },
104484
106022
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' } },
104485
106023
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
104486
106024
  "\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D!",
@@ -104490,22 +106028,22 @@ ${imageData.originalPrompt}
104490
106028
  getElectronAPI().openExternal(uploadedLink);
104491
106029
  }, style: { cursor: 'pointer', textDecoration: 'underline', color: 'inherit' } }, "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 Google Drive")),
104492
106030
  linkCopied && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'success.dark', fontWeight: 'bold' } }, "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u043D\u043E!"))))),
104493
- folderFilesInfo !== null && !folderFilesInfo.hasProduct && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "warning", sx: { mt: 1 } }, "\u0414\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F product.png/jpg. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043E \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043A\u043D\u043E\u043F\u043A\u0438 \"Generate Product from Banka\".")),
106031
+ folderFilesInfo !== null && !folderFilesInfo.hasProduct && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "warning", sx: { mt: 1 } }, "\u0414\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u0442\u0440\u0435\u0431\u0443\u0435\u0442\u0441\u044F product.png/jpg/webp. \u0421\u043D\u0430\u0447\u0430\u043B\u0430 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u0443\u0439\u0442\u0435 \u0435\u0433\u043E \u0441 \u043F\u043E\u043C\u043E\u0449\u044C\u044E \u043A\u043D\u043E\u043F\u043A\u0438 \"Generate Product from Banka\".")),
104494
106032
  !generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
104495
106033
  !openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 OpenRouter API Key")),
104496
106034
  openaiApiKey && (!accessToken && !refreshToken) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0412\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 Google Drive")),
104497
106035
  openaiApiKey && (accessToken || refreshToken) && !generateProduct.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0422\u043E\u0432\u0430\u0440")),
104498
106036
  openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && !generateGeo.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0413\u0435\u043E")),
104499
106037
  openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && generateGeo.trim() && !driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 URL \u043F\u0430\u043F\u043A\u0438 Google Drive"))))),
104500
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: productFileInputRef, accept: "image/png,image/jpeg,image/jpg", style: { display: 'none' }, onChange: handleProductFileSelected }),
106038
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { type: "file", ref: productFileInputRef, accept: "image/png,image/jpeg,image/jpg,image/webp", style: { display: 'none' }, onChange: handleProductFileSelected }),
104501
106039
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
104502
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "success", startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], null), onClick: handleUploadProductFile, disabled: uploadingProduct || !accessToken || !driveFolderUrl.trim(), sx: { flexGrow: 1 }, size: "large" }, uploadingProduct ? 'Загрузка...' : 'Загрузить product.png/jpg'),
104503
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), onClick: handleCreateLanding, disabled: generatingLanding ||
106040
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "success", startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: handleUploadProductFile, disabled: uploadingProduct || !accessToken || !driveFolderUrl.trim(), sx: { flexGrow: 1 }, size: "large" }, uploadingProduct ? 'Загрузка...' : 'Загрузить product.png/jpg/webp'),
106041
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null), onClick: handleCreateLanding, disabled: generatingLanding ||
104504
106042
  !openaiApiKey ||
104505
106043
  !accessToken ||
104506
106044
  !driveFolderUrl.trim() ||
104507
106045
  (folderFilesInfo !== null && !folderFilesInfo.hasProduct), sx: { flexGrow: 1 }, size: "large", title: folderFilesInfo !== null && !folderFilesInfo.hasProduct
104508
- ? 'product.png/jpg не найден в папке. Загрузите его с помощью кнопки «Загрузить product.png/jpg»'
106046
+ ? 'product.png/jpg/webp не найден в папке. Загрузите его с помощью кнопки «Загрузить product»'
104509
106047
  : undefined }, generatingLanding ? 'Creating Landing...' : 'Создать лендинг')),
104510
106048
  generatedImagesData.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2, mt: 3 } },
104511
106049
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true, sx: { fontWeight: 'bold' } },
@@ -104517,6 +106055,8 @@ ${imageData.originalPrompt}
104517
106055
  checkingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
104518
106056
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }),
104519
106057
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary' } }, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043A\u0430\u0447\u0435\u0441\u0442\u0432\u0430..."))),
106058
+ generatedImagesData.length > 0 && generatedImagesData.some(img => !img.uploaded && img.imageUrl) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
106059
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", onClick: handleUploadAllImages, disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))),
104520
106060
  generatedImagesData.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
104521
106061
  display: 'grid',
104522
106062
  gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' },
@@ -104526,6 +106066,34 @@ ${imageData.originalPrompt}
104526
106066
  const imgRatio = imageData.aspectRatio ?? (imageAspectRatio === 'both' ? '1:1' : imageAspectRatio);
104527
106067
  const aspectRatioCss = imgRatio === '2:3' ? '2 / 3' : '1 / 1';
104528
106068
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { key: imageData.index, sx: { position: 'relative' } },
106069
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043A\u0440\u0435\u0430\u0442\u0438\u0432" },
106070
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
106071
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043A\u0440\u0435\u0430\u0442\u0438\u0432", sx: {
106072
+ position: 'absolute',
106073
+ top: 6,
106074
+ right: 6,
106075
+ zIndex: 3,
106076
+ bgcolor: 'rgba(32, 32, 32, 0.92)',
106077
+ color: '#fff',
106078
+ border: '2px solid rgba(255, 255, 255, 0.95)',
106079
+ boxShadow: '0 2px 12px rgba(0, 0, 0, 0.45)',
106080
+ width: 36,
106081
+ height: 36,
106082
+ '&:hover': {
106083
+ bgcolor: 'error.main',
106084
+ borderColor: 'rgba(255, 255, 255, 1)',
106085
+ color: '#fff',
106086
+ },
106087
+ '&.Mui-disabled': {
106088
+ bgcolor: 'rgba(32, 32, 32, 0.45)',
106089
+ borderColor: 'rgba(255, 255, 255, 0.4)',
106090
+ color: 'rgba(255, 255, 255, 0.5)',
106091
+ },
106092
+ }, onClick: () => handleDeleteGeneratedImage(imageData.index), disabled: generatingImages ||
106093
+ imageData.generating ||
106094
+ !!imageData.regenerating ||
106095
+ !!imageData.uploading },
106096
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_42__["default"], { fontSize: "small" })))),
104529
106097
  imageData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
104530
106098
  width: '100%',
104531
106099
  aspectRatio: aspectRatioCss,
@@ -104546,7 +106114,24 @@ ${imageData.originalPrompt}
104546
106114
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach),
104547
106115
  generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } },
104548
106116
  "\u23F1\uFE0F \u041F\u0440\u043E\u0448\u043B\u043E: ",
104549
- formatElapsedTime(elapsedTime.images))))) : imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
106117
+ formatElapsedTime(elapsedTime.images))))) : imageData.regenerating && !imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
106118
+ width: '100%',
106119
+ aspectRatio: aspectRatioCss,
106120
+ border: (theme) => `2px dashed ${theme.palette.primary.main}`,
106121
+ borderRadius: 1,
106122
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106123
+ ? 'rgba(25, 118, 210, 0.1)'
106124
+ : 'rgba(25, 118, 210, 0.05)',
106125
+ display: 'flex',
106126
+ flexDirection: 'column',
106127
+ alignItems: 'center',
106128
+ justifyContent: 'center',
106129
+ gap: 2,
106130
+ p: 3
106131
+ } },
106132
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
106133
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary', textAlign: 'center', fontWeight: 'bold' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0430..."),
106134
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach))) : imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
104550
106135
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "img", src: imageData.imageUrl, alt: `Generated Image ${imageData.index}`, sx: {
104551
106136
  width: '100%',
104552
106137
  height: 'auto',
@@ -104641,7 +106226,7 @@ ${imageData.originalPrompt}
104641
106226
  "+",
104642
106227
  imageData.checkErrors.length - 2,
104643
106228
  " \u0435\u0449\u0451")))),
104644
- imageData.checkFailed && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", color: "warning", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], null), onClick: () => handleRetryCheck(imageData), disabled: imageData.checking, sx: { mt: 0.5, fontSize: '0.7rem', py: 0.25, px: 1 } }, "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443")))),
106229
+ imageData.checkFailed && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", color: "warning", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null), onClick: () => handleRetryCheck(imageData), disabled: imageData.checking, sx: { mt: 0.5, fontSize: '0.7rem', py: 0.25, px: 1 } }, "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443")))),
104645
106230
  imageData.checkStatus === 'checking' && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'warning.main', display: 'block' } }, "\uD83D\uDD0D \u041F\u0440\u043E\u0432\u0435\u0440\u044F\u0435\u0442\u0441\u044F...")),
104646
106231
  imageData.checkStatus === 'pending' && !imageData.failed && !imageData.generating && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', display: 'block' } }, "\u23F3 \u041E\u0436\u0438\u0434\u0430\u0435\u0442 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0438")),
104647
106232
  imageData.failed && !imageData.generating && !imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'error.main', display: 'block', fontWeight: 'bold' } }, "\u274C \u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u043D\u0435 \u0443\u0434\u0430\u043B\u0430\u0441\u044C")),
@@ -104664,7 +106249,7 @@ ${imageData.originalPrompt}
104664
106249
  : 'transparent'
104665
106250
  }
104666
106251
  } }),
104667
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "contained", color: imageData.failed ? 'error' : imageData.checkStatus === 'needs_rebuild' ? 'warning' : 'primary', startIcon: imageData.regenerating ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], null), onClick: () => handleRegenerateImage(imageData), disabled: imageData.regenerating ||
106252
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "contained", color: imageData.failed ? 'error' : imageData.checkStatus === 'needs_rebuild' ? 'warning' : 'primary', startIcon: imageData.regenerating ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_36__["default"], null), onClick: () => handleRegenerateImage(imageData), disabled: imageData.regenerating ||
104668
106253
  imageData.uploading ||
104669
106254
  imageData.checkStatus === 'checking' ||
104670
106255
  !imageData.originalPrompt ||
@@ -104674,12 +106259,12 @@ ${imageData.originalPrompt}
104674
106259
  : ((generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating)
104675
106260
  ? 'В очереди'
104676
106261
  : (!imageData.imageUrl ? 'Сгенерировать' : 'Переделать'))),
104677
- imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], null), onClick: () => handleRegenerateImageFresh(imageData), disabled: imageData.regenerating ||
106262
+ imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null), onClick: () => handleRegenerateImageFresh(imageData), disabled: imageData.regenerating ||
104678
106263
  imageData.uploading ||
104679
106264
  imageData.checkStatus === 'checking' ||
104680
106265
  !imageData.originalPrompt ||
104681
106266
  !imageData.productImageUrl, fullWidth: true }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u043D\u043E\u0432\u043E")),
104682
- !imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], null), onClick: () => {
106267
+ !imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: () => {
104683
106268
  const folderId = extractFolderId(driveFolderUrl);
104684
106269
  if (folderId) {
104685
106270
  handleUploadImage(imageData, folderId);
@@ -104687,15 +106272,24 @@ ${imageData.originalPrompt}
104687
106272
  }, disabled: imageData.uploading || imageData.regenerating || !driveFolderUrl.trim(), fullWidth: true }, imageData.uploading ? 'Загрузка...' : 'Загрузить'))))));
104688
106273
  }))),
104689
106274
  generatedImagesData.length > 0 && generatedImagesData.some(img => !img.uploaded && img.imageUrl) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mt: 2 } },
104690
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", onClick: handleUploadAllImages, disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))))),
106275
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "contained", color: "primary", onClick: handleUploadAllImages, disabled: uploadingImages || generatingImages || !driveFolderUrl.trim(), startIcon: uploadingImages ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))))),
104691
106276
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
104692
106277
  (generatedTitlesData.length > 0 || generatedTextsData.length > 0 || loadingContentFromDrive) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
104693
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true, sx: { fontWeight: 'bold' } },
104694
- "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u043F\u0430\u0440\u044B (",
104695
- Math.min(generatedTitlesData.filter(t => t.title).length, generatedTextsData.filter(t => t.text).length),
104696
- "/",
104697
- Math.max(generatedTitlesData.length, generatedTextsData.length),
104698
- ")"),
106278
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 1, mb: 1 } },
106279
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", sx: { fontWeight: 'bold' }, component: "div" },
106280
+ "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D\u043D\u044B\u0435 \u043F\u0430\u0440\u044B (",
106281
+ Math.min(generatedTitlesData.filter(t => t.title).length, generatedTextsData.filter(t => t.text).length),
106282
+ "/",
106283
+ Math.max(generatedTitlesData.length, generatedTextsData.length),
106284
+ ")"),
106285
+ (generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: pairsJsonCopied ? 'Скопировано' : 'Скопировать все пары как JSON-массив' },
106286
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", "aria-label": "\u0421\u043A\u043E\u043F\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0430\u0440\u044B \u043A\u0430\u043A JSON", onClick: () => void copyGeneratedPairsAsJson(), disabled: generating, sx: {
106287
+ opacity: 0.28,
106288
+ p: 0.35,
106289
+ color: 'text.secondary',
106290
+ '&:hover': { opacity: 0.75, color: 'text.primary' },
106291
+ } },
106292
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], { sx: { fontSize: 16 } }))))),
104699
106293
  loadingContentFromDrive && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
104700
106294
  display: 'flex',
104701
106295
  flexDirection: 'column',
@@ -104722,7 +106316,7 @@ ${imageData.originalPrompt}
104722
106316
  const pairLabel = pairApproach ? pairApproach.name : `пара ${i + 1}`;
104723
106317
  const pairGenerating = (titleData?.generating || textData?.generating);
104724
106318
  const pairFailed = (!pairGenerating && titleData?.failed && textData?.failed);
104725
- return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { key: i, variant: "outlined", sx: {
106319
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { key: i, variant: "outlined", sx: {
104726
106320
  p: 2,
104727
106321
  borderColor: pairFailed
104728
106322
  ? 'error.main'
@@ -104734,7 +106328,7 @@ ${imageData.originalPrompt}
104734
106328
  ? (theme.palette.mode === 'dark' ? 'rgba(25,118,210,0.05)' : 'rgba(25,118,210,0.02)')
104735
106329
  : 'transparent',
104736
106330
  } },
104737
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { mb: 1.5 } },
106331
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { mb: 1.5, flexWrap: 'wrap' } },
104738
106332
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: {
104739
106333
  fontWeight: 700,
104740
106334
  px: 1,
@@ -104750,7 +106344,12 @@ ${imageData.originalPrompt}
104750
106344
  "\u041F\u0430\u0440\u0430 ",
104751
106345
  i + 1),
104752
106346
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, pairLabel),
104753
- translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 13, sx: { color: 'text.disabled', ml: 0.5 } })) : pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["default"], { title: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
106347
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flexGrow: 1, minWidth: 8 } }),
106348
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0430\u0440\u0443" },
106349
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
106350
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", color: "error", "aria-label": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0430\u0440\u0443", onClick: () => handleDeleteGeneratedPair(i), disabled: pairGenerating || generating },
106351
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_42__["default"], { fontSize: "small" })))),
106352
+ translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 13, sx: { color: 'text.disabled', ml: 0.5 } })) : pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
104754
106353
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { fontWeight: 700, display: 'block', mb: 0.5 } }, "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A:"),
104755
106354
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { display: 'block', mb: 1 } }, pairTranslations[i].titleRu),
104756
106355
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { fontWeight: 700, display: 'block', mb: 0.5 } }, "\u0422\u0435\u043A\u0441\u0442:"),
@@ -104758,13 +106357,26 @@ ${imageData.originalPrompt}
104758
106357
  tooltip: { sx: { maxWidth: 360, fontSize: 12, lineHeight: 1.6, p: '10px 14px' } },
104759
106358
  } },
104760
106359
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { size: "small", sx: { p: 0.25, color: 'text.disabled', '&:hover': { color: 'primary.main' } } },
104761
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], { sx: { fontSize: 14 } })))) : null),
106360
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], { sx: { fontSize: 14 } })))) : null),
104762
106361
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 1.5 },
104763
106362
  titleData && (titleData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
104764
106363
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16, sx: { color: 'primary.main' } }),
104765
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary" }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430\u2026"))) : titleData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'error.main' } },
104766
- "\u274C \u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u043D\u0435 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D",
104767
- titleData.errorMessage ? `: ${titleData.errorMessage}` : '')) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: `Заголовок ${i + 1}`, variant: "outlined", fullWidth: true, size: "small", value: titleData.title, onChange: (e) => {
106364
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary" }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430\u2026"))) : titleData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: `Заголовок ${i + 1}`, variant: "outlined", fullWidth: true, size: "small", value: titleData.title, placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A \u0432\u0440\u0443\u0447\u043D\u0443\u044E", helperText: titleData.errorMessage ? `Не сгенерирован: ${titleData.errorMessage}` : 'Можно ввести или исправить заголовок вручную', error: !!titleData.errorMessage, onChange: (e) => {
106365
+ const newValue = e.target.value;
106366
+ setGeneratedTitlesData(prev => {
106367
+ const updated = prev.map(t => t.index === titleData.index
106368
+ ? { ...t, title: newValue, failed: false, errorMessage: undefined }
106369
+ : t);
106370
+ setTitles(updated.map(t => t.title).filter(Boolean).join('\n'));
106371
+ return updated;
106372
+ });
106373
+ }, sx: {
106374
+ '& .MuiInputBase-root': {
106375
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106376
+ ? 'rgba(244,67,54,0.08)'
106377
+ : 'rgba(244,67,54,0.04)'
106378
+ }
106379
+ } })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: `Заголовок ${i + 1}`, variant: "outlined", fullWidth: true, size: "small", value: titleData.title, onChange: (e) => {
104768
106380
  const newValue = e.target.value;
104769
106381
  setGeneratedTitlesData(prev => {
104770
106382
  const updated = prev.map(t => t.index === titleData.index ? { ...t, title: newValue } : t);
@@ -104780,9 +106392,22 @@ ${imageData.originalPrompt}
104780
106392
  } }))),
104781
106393
  textData && (textData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
104782
106394
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16, sx: { color: 'primary.main' } }),
104783
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary" }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0442\u0435\u043A\u0441\u0442\u0430\u2026"))) : textData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'error.main' } },
104784
- "\u274C \u0422\u0435\u043A\u0441\u0442 \u043D\u0435 \u0441\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u043D",
104785
- textData.errorMessage ? `: ${textData.errorMessage}` : '')) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: `Текст ${i + 1}`, variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: textData.text, onChange: (e) => {
106395
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary" }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0442\u0435\u043A\u0441\u0442\u0430\u2026"))) : textData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: `Текст ${i + 1}`, variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: textData.text, placeholder: "\u0412\u0432\u0435\u0434\u0438\u0442\u0435 \u0442\u0435\u043A\u0441\u0442 \u043E\u0431\u044A\u044F\u0432\u043B\u0435\u043D\u0438\u044F \u0432\u0440\u0443\u0447\u043D\u0443\u044E", helperText: textData.errorMessage ? `Не сгенерирован: ${textData.errorMessage}` : 'Можно ввести или исправить текст вручную', error: !!textData.errorMessage, onChange: (e) => {
106396
+ const newValue = e.target.value;
106397
+ setGeneratedTextsData(prev => {
106398
+ const updated = prev.map(t => t.index === textData.index
106399
+ ? { ...t, text: newValue, failed: false, errorMessage: undefined }
106400
+ : t);
106401
+ setTexts(updated.map(t => t.text));
106402
+ return updated;
106403
+ });
106404
+ }, sx: {
106405
+ '& .MuiInputBase-root': {
106406
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106407
+ ? 'rgba(244,67,54,0.08)'
106408
+ : 'rgba(244,67,54,0.04)'
106409
+ }
106410
+ } })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: `Текст ${i + 1}`, variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: textData.text, onChange: (e) => {
104786
106411
  const newValue = e.target.value;
104787
106412
  setGeneratedTextsData(prev => {
104788
106413
  const updated = prev.map(t => t.index === textData.index ? { ...t, text: newValue } : t);
@@ -104799,7 +106424,7 @@ ${imageData.originalPrompt}
104799
106424
  }))))),
104800
106425
  (landingGenerationLogs.length > 0 || generatingLanding) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
104801
106426
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true, sx: { fontWeight: 'bold' } }, "\u041F\u0440\u043E\u0446\u0435\u0441\u0441 \u0441\u043E\u0437\u0434\u0430\u043D\u0438\u044F \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"),
104802
- landingGenerationLogs.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_30__["default"], { sx: {
106427
+ landingGenerationLogs.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { sx: {
104803
106428
  p: 2,
104804
106429
  backgroundColor: (theme) => theme.palette.mode === 'dark'
104805
106430
  ? 'rgba(25, 118, 210, 0.1)'
@@ -104825,8 +106450,8 @@ ${imageData.originalPrompt}
104825
106450
  generatingLanding && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
104826
106451
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }),
104827
106452
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary' } }, formatElapsedTime(elapsedTime.landing)))),
104828
- !generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null), fullWidth: true }, "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"))))))))),
104829
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_PromptManagerDialog__WEBPACK_IMPORTED_MODULE_48__["default"], { open: promptManagerOpen, onClose: () => setPromptManagerOpen(false) }))));
106453
+ !generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_50__["default"], null), fullWidth: true }, "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"))))))))),
106454
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_PromptManagerDialog__WEBPACK_IMPORTED_MODULE_51__["default"], { open: promptManagerOpen, onClose: () => setPromptManagerOpen(false) }))));
104830
106455
  }
104831
106456
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);
104832
106457
 
@@ -104847,8 +106472,8 @@ __webpack_require__.r(__webpack_exports__);
104847
106472
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "./node_modules/react/index.js");
104848
106473
  /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
104849
106474
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Box/Box.js");
104850
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Paper/Paper.js");
104851
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Typography/Typography.js");
106475
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Typography/Typography.js");
106476
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Paper/Paper.js");
104852
106477
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/IconButton/IconButton.js");
104853
106478
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/TextField/TextField.js");
104854
106479
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Stack/Stack.js");
@@ -104863,25 +106488,27 @@ __webpack_require__.r(__webpack_exports__);
104863
106488
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogContent/DialogContent.js");
104864
106489
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tabs/Tabs.js");
104865
106490
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tab/Tab.js");
104866
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
104867
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Accordion/Accordion.js");
104868
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionSummary/AccordionSummary.js");
104869
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionDetails/AccordionDetails.js");
104870
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogActions/DialogActions.js");
104871
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Cancel.js");
104872
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Close.js");
104873
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CompareArrows.js");
104874
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Edit.js");
104875
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
104876
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/KeyboardArrowDown.js");
104877
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/KeyboardArrowUp.js");
104878
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/RestartAlt.js");
104879
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Save.js");
104880
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Search.js");
104881
- /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
104882
- /* harmony import */ var _prompts__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! ./prompts */ "./src/prompts.ts");
104883
- /* harmony import */ var _landingPrompts__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! ./landingPrompts */ "./src/landingPrompts.ts");
104884
- /* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
106491
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tooltip/Tooltip.js");
106492
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
106493
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Accordion/Accordion.js");
106494
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionSummary/AccordionSummary.js");
106495
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionDetails/AccordionDetails.js");
106496
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogActions/DialogActions.js");
106497
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Snackbar/Snackbar.js");
106498
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Cancel.js");
106499
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Close.js");
106500
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CompareArrows.js");
106501
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Edit.js");
106502
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
106503
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/KeyboardArrowDown.js");
106504
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_31__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/KeyboardArrowUp.js");
106505
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/RestartAlt.js");
106506
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Save.js");
106507
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Search.js");
106508
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
106509
+ /* harmony import */ var _prompts__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! ./prompts */ "./src/prompts.ts");
106510
+ /* harmony import */ var _landingPrompts__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! ./landingPrompts */ "./src/landingPrompts.ts");
106511
+ /* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
104885
106512
 
104886
106513
 
104887
106514
 
@@ -104892,6 +106519,36 @@ function TabPanel(props) {
104892
106519
  const { children, value, index, ...other } = props;
104893
106520
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("div", { role: "tabpanel", hidden: value !== index, id: `prompt-tabpanel-${index}`, "aria-labelledby": `prompt-tab-${index}`, ...other }, value === index && react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { p: 3 } }, children)));
104894
106521
  }
106522
+ /** Подсказка для кнопки типа товара: списки подходов для текстов и картинок (номера как в таблицах). */
106523
+ function productTypePresetTooltip(label) {
106524
+ const textNums = _promptOverrides__WEBPACK_IMPORTED_MODULE_38__.PRODUCT_TYPE_TEXT_PAIR_PRESETS[label];
106525
+ if (!textNums)
106526
+ return label;
106527
+ const sortedText = [...textNums].sort((a, b) => a - b);
106528
+ const imgPreset = _promptOverrides__WEBPACK_IMPORTED_MODULE_38__.PRODUCT_TYPE_IMAGE_PRESETS[label];
106529
+ const sortedImg = imgPreset ? [...imgPreset].sort((a, b) => a - b) : null;
106530
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { py: 0.25, maxWidth: 380, color: 'common.white', fontSize: '0.75rem' } },
106531
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", component: "div", sx: { fontWeight: 700, mb: 0.75, display: 'block', color: 'inherit' } },
106532
+ "\u0422\u0435\u043A\u0441\u0442\u044B \u2014 ",
106533
+ sortedText.length,
106534
+ " \u043F\u0430\u0440:"),
106535
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { component: "ul", sx: { m: 0, pl: 2.25, mb: 1.25, listStyleType: 'disc', color: 'inherit' } }, sortedText.map((n) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { key: `t-${n}`, variant: "caption", component: "li", sx: { display: 'list-item', lineHeight: 1.5, mb: 0.25, color: 'inherit' } },
106536
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("strong", null,
106537
+ n,
106538
+ "."),
106539
+ " ",
106540
+ _prompts__WEBPACK_IMPORTED_MODULE_36__.PAIR_APPROACH_POOL[n - 1]?.name ?? '—')))),
106541
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", component: "div", sx: { fontWeight: 700, mb: 0.75, display: 'block', color: 'inherit' } },
106542
+ "\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F",
106543
+ sortedImg ? ` — ${sortedImg.length} подходов` : '',
106544
+ ":"),
106545
+ sortedImg ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { component: "ul", sx: { m: 0, pl: 2.25, listStyleType: 'disc', color: 'inherit' } }, sortedImg.map((n) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { key: `i-${n}`, variant: "caption", component: "li", sx: { display: 'list-item', lineHeight: 1.5, mb: 0.25, color: 'inherit' } },
106546
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("strong", null,
106547
+ n,
106548
+ "."),
106549
+ " ",
106550
+ _prompts__WEBPACK_IMPORTED_MODULE_36__.CREO_APPROACHES[n - 1]?.name ?? '—'))))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", sx: { display: 'block', lineHeight: 1.5, opacity: 0.85, color: 'inherit' } }, "\u0412\u0441\u0435 10 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432 \u043F\u043E 1 \u043A\u0440\u0435\u043E (\u043D\u0435\u0442 \u043E\u0442\u0434\u0435\u043B\u044C\u043D\u043E\u0433\u043E \u043F\u0440\u0435\u0441\u0435\u0442\u0430)"))));
106551
+ }
104895
106552
  function SearchableTextField({ value, onChange, disabled, rows = 15, placeholder, helperText, fullWidth = true, multiline = true }) {
104896
106553
  const [searchOpen, setSearchOpen] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
104897
106554
  const [searchQuery, setSearchQuery] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
@@ -104961,7 +106618,7 @@ function SearchableTextField({ value, onChange, disabled, rows = 15, placeholder
104961
106618
  }
104962
106619
  };
104963
106620
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { position: 'relative' } },
104964
- searchOpen && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { elevation: 3, sx: {
106621
+ searchOpen && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { elevation: 3, sx: {
104965
106622
  position: 'absolute',
104966
106623
  top: 4,
104967
106624
  right: 4,
@@ -104975,7 +106632,7 @@ function SearchableTextField({ value, onChange, disabled, rows = 15, placeholder
104975
106632
  border: '1px solid',
104976
106633
  borderColor: 'divider',
104977
106634
  } },
104978
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_32__["default"], { sx: { fontSize: 18, color: 'text.secondary' } }),
106635
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], { sx: { fontSize: 18, color: 'text.secondary' } }),
104979
106636
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { ref: searchInputRef, value: searchQuery, onChange: (e) => { setSearchQuery(e.target.value); setCurrentMatch(0); }, onKeyDown: handleKeyDown, placeholder: "\u041F\u043E\u0438\u0441\u043A...", style: {
104980
106637
  border: 'none',
104981
106638
  outline: 'none',
@@ -104986,13 +106643,13 @@ function SearchableTextField({ value, onChange, disabled, rows = 15, placeholder
104986
106643
  color: 'inherit',
104987
106644
  fontFamily: 'inherit',
104988
106645
  }, autoFocus: true }),
104989
- searchQuery && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "caption", sx: { color: 'text.secondary', whiteSpace: 'nowrap', minWidth: 50, textAlign: 'center' } }, matches.length > 0 ? `${currentMatch + 1} / ${matches.length}` : 'нет')),
106646
+ searchQuery && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", sx: { color: 'text.secondary', whiteSpace: 'nowrap', minWidth: 50, textAlign: 'center' } }, matches.length > 0 ? `${currentMatch + 1} / ${matches.length}` : 'нет')),
104990
106647
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => navigateToMatch(currentMatch - 1), disabled: matches.length === 0, sx: { p: 0.3 } },
104991
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_29__["default"], { sx: { fontSize: 18 } })),
106648
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_31__["default"], { sx: { fontSize: 18 } })),
104992
106649
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => navigateToMatch(currentMatch + 1), disabled: matches.length === 0, sx: { p: 0.3 } },
104993
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_28__["default"], { sx: { fontSize: 18 } })),
106650
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_30__["default"], { sx: { fontSize: 18 } })),
104994
106651
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => { setSearchOpen(false); setSearchQuery(''); }, sx: { p: 0.3 } },
104995
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_24__["default"], { sx: { fontSize: 18 } })))),
106652
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_26__["default"], { sx: { fontSize: 18 } })))),
104996
106653
  !searchOpen && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => { setSearchOpen(true); setTimeout(() => searchInputRef.current?.focus(), 50); }, sx: {
104997
106654
  position: 'absolute',
104998
106655
  top: 8,
@@ -105003,7 +106660,7 @@ function SearchableTextField({ value, onChange, disabled, rows = 15, placeholder
105003
106660
  bgcolor: 'background.paper',
105004
106661
  boxShadow: 1,
105005
106662
  } },
105006
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_32__["default"], { sx: { fontSize: 16 } }))),
106663
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], { sx: { fontSize: 16 } }))),
105007
106664
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { inputRef: textareaRef, fullWidth: fullWidth, multiline: multiline, rows: rows, value: value, onChange: onChange, disabled: disabled, placeholder: placeholder, helperText: helperText, onKeyDown: handleTextareaKeyDown, sx: {
105008
106665
  '& .MuiInputBase-input': {
105009
106666
  fontFamily: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace',
@@ -105151,7 +106808,7 @@ function DiffViewer({ oldText, newText }) {
105151
106808
  }
105152
106809
  };
105153
106810
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { position: 'relative' } },
105154
- searchOpen && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { elevation: 3, sx: {
106811
+ searchOpen && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { elevation: 3, sx: {
105155
106812
  position: 'absolute',
105156
106813
  top: 4,
105157
106814
  right: 4,
@@ -105165,7 +106822,7 @@ function DiffViewer({ oldText, newText }) {
105165
106822
  border: '1px solid',
105166
106823
  borderColor: 'divider',
105167
106824
  } },
105168
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_32__["default"], { sx: { fontSize: 18, color: 'text.secondary' } }),
106825
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], { sx: { fontSize: 18, color: 'text.secondary' } }),
105169
106826
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("input", { ref: searchInputRef, value: searchQuery, onChange: (e) => { setSearchQuery(e.target.value); setCurrentMatch(0); }, onKeyDown: handleSearchKeyDown, placeholder: "\u041F\u043E\u0438\u0441\u043A...", style: {
105170
106827
  border: 'none',
105171
106828
  outline: 'none',
@@ -105176,13 +106833,13 @@ function DiffViewer({ oldText, newText }) {
105176
106833
  color: 'inherit',
105177
106834
  fontFamily: 'inherit',
105178
106835
  }, autoFocus: true }),
105179
- searchQuery && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "caption", sx: { color: 'text.secondary', whiteSpace: 'nowrap', minWidth: 50, textAlign: 'center' } }, totalMatches > 0 ? `${currentMatch + 1} / ${totalMatches}` : 'нет')),
106836
+ searchQuery && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", sx: { color: 'text.secondary', whiteSpace: 'nowrap', minWidth: 50, textAlign: 'center' } }, totalMatches > 0 ? `${currentMatch + 1} / ${totalMatches}` : 'нет')),
105180
106837
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => navigateMatch(-1), disabled: totalMatches === 0, sx: { p: 0.3 } },
105181
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_29__["default"], { sx: { fontSize: 18 } })),
106838
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_31__["default"], { sx: { fontSize: 18 } })),
105182
106839
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => navigateMatch(1), disabled: totalMatches === 0, sx: { p: 0.3 } },
105183
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_28__["default"], { sx: { fontSize: 18 } })),
106840
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_30__["default"], { sx: { fontSize: 18 } })),
105184
106841
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => { setSearchOpen(false); setSearchQuery(''); }, sx: { p: 0.3 } },
105185
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_24__["default"], { sx: { fontSize: 18 } })))),
106842
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_26__["default"], { sx: { fontSize: 18 } })))),
105186
106843
  !searchOpen && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], { size: "small", onClick: () => { setSearchOpen(true); setTimeout(() => searchInputRef.current?.focus(), 50); }, sx: {
105187
106844
  position: 'absolute',
105188
106845
  top: 28,
@@ -105193,11 +106850,11 @@ function DiffViewer({ oldText, newText }) {
105193
106850
  bgcolor: 'background.paper',
105194
106851
  boxShadow: 1,
105195
106852
  } },
105196
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_32__["default"], { sx: { fontSize: 16 } }))),
106853
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], { sx: { fontSize: 16 } }))),
105197
106854
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 1, sx: { mb: 1 }, alignItems: "center" },
105198
106855
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: `+${stats.added}`, size: "small", sx: { bgcolor: '#e6ffec', color: '#1a7f37', fontWeight: 'bold', fontFamily: 'monospace' } }),
105199
106856
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: `−${stats.removed}`, size: "small", sx: { bgcolor: '#ffebe9', color: '#cf222e', fontWeight: 'bold', fontFamily: 'monospace' } })),
105200
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { ref: tableRef, variant: "outlined", sx: {
106857
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { ref: tableRef, variant: "outlined", sx: {
105201
106858
  overflow: 'auto',
105202
106859
  maxHeight: 500,
105203
106860
  fontFamily: '"SFMono-Regular", Consolas, "Liberation Mono", Menlo, monospace',
@@ -105262,20 +106919,33 @@ function PromptManagerDialog({ open, onClose }) {
105262
106919
  // selectedApproaches: array of indices from PAIR_APPROACH_POOL, ordered
105263
106920
  const [selectedApproaches, setSelectedApproaches] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([0, 1, 2]);
105264
106921
  // imageApproachCounts: по одному на каждый подход (CREO_APPROACHES), каждый 0–4
105265
- const [imageApproachCounts, setImageApproachCounts] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => Array(_prompts__WEBPACK_IMPORTED_MODULE_34__.CREO_APPROACHES.length).fill(1));
106922
+ const [imageApproachCounts, setImageApproachCounts] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => Array(_prompts__WEBPACK_IMPORTED_MODULE_36__.CREO_APPROACHES.length).fill(1));
106923
+ const [creoToastOpen, setCreoToastOpen] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
106924
+ const [creoToastMessage, setCreoToastMessage] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
106925
+ const creoToastDebounceRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null);
105266
106926
  // Загрузить оверрайды при открытии
105267
106927
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
105268
106928
  if (open) {
105269
- const loaded = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.loadPromptOverrides)();
106929
+ const loaded = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.loadPromptOverrides)();
105270
106930
  setOverrides(loaded);
105271
- setSelectedApproaches((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.getSelectedPairApproaches)());
105272
- setImageApproachCounts((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.getImageApproachCounts)());
106931
+ setSelectedApproaches((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.getSelectedPairApproaches)());
106932
+ setImageApproachCounts((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.getImageApproachCounts)());
105273
106933
  setHasChanges(false);
105274
106934
  }
105275
106935
  }, [open]);
105276
106936
  const handleTabChange = (_event, newValue) => {
105277
106937
  setTabValue(newValue);
105278
106938
  };
106939
+ const showCreoTotalToast = (pairsCount, imageCount) => {
106940
+ const imageAspectRatio = localStorage.getItem('imageAspectRatio') || '1:1';
106941
+ const bothMultiplier = imageAspectRatio === 'both' ? 2 : 1;
106942
+ const total = pairsCount * imageCount * bothMultiplier;
106943
+ const formula = bothMultiplier === 2
106944
+ ? `${pairsCount} × ${imageCount} × 2 = ${total}`
106945
+ : `${pairsCount} × ${imageCount} = ${total}`;
106946
+ setCreoToastMessage(`Всего креативов: ${formula}`);
106947
+ setCreoToastOpen(true);
106948
+ };
105279
106949
  const handlePairApproachToggle = (idx) => {
105280
106950
  setSelectedApproaches(prev => {
105281
106951
  let next;
@@ -105286,11 +106956,13 @@ function PromptManagerDialog({ open, onClose }) {
105286
106956
  next = prev.filter(i => i !== idx);
105287
106957
  }
105288
106958
  else {
105289
- // Select — keep sorted by index
106959
+ // Select — сортировка по индексу подхода (порядок пар задаёт промпт по номерам 1…N)
105290
106960
  next = [...prev, idx].sort((a, b) => a - b);
105291
106961
  }
105292
106962
  setOverrides(o => ({ ...o, selectedPairApproaches: next }));
105293
106963
  setHasChanges(true);
106964
+ const imageCount = imageApproachCounts.reduce((a, b) => a + b, 0);
106965
+ setTimeout(() => showCreoTotalToast(next.length, imageCount), 0);
105294
106966
  return next;
105295
106967
  });
105296
106968
  };
@@ -105302,9 +106974,27 @@ function PromptManagerDialog({ open, onClose }) {
105302
106974
  next[idx] = clamped;
105303
106975
  setOverrides(o => ({ ...o, imageApproachCounts: next }));
105304
106976
  setHasChanges(true);
106977
+ // Debounced toast — показываем через 500ms после последнего изменения (стрелки/ввод)
106978
+ if (creoToastDebounceRef.current)
106979
+ clearTimeout(creoToastDebounceRef.current);
106980
+ creoToastDebounceRef.current = setTimeout(() => {
106981
+ creoToastDebounceRef.current = null;
106982
+ const pairsCount = selectedApproaches.length;
106983
+ const imageCount = next.reduce((a, b) => a + b, 0);
106984
+ showCreoTotalToast(pairsCount, imageCount);
106985
+ }, 500);
105305
106986
  return next;
105306
106987
  });
105307
106988
  };
106989
+ const handleImageCountBlur = () => {
106990
+ if (creoToastDebounceRef.current) {
106991
+ clearTimeout(creoToastDebounceRef.current);
106992
+ creoToastDebounceRef.current = null;
106993
+ }
106994
+ const pairsCount = selectedApproaches.length;
106995
+ const imageCount = imageApproachCounts.reduce((a, b) => a + b, 0);
106996
+ showCreoTotalToast(pairsCount, imageCount);
106997
+ };
105308
106998
  const handleToggleOverride = (promptName, enabled) => {
105309
106999
  setOverrides(prev => {
105310
107000
  const prevOverride = prev[promptName];
@@ -105355,14 +107045,15 @@ function PromptManagerDialog({ open, onClose }) {
105355
107045
  else {
105356
107046
  console.log(debugMsg, overrides);
105357
107047
  }
105358
- (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.savePromptOverrides)(overrides);
107048
+ (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.savePromptOverrides)(overrides);
107049
+ window.dispatchEvent(new Event(_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.PROMPT_OVERRIDES_SAVED_EVENT));
105359
107050
  setHasChanges(false);
105360
107051
  onClose();
105361
107052
  };
105362
107053
  const handleCancel = () => {
105363
107054
  if (hasChanges) {
105364
107055
  if (window.confirm('Есть несохраненные изменения. Закрыть без сохранения?')) {
105365
- setOverrides((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_36__.loadPromptOverrides)());
107056
+ setOverrides((0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.loadPromptOverrides)());
105366
107057
  setHasChanges(false);
105367
107058
  onClose();
105368
107059
  }
@@ -105376,25 +107067,25 @@ function PromptManagerDialog({ open, onClose }) {
105376
107067
  const getOriginalPrompt = (promptName) => {
105377
107068
  switch (promptName) {
105378
107069
  case 'getPairsSystemPrompt':
105379
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getPairsSystemPrompt)('${geo}', true, selectedApproaches.length, selectedApproaches);
107070
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getPairsSystemPrompt)('${geo}', true, selectedApproaches.length, selectedApproaches);
105380
107071
  case 'getPairsUserPrompt':
105381
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getPairsUserPrompt)('${product}', '${geo}', '${additionalInfo}', true, selectedApproaches.length, selectedApproaches);
107072
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getPairsUserPrompt)('${product}', '${geo}', '${additionalInfo}', true, selectedApproaches.length, selectedApproaches);
105382
107073
  case 'getTitlesSystemPrompt':
105383
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getTitlesSystemPrompt)('${geo}', true, selectedApproaches.length);
107074
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getTitlesSystemPrompt)('${geo}', true, selectedApproaches.length);
105384
107075
  case 'getTextsSystemPrompt':
105385
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getTextsSystemPrompt)('${geo}', true, selectedApproaches.length);
107076
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getTextsSystemPrompt)('${geo}', true, selectedApproaches.length);
105386
107077
  case 'getUserPrompt':
105387
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getUserPrompt)('${product}', '${geo}', '${additionalInfo}', 'titles', true, selectedApproaches.length);
107078
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getUserPrompt)('${product}', '${geo}', '${additionalInfo}', 'titles', true, selectedApproaches.length);
105388
107079
  case 'getImageCheckPrompt':
105389
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getImageCheckPrompt)('${product}', '${geo}', true);
107080
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getImageCheckPrompt)('${product}', '${geo}', true);
105390
107081
  case 'getValidationPrompt':
105391
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getValidationPrompt)('${product}', '${geo}', ['keyword1', 'keyword2'], '${approachName}', true);
107082
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getValidationPrompt)('${product}', '${geo}', ['keyword1', 'keyword2'], '${approachName}', true, 'Новая по брифу: 29 EUR; старая (2×): 58 EUR — в рантайме подставляется из поля цены; в кастомном промпте плейсхолдер ${priceBrief}');
105392
107083
  case 'getImageGenerationBasePrompt':
105393
- return (0,_prompts__WEBPACK_IMPORTED_MODULE_34__.getImageGenerationBasePrompt)('${generateGeo}', '${generatePrice}', '${generateCurrency}', true);
107084
+ return (0,_prompts__WEBPACK_IMPORTED_MODULE_36__.getImageGenerationBasePrompt)('${generateGeo}', '${generatePrice}', '${generateCurrency}', true);
105394
107085
  case 'getLandingPageSystemPrompt':
105395
- return (0,_landingPrompts__WEBPACK_IMPORTED_MODULE_35__.getLandingPageSystemPrompt)(true);
107086
+ return (0,_landingPrompts__WEBPACK_IMPORTED_MODULE_37__.getLandingPageSystemPrompt)(true);
105396
107087
  case 'getLandingPageUserPrompt':
105397
- return (0,_landingPrompts__WEBPACK_IMPORTED_MODULE_35__.getLandingPageUserPrompt)('${product}', '${geo}', true);
107088
+ return (0,_landingPrompts__WEBPACK_IMPORTED_MODULE_37__.getLandingPageUserPrompt)('${product}', '${geo}', true);
105398
107089
  default:
105399
107090
  return '';
105400
107091
  }
@@ -105416,18 +107107,18 @@ function PromptManagerDialog({ open, onClose }) {
105416
107107
  enabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
105417
107108
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { size: "small", value: viewMode, exclusive: true, onChange: (_, val) => val && setViewModes(prev => ({ ...prev, [viewModeKey]: val })) },
105418
107109
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { value: "edit" },
105419
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_26__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
107110
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_28__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
105420
107111
  " \u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440"),
105421
107112
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { value: "diff" },
105422
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_25__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
107113
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_27__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
105423
107114
  " Diff")),
105424
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_30__["default"], null), onClick: () => handleResetPrompt(promptName) }, "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C")))),
105425
- description && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, description)),
107115
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_32__["default"], null), onClick: () => handleResetPrompt(promptName) }, "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C")))),
107116
+ description && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "body2", color: "text.secondary", sx: { mb: 1 } }, description)),
105426
107117
  enabled && viewMode === 'diff' ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(DiffViewer, { oldText: originalPrompt, newText: customPrompt })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SearchableTextField, { rows: 15, value: displayPrompt, onChange: (e) => handlePromptChange(promptName, e.target.value), disabled: !enabled, placeholder: enabled ? 'Введите кастомный промпт' : 'Включите переключатель для редактирования', helperText: !enabled ? 'Это оригинальный промпт. Включите переключатель выше для редактирования.' : undefined }))));
105427
107118
  };
105428
107119
  // Управление подходами для изображений
105429
107120
  const handleApproachToggle = (approachName, enabled) => {
105430
- const originalApproach = _prompts__WEBPACK_IMPORTED_MODULE_34__.CREO_APPROACHES.find(a => a.name === approachName);
107121
+ const originalApproach = _prompts__WEBPACK_IMPORTED_MODULE_36__.CREO_APPROACHES.find(a => a.name === approachName);
105431
107122
  if (!originalApproach)
105432
107123
  return;
105433
107124
  setOverrides(prev => {
@@ -105477,8 +107168,8 @@ function PromptManagerDialog({ open, onClose }) {
105477
107168
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], { open: open, onClose: handleCancel, maxWidth: "lg", fullWidth: true },
105478
107169
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], null,
105479
107170
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center" },
105480
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_33__["default"], null),
105481
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "h6" }, "\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u043C\u043F\u0442\u0430\u043C\u0438"),
107171
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_35__["default"], null),
107172
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "h6" }, "\u0423\u043F\u0440\u0430\u0432\u043B\u0435\u043D\u0438\u0435 \u043F\u0440\u043E\u043C\u043F\u0442\u0430\u043C\u0438"),
105482
107173
  hasChanges && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: "\u0415\u0441\u0442\u044C \u043D\u0435\u0441\u043E\u0445\u0440\u0430\u043D\u0435\u043D\u043D\u044B\u0435 \u0438\u0437\u043C\u0435\u043D\u0435\u043D\u0438\u044F", color: "warning", size: "small" })))),
105483
107174
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], null,
105484
107175
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { value: tabValue, onChange: handleTabChange, sx: { borderBottom: 1, borderColor: 'divider' } },
@@ -105489,9 +107180,41 @@ function PromptManagerDialog({ open, onClose }) {
105489
107180
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TabPanel, { value: tabValue, index: 0 },
105490
107181
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { mb: 3, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 } },
105491
107182
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mb: 1.5 } },
105492
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0442\u0435\u043A\u0441\u0442\u043E\u0432 (\u043F\u0430\u0440\u044B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A + \u0442\u0435\u043A\u0441\u0442)"),
107183
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0442\u0435\u043A\u0441\u0442\u043E\u0432 (\u043F\u0430\u0440\u044B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A + \u0442\u0435\u043A\u0441\u0442)"),
105493
107184
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: `Выбрано: ${selectedApproaches.length}`, color: "primary", size: "small" }),
105494
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "caption", color: "text.secondary" }, "(\u043C\u0438\u043D\u0438\u043C\u0443\u043C 2, \u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C 10)")),
107185
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", color: "text.secondary" }, "(\u043C\u0438\u043D\u0438\u043C\u0443\u043C 2, \u043C\u0430\u043A\u0441\u0438\u043C\u0443\u043C 10)")),
107186
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", color: "text.secondary", sx: { display: 'block', mb: 0.75 } }, "\u0422\u0438\u043F \u0442\u043E\u0432\u0430\u0440\u0430 \u2014 \u0431\u044B\u0441\u0442\u0440\u044B\u0439 \u043D\u0430\u0431\u043E\u0440 \u043F\u0430\u0440 \u0442\u0435\u043A\u0441\u0442\u043E\u0432 \u0438 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432 \u043A \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F\u043C (1\u201310 = \u2116 \u0441\u0442\u0440\u043E\u043A\u0438 \u0432 \u043A\u0430\u0436\u0434\u043E\u0439 \u0442\u0430\u0431\u043B\u0438\u0446\u0435):"),
107187
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", flexWrap: "wrap", gap: 0.75, sx: { mb: 1.5 } }, Object.entries(_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.PRODUCT_TYPE_TEXT_PAIR_PRESETS).map(([label, nums]) => (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { key: label, title: productTypePresetTooltip(label), placement: "top", arrow: true, enterDelay: 200, componentsProps: {
107188
+ tooltip: {
107189
+ sx: {
107190
+ maxWidth: 420,
107191
+ bgcolor: 'grey.900',
107192
+ color: 'common.white',
107193
+ border: '1px solid',
107194
+ borderColor: 'grey.700',
107195
+ '& .MuiTooltip-arrow': { color: 'grey.900' },
107196
+ },
107197
+ },
107198
+ } },
107199
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", variant: "outlined", color: "inherit", sx: { textTransform: 'none', fontSize: '0.8rem' }, onClick: () => {
107200
+ const next = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.productPresetNumbersToIndices)(nums);
107201
+ if (next.length < 2)
107202
+ return;
107203
+ const imgNums = _promptOverrides__WEBPACK_IMPORTED_MODULE_38__.PRODUCT_TYPE_IMAGE_PRESETS[label];
107204
+ const nextImageCounts = imgNums
107205
+ ? (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_38__.productPresetNumbersToImageCounts)(imgNums)
107206
+ : Array(_prompts__WEBPACK_IMPORTED_MODULE_36__.CREO_APPROACHES.length).fill(1);
107207
+ setSelectedApproaches(next);
107208
+ setImageApproachCounts(nextImageCounts);
107209
+ setOverrides(o => ({
107210
+ ...o,
107211
+ selectedPairApproaches: next,
107212
+ imageApproachCounts: nextImageCounts,
107213
+ }));
107214
+ setHasChanges(true);
107215
+ const imageCount = nextImageCounts.reduce((a, b) => a + b, 0);
107216
+ setTimeout(() => showCreoTotalToast(next.length, imageCount), 0);
107217
+ } }, label))))),
105495
107218
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { overflowX: 'auto' } },
105496
107219
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("table", { style: { width: '100%', borderCollapse: 'collapse', fontSize: 12 } },
105497
107220
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("thead", null,
@@ -105500,7 +107223,7 @@ function PromptManagerDialog({ open, onClose }) {
105500
107223
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc', whiteSpace: 'nowrap', width: 140 } }, "\u0423\u0433\u043E\u043B"),
105501
107224
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc' } }, "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043E\u043A"),
105502
107225
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc' } }, "\u0422\u0435\u043A\u0441\u0442"))),
105503
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, _prompts__WEBPACK_IMPORTED_MODULE_34__.PAIR_APPROACH_POOL.map((p, i) => {
107226
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, _prompts__WEBPACK_IMPORTED_MODULE_36__.PAIR_APPROACH_POOL.map((p, i) => {
105504
107227
  const checked = selectedApproaches.includes(i);
105505
107228
  const isLast = checked && selectedApproaches.length <= 2;
105506
107229
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", { key: i, onClick: () => handlePairApproachToggle(i), style: {
@@ -105512,16 +107235,16 @@ function PromptManagerDialog({ open, onClose }) {
105512
107235
  transition: 'opacity 0.15s, background-color 0.15s',
105513
107236
  } },
105514
107237
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { textAlign: 'center', padding: '2px 8px' } },
105515
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { checked: checked, disabled: isLast, size: "small", onClick: e => e.stopPropagation(), onChange: () => handlePairApproachToggle(i), sx: { p: 0.5 } })),
107238
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { checked: checked, disabled: isLast, size: "small", onClick: e => e.stopPropagation(), onChange: () => handlePairApproachToggle(i), sx: { p: 0.5 } })),
105516
107239
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', fontWeight: 500, whiteSpace: 'nowrap' } }, p.name),
105517
107240
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, p.titleApproach),
105518
107241
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, p.textApproach.split('\n')[0])));
105519
107242
  }))))),
105520
107243
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { mb: 3, p: 2, border: '1px solid', borderColor: 'divider', borderRadius: 1 } },
105521
107244
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mb: 1.5 } },
105522
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439"),
107245
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle1", sx: { fontWeight: 600 } }, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439"),
105523
107246
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: `Всего: ${imageApproachCounts.reduce((a, b) => a + b, 0)}`, color: "primary", size: "small" }),
105524
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "caption", color: "text.secondary" }, "(0\u20134 \u043D\u0430 \u043A\u0430\u0436\u0434\u044B\u0439 \u043F\u043E\u0434\u0445\u043E\u0434)")),
107247
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "caption", color: "text.secondary" }, "(0\u20134 \u043D\u0430 \u043A\u0430\u0436\u0434\u044B\u0439 \u043F\u043E\u0434\u0445\u043E\u0434)")),
105525
107248
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { overflowX: 'auto' } },
105526
107249
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("table", { style: { width: '100%', borderCollapse: 'collapse', fontSize: 12 } },
105527
107250
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("thead", null,
@@ -105529,14 +107252,14 @@ function PromptManagerDialog({ open, onClose }) {
105529
107252
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'center', padding: '4px 8px', borderBottom: '1px solid #ccc', width: 70 } }, "\u041A\u043E\u043B-\u0432\u043E"),
105530
107253
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc', whiteSpace: 'nowrap', width: 180 } }, "\u041F\u043E\u0434\u0445\u043E\u0434"),
105531
107254
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("th", { style: { textAlign: 'left', padding: '4px 8px', borderBottom: '1px solid #ccc' } }, "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435"))),
105532
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, _prompts__WEBPACK_IMPORTED_MODULE_34__.CREO_APPROACHES.map((approach, i) => {
107255
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tbody", null, _prompts__WEBPACK_IMPORTED_MODULE_36__.CREO_APPROACHES.map((approach, i) => {
105533
107256
  const count = imageApproachCounts[i] ?? 0;
105534
107257
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement("tr", { key: i, style: { opacity: count > 0 ? 1 : 0.6 } },
105535
107258
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { textAlign: 'center', padding: '2px 8px', verticalAlign: 'middle' } },
105536
107259
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { type: "number", size: "small", value: count, onChange: (e) => {
105537
107260
  const v = parseInt(e.target.value, 10);
105538
107261
  handleImageApproachCountChange(i, isNaN(v) ? 0 : v);
105539
- }, inputProps: { min: 0, max: 4, step: 1 }, sx: { width: 56, '& .MuiInputBase-input': { textAlign: 'center', py: 0.5 } } })),
107262
+ }, onBlur: handleImageCountBlur, inputProps: { min: 0, max: 4, step: 1 }, sx: { width: 56, '& .MuiInputBase-input': { textAlign: 'center', py: 0.5 } } })),
105540
107263
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', fontWeight: 500, whiteSpace: 'nowrap' } }, approach.name),
105541
107264
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, approach.prompt.split('\n')[0])));
105542
107265
  }))))),
@@ -105544,46 +107267,46 @@ function PromptManagerDialog({ open, onClose }) {
105544
107267
  renderPromptEditor('getPairsUserPrompt', 'Пользовательский промпт (пары)', 'Пользовательский промпт для генерации пар. Переменные: ${product}, ${geo}, ${additionalInfo}, ${count}, ${n}')),
105545
107268
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TabPanel, { value: tabValue, index: 1 },
105546
107269
  renderPromptEditor('getImageGenerationBasePrompt', 'Базовый промпт для изображений', 'Базовый промпт, используемый для всех подходов'),
105547
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "h6", sx: { mt: 3, mb: 2 } }, "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432 \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
105548
- _prompts__WEBPACK_IMPORTED_MODULE_34__.CREO_APPROACHES.map((approach) => {
107270
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "h6", sx: { mt: 3, mb: 2 } }, "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u043D\u0438\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432 \u0434\u043B\u044F \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0438 \u043A\u0440\u0435\u0430\u0442\u0438\u0432\u043E\u0432"),
107271
+ _prompts__WEBPACK_IMPORTED_MODULE_36__.CREO_APPROACHES.map((approach) => {
105549
107272
  const override = overrides.creoApproaches?.[approach.name];
105550
107273
  const enabled = override?.enabled || false;
105551
107274
  const approachViewKey = `approach_${approach.name}`;
105552
107275
  const approachViewMode = viewModes[approachViewKey] || 'edit';
105553
- return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], { key: approach.name, sx: { mb: 2 } },
105554
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_27__["default"], null) },
107276
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { key: approach.name, sx: { mb: 2 } },
107277
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_29__["default"], null) },
105555
107278
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { width: '100%', mr: 2 } },
105556
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle1" }, approach.name),
107279
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle1" }, approach.name),
105557
107280
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { label: enabled ? 'Кастомный' : 'Оригинал', color: enabled ? 'primary' : 'default', size: "small" }),
105558
- enabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_30__["default"], null), onClick: (e) => {
107281
+ enabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_32__["default"], null), onClick: (e) => {
105559
107282
  e.stopPropagation();
105560
107283
  handleResetApproach(approach.name);
105561
107284
  } }, "\u0421\u0431\u0440\u043E\u0441\u0438\u0442\u044C")))),
105562
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], null,
107285
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], null,
105563
107286
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mb: 2 } },
105564
107287
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_8__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { checked: enabled, onChange: (e) => handleApproachToggle(approach.name, e.target.checked) }), label: "\u0418\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u0441\u0442\u043E\u043C\u043D\u044B\u0439 \u043F\u043E\u0434\u0445\u043E\u0434" }),
105565
107288
  enabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], { size: "small", value: approachViewMode, exclusive: true, onChange: (_, val) => val && setViewModes(prev => ({ ...prev, [approachViewKey]: val })) },
105566
107289
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { value: "edit" },
105567
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_26__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
107290
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_28__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
105568
107291
  " \u0420\u0435\u0434\u0430\u043A\u0442\u043E\u0440"),
105569
107292
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { value: "diff" },
105570
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_25__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
107293
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_27__["default"], { sx: { fontSize: 16, mr: 0.5 } }),
105571
107294
  " Diff")))),
105572
107295
  enabled && approachViewMode === 'diff' ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], null,
105573
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle2", sx: { mb: 1 } }, "\u041F\u0440\u043E\u043C\u043F\u0442 \u043F\u043E\u0434\u0445\u043E\u0434\u0430"),
107296
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle2", sx: { mb: 1 } }, "\u041F\u0440\u043E\u043C\u043F\u0442 \u043F\u043E\u0434\u0445\u043E\u0434\u0430"),
105574
107297
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(DiffViewer, { oldText: approach.prompt, newText: override?.customPrompt || approach.prompt }),
105575
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle2", sx: { mt: 2, mb: 1 } }, "\u0423\u0433\u043E\u043B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430"),
107298
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle2", sx: { mt: 2, mb: 1 } }, "\u0423\u0433\u043E\u043B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430"),
105576
107299
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(DiffViewer, { oldText: approach.headlineAngle, newText: override?.customHeadlineAngle || approach.headlineAngle }),
105577
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle2", sx: { mt: 2, mb: 1 } }, "\u0424\u043E\u043A\u0443\u0441 \u043D\u0430 \u0431\u0443\u043B\u043B\u0435\u0442\u0430\u0445"),
107300
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle2", sx: { mt: 2, mb: 1 } }, "\u0424\u043E\u043A\u0443\u0441 \u043D\u0430 \u0431\u0443\u043B\u043B\u0435\u0442\u0430\u0445"),
105578
107301
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(DiffViewer, { oldText: approach.bulletsFocus, newText: override?.customBulletsFocus || approach.bulletsFocus }))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
105579
107302
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { mb: 2 } },
105580
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle2", gutterBottom: true }, "\u041F\u0440\u043E\u043C\u043F\u0442 \u043F\u043E\u0434\u0445\u043E\u0434\u0430"),
107303
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle2", gutterBottom: true }, "\u041F\u0440\u043E\u043C\u043F\u0442 \u043F\u043E\u0434\u0445\u043E\u0434\u0430"),
105581
107304
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SearchableTextField, { rows: 4, value: override?.customPrompt || approach.prompt, onChange: (e) => handleApproachFieldChange(approach.name, 'customPrompt', e.target.value), disabled: !enabled })),
105582
107305
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], { sx: { mb: 2 } },
105583
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle2", gutterBottom: true }, "\u0423\u0433\u043E\u043B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430"),
107306
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle2", gutterBottom: true }, "\u0423\u0433\u043E\u043B \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0430"),
105584
107307
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SearchableTextField, { rows: 2, value: override?.customHeadlineAngle || approach.headlineAngle, onChange: (e) => handleApproachFieldChange(approach.name, 'customHeadlineAngle', e.target.value), disabled: !enabled })),
105585
107308
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_1__["default"], null,
105586
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_3__["default"], { variant: "subtitle2", gutterBottom: true }, "\u0424\u043E\u043A\u0443\u0441 \u043D\u0430 \u0431\u0443\u043B\u043B\u0435\u0442\u0430\u0445"),
107309
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_2__["default"], { variant: "subtitle2", gutterBottom: true }, "\u0424\u043E\u043A\u0443\u0441 \u043D\u0430 \u0431\u0443\u043B\u043B\u0435\u0442\u0430\u0445"),
105587
107310
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(SearchableTextField, { rows: 2, value: override?.customBulletsFocus || approach.bulletsFocus, onChange: (e) => handleApproachFieldChange(approach.name, 'customBulletsFocus', e.target.value), disabled: !enabled })))))));
105588
107311
  })),
105589
107312
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TabPanel, { value: tabValue, index: 2 },
@@ -105592,9 +107315,10 @@ function PromptManagerDialog({ open, onClose }) {
105592
107315
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(TabPanel, { value: tabValue, index: 3 },
105593
107316
  renderPromptEditor('getLandingPageSystemPrompt', 'Промпт лендинга (System)', 'Системный промпт для генерации лендинг-страниц'),
105594
107317
  renderPromptEditor('getLandingPageUserPrompt', 'Промпт лендинга (User)', 'Пользовательский промпт для генерации лендинг-страниц'))),
105595
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], null,
105596
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { onClick: handleCancel, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_23__["default"], null) }, "\u041E\u0442\u043C\u0435\u043D\u0430"),
105597
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { onClick: handleSave, variant: "contained", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_31__["default"], null), disabled: !hasChanges }, "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C"))));
107318
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], null,
107319
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { onClick: handleCancel, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_25__["default"], null) }, "\u041E\u0442\u043C\u0435\u043D\u0430"),
107320
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { onClick: handleSave, variant: "contained", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_33__["default"], null), disabled: !hasChanges }, "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C")),
107321
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { open: creoToastOpen, autoHideDuration: 3000, onClose: () => setCreoToastOpen(false), message: creoToastMessage, anchorOrigin: { vertical: 'bottom', horizontal: 'center' } })));
105598
107322
  }
105599
107323
 
105600
107324
 
@@ -105813,6 +107537,9 @@ const MODELS = {
105813
107537
  "use strict";
105814
107538
  __webpack_require__.r(__webpack_exports__);
105815
107539
  /* harmony export */ __webpack_require__.d(__webpack_exports__, {
107540
+ /* harmony export */ PRODUCT_TYPE_IMAGE_PRESETS: () => (/* binding */ PRODUCT_TYPE_IMAGE_PRESETS),
107541
+ /* harmony export */ PRODUCT_TYPE_TEXT_PAIR_PRESETS: () => (/* binding */ PRODUCT_TYPE_TEXT_PAIR_PRESETS),
107542
+ /* harmony export */ PROMPT_OVERRIDES_SAVED_EVENT: () => (/* binding */ PROMPT_OVERRIDES_SAVED_EVENT),
105816
107543
  /* harmony export */ getCreoApproachOverride: () => (/* binding */ getCreoApproachOverride),
105817
107544
  /* harmony export */ getImageApproachCounts: () => (/* binding */ getImageApproachCounts),
105818
107545
  /* harmony export */ getPairsCount: () => (/* binding */ getPairsCount),
@@ -105820,6 +107547,11 @@ __webpack_require__.r(__webpack_exports__);
105820
107547
  /* harmony export */ getSelectedPairApproaches: () => (/* binding */ getSelectedPairApproaches),
105821
107548
  /* harmony export */ loadOverridesFromElectron: () => (/* binding */ loadOverridesFromElectron),
105822
107549
  /* harmony export */ loadPromptOverrides: () => (/* binding */ loadPromptOverrides),
107550
+ /* harmony export */ mergePromptApproachesFromDriveFile: () => (/* binding */ mergePromptApproachesFromDriveFile),
107551
+ /* harmony export */ normalizeImageApproachCountsFromDrive: () => (/* binding */ normalizeImageApproachCountsFromDrive),
107552
+ /* harmony export */ normalizeSelectedPairApproachesFromDrive: () => (/* binding */ normalizeSelectedPairApproachesFromDrive),
107553
+ /* harmony export */ productPresetNumbersToImageCounts: () => (/* binding */ productPresetNumbersToImageCounts),
107554
+ /* harmony export */ productPresetNumbersToIndices: () => (/* binding */ productPresetNumbersToIndices),
105823
107555
  /* harmony export */ resetAllOverrides: () => (/* binding */ resetAllOverrides),
105824
107556
  /* harmony export */ resetCreoApproachOverride: () => (/* binding */ resetCreoApproachOverride),
105825
107557
  /* harmony export */ resetPromptOverride: () => (/* binding */ resetPromptOverride),
@@ -105831,6 +107563,50 @@ __webpack_require__.r(__webpack_exports__);
105831
107563
  * Утилиты для работы с оверрайдами промптов
105832
107564
  */
105833
107565
  const STORAGE_KEY = 'promptOverrides';
107566
+ /** Номера 1–10 = строка в таблице подходов (PAIR_APPROACH_POOL[i] → номер i + 1). Порядок в массиве не важен — при применении сортируется по номеру строки. */
107567
+ const PRODUCT_TYPE_TEXT_PAIR_PRESETS = {
107568
+ похудалки: [1, 2, 3, 6, 10],
107569
+ простатит: [1, 6, 8, 10, 7],
107570
+ потенция: [6, 10, 8, 7, 1],
107571
+ диабет: [8, 1, 7, 6, 10],
107572
+ паразиты: [6, 1, 8, 5, 7],
107573
+ суставы: [1, 3, 8, 2, 7],
107574
+ };
107575
+ /** Номера 1–10 = строка в таблице подходов к изображениям (CREO_APPROACHES[i] → номер i + 1). Порядок в массиве не важен. */
107576
+ const PRODUCT_TYPE_IMAGE_PRESETS = {
107577
+ похудалки: [2, 3, 6, 8, 10],
107578
+ простатит: [1, 4, 5, 6, 7, 8, 9],
107579
+ потенция: [1, 4, 5, 6, 7, 8, 9],
107580
+ диабет: [1, 4, 6, 9],
107581
+ паразиты: [4, 5, 7, 8],
107582
+ суставы: [3, 4, 5, 6, 9],
107583
+ };
107584
+ /** Индексы PAIR_APPROACH_POOL (0-based), по возрастанию. */
107585
+ function productPresetNumbersToIndices(oneBased) {
107586
+ const poolLen = 10;
107587
+ const seen = new Set();
107588
+ for (const n of oneBased) {
107589
+ const i = n - 1;
107590
+ if (i >= 0 && i < poolLen)
107591
+ seen.add(i);
107592
+ }
107593
+ return [...seen].sort((a, b) => a - b);
107594
+ }
107595
+ /**
107596
+ * Пресет типа товара → массив длиной IMAGE_APPROACH_COUNT: у выбранных подходов кол-во 1, у остальных 0.
107597
+ */
107598
+ function productPresetNumbersToImageCounts(oneBased) {
107599
+ const counts = Array(IMAGE_APPROACH_COUNT).fill(0);
107600
+ const seen = new Set();
107601
+ for (const n of oneBased) {
107602
+ const i = n - 1;
107603
+ if (i >= 0 && i < IMAGE_APPROACH_COUNT && !seen.has(i)) {
107604
+ seen.add(i);
107605
+ counts[i] = 1;
107606
+ }
107607
+ }
107608
+ return counts;
107609
+ }
105834
107610
  // Debug logging — пишет в терминал Electron (или в console как fallback)
105835
107611
  function _debugLog(...args) {
105836
107612
  const api = typeof window !== 'undefined' ? window.electronAPI : null;
@@ -105864,6 +107640,34 @@ function getPairsCount() {
105864
107640
  }
105865
107641
  /** Количество подходов для изображений. Должно совпадать с CREO_APPROACHES.length в prompts.ts */
105866
107642
  const IMAGE_APPROACH_COUNT = 10;
107643
+ const PAIR_APPROACH_POOL_LEN = 10;
107644
+ /** Нормализация индексов пар из JSON с диска (0-based, уникальные, отсортированные, минимум 2). */
107645
+ function normalizeSelectedPairApproachesFromDrive(raw) {
107646
+ if (!Array.isArray(raw))
107647
+ return null;
107648
+ const seen = new Set();
107649
+ for (const x of raw) {
107650
+ const n = typeof x === 'number' && Number.isInteger(x) ? x : parseInt(String(x), 10);
107651
+ if (Number.isInteger(n) && n >= 0 && n < PAIR_APPROACH_POOL_LEN)
107652
+ seen.add(n);
107653
+ }
107654
+ const out = [...seen].sort((a, b) => a - b);
107655
+ return out.length >= 2 ? out : null;
107656
+ }
107657
+ /** Нормализация количеств крео из JSON с диска (длина 10, 0–4; хотя бы один подход > 0). */
107658
+ function normalizeImageApproachCountsFromDrive(raw) {
107659
+ if (!Array.isArray(raw))
107660
+ return null;
107661
+ const out = [];
107662
+ for (let i = 0; i < IMAGE_APPROACH_COUNT; i++) {
107663
+ const v = raw[i];
107664
+ const n = typeof v === 'number' && Number.isFinite(v) ? v : parseInt(String(v), 10);
107665
+ out.push(Number.isFinite(n) ? Math.max(0, Math.min(4, Math.round(n))) : 0);
107666
+ }
107667
+ if (out.every(c => c === 0))
107668
+ return null;
107669
+ return out;
107670
+ }
105867
107671
  /**
105868
107672
  * Получить количество изображений по каждому подходу (N элементов, 0–4).
105869
107673
  * По умолчанию — по 1 на каждый подход.
@@ -105929,6 +107733,32 @@ function savePromptOverrides(overrides) {
105929
107733
  console.error('Failed to save prompt overrides:', err);
105930
107734
  }
105931
107735
  }
107736
+ /** Имя события после сохранения подходов в менеджере промптов — чтобы синхронизировать JSON на Drive. */
107737
+ const PROMPT_OVERRIDES_SAVED_EVENT = 'docs-combiner-prompt-overrides-saved';
107738
+ /**
107739
+ * Подмешать в localStorage выбранные подходы из project-settings.json на Drive (если поля валидны).
107740
+ */
107741
+ function mergePromptApproachesFromDriveFile(loadedData) {
107742
+ const pairs = normalizeSelectedPairApproachesFromDrive(loadedData.selectedPairApproaches);
107743
+ const counts = normalizeImageApproachCountsFromDrive(loadedData.imageApproachCounts);
107744
+ if (!pairs && !counts)
107745
+ return false;
107746
+ const overrides = loadPromptOverrides();
107747
+ let dirty = false;
107748
+ if (pairs) {
107749
+ overrides.selectedPairApproaches = pairs;
107750
+ dirty = true;
107751
+ }
107752
+ if (counts) {
107753
+ overrides.imageApproachCounts = counts;
107754
+ dirty = true;
107755
+ }
107756
+ if (dirty) {
107757
+ savePromptOverrides(overrides);
107758
+ return true;
107759
+ }
107760
+ return false;
107761
+ }
105932
107762
  /**
105933
107763
  * Получить оверрайд для простого промпта
105934
107764
  */
@@ -106123,58 +107953,57 @@ function _debugLog(...args) {
106123
107953
  const PAIR_APPROACH_POOL = [
106124
107954
  {
106125
107955
  name: 'болевая точка',
106126
- titleApproach: 'прямой удар по симптому — только боль/дискомфорт, без решения в заголовке',
106127
- textApproach: 'Начни с прямого называния симптома или дискомфорта без вопроса, просто факт боли (например: «Боль не даёт нормально двигаться», «Дискомфорт с утра до вечера» адаптируй под категорию продукта). Покажи, как продукт точечно устраняет именно этот симптом. Конкретика, без общих обещаний.',
107956
+ titleApproach: 'одна ясная боль (не две проблемы в одном заголовке). Усиливай через несправедливость / ощущение «так несправедливо» (устал бороться, снова срыв, тело не слушается) не только сухое перечисление симптомов. ЗАГОЛОВОК = КОНСТАТАЦИЯ, не вопрос: ЗАПРЕЩЕНО заканчивать на «почему?», «perché?», «why?» и подобное — боль называешь фактом, не спрашиваешь',
107957
+ textApproach: 'Одна центральная проблема за текстне распыляйся на несколько болей. ЗАПРЕЩЕНО перечислять ингредиенты, состав, matcha/MCT/«формулу» это территория «авторитет/экспертиза», не болевой точки. Опиши дискомфорт и как продукт снимает именно эту боль; без каталога компонентов.',
106128
107958
  },
106129
107959
  {
106130
107960
  name: 'трансформация до/после',
106131
- titleApproach: 'контраст жизни до и послеизменение состояния, результат трансформации',
106132
- textApproach: 'Начни с описания «жизни до» («Раньше я…», «Antes sentía…»). Покажи контраст — как изменилось состояние после применения. Конкретный результат с таймингом.',
107961
+ titleApproach: 'контраст СОСТОЯНИЙ и ощущений до/после (вздутие/усталость → лёгкость, тяжесть → контроль, «не узнаю себя в зеркале» → спокойствие) с якорем во времени во фразе, но БЕЗ цифр на весах. ЗАПРЕЩЕНО в заголовке: −X kg, «persi N kg», весы, любой явный минус килограммов это только у testimonial',
107962
+ textApproach: 'СТРОГО от первого лица («Я / Io / Yo…»). Это не отзыв с именем это МОЙ контраст «как было плохо / как стало лучше» по телу и эмоциям. ЗАПРЕЩЕНО копировать формат отзыва: не начинай как реклама «я попробовала продукт и минус X кг» подряд; сначала ощущения и жизнь до/после, продукт — связка, а не пересказ цифр с весов (цифры веса допустимы в тексте лишь второстепенно, если уместно; акцент — на смене состояния). ЗАПРЕЩЕНО соцдоказательство («многие отмечают», «molte persone»).',
106133
107963
  },
106134
107964
  {
106135
107965
  name: 'testimonial',
106136
107966
  isTestimonial: true,
106137
- titleApproach: 'намекает на личный результат или трансформацию (например «Наконец-то без боли 😌», «-4 кг за 2 недели ✅» примеры формата, адаптируй под категорию). НЕ использует «Имя, возраст:» — это только для текста',
106138
- textApproach: `СТРОГО от первого лица и начинается с «Имя, возраст:» («Kasia, 41 lat:», «Maria, 52 años:»).
106139
- * Начинается с «Имя, возраст:» обязательно
106140
- * Возраст должен соответствовать аудитории основном 45+, для похудения допустим ниже)
106141
- * История от первого лица (я/мне/у меня)
106142
- * Конкретный результат с таймингом (7–14 дней; примеры: «Po 7 dniach...», «Después de 2 semanas...»)
107967
+ titleApproach: 'короткая «живая» фраза с конкретикой результата на весах/сроке («−2,8 kg in 10 giorni… incredibile 😅») здесь УМЕСТНЫ −кг и срок; это отличает testimonial от «трансформации». НЕ используй «Имя, возраст:» в заголовке — только в тексте',
107968
+ textApproach: `Это единственный подход-ОТЗЫВ: читатель должен поверить в реального человека.
107969
+ * Обязательно начало текста с «Имя, возраст:» («Giulia, 49 anni:», «Kasia, 41 lat:»)
107970
+ * История только от первого лица после имени
107971
+ * Конкретный результат с таймингом (7–14 дней), можно килограммы и детали быта
106143
107972
  * Заканчивается приглашением попробовать + CTA`,
106144
107973
  },
106145
107974
  {
106146
107975
  name: 'срочность/дефицит',
106147
- titleApproach: 'дедлайн по офферу или запасам«только сегодня», «последний шанс», ограниченное количество',
107976
+ titleApproach: 'ТОЛЬКО дефицит оффера: время до конкретного дедлайна, остаток штук, «до полуночи», «осталось N упаковок» ЗАПРЕЩЕНО в заголовке проблема, тело, продукт, «лишние кг», категория товара. Не баннер магазина — конкретная граница (день, час, число мест)',
106148
107977
  textApproach: 'Начни с конкретного сигнала ограниченности — времени или количества («Tylko dziś», «Últimas unidades», «Осталось 12 упаковок», «Акция до конца дня»). Весь текст строится ИСКЛЮЧИТЕЛЬНО вокруг дефицита или дедлайна: осталось мало, время заканчивается, потом будет дороже или не будет вообще. ЗАПРЕЩЕНО упоминать состав, ингредиенты, свойства или пользу продукта — только ограниченность оффера. CTA максимально срочный.',
106149
107978
  },
106150
107979
  {
106151
107980
  name: 'социальное доказательство',
106152
- titleApproach: 'цифры людей, которые уже решили проблему — «X из Y», популярность, массовый результат',
107981
+ titleApproach: 'одна ЧИТАЕМАЯ фраза с крупной цифрой (например «50.000 italiane hanno già scelto … 🔥») грамматика и смысл на языке GEO должны сходиться; читатель понимает фразу с первого раза. ЗАПРЕЩЕНО несвязные склейки («9 su 10 scelgono controllo 🔥 fame») и обрывки, где цифра + существительные не составляют нормального высказывания',
106153
107982
  textApproach: 'Начни с цифры или массового факта («Уже 50 000 клиентов», «9 din 10 femei observă diferența»). Акцент на том, что проблему уже решили тысячи — и ты тоже можешь.',
106154
107983
  },
106155
107984
  {
106156
107985
  name: 'любопытство/интрига',
106157
- titleApproach: 'секрет, «почему не работают другие методы», неожиданный факт, открытие',
107986
+ titleApproach: 'провокационный вопрос или утверждение, которое ломает сразу ДВА привычных решения (диета И спорт / dieta e palestra…), — но ОДНОЙ ЦЕЛЬНОЙ фразой: связный синтаксис, без рубки на обрывки через запятую и эмодзи посередине. Пример уровня: «Dieta e palestra ma la pancia resta? 🤔» — а не три оторванных куска',
106158
107987
  textApproach: 'Начни с провокационного вопроса или неожиданного инсайта («Знаете, почему обычные средства не помогают?», «¿Sabías que…?»). Раскрой неочевидный факт о проблеме или механизме решения и выведи к продукту.',
106159
107988
  },
106160
107989
  {
106161
107990
  name: 'авторитет/экспертиза',
106162
- titleApproach: 'состав, происхождение, механизм действия, научный подход, проверенная формула',
107991
+ titleApproach: 'information gap: в заголовке ЗАПРЕЩЕНО называть ингредиенты и раскрывать метод/механизм напрямую — никаких matcha, MCT, tè verde, «formula con…», «metodo naturale per…», «accelerare il metabolismo», «supporta il metabolismo» и т.п.; иначе ответ уже в заголовке и клик не нужен. Подай состав или подход как тайну / открытие / «что скрывают» / «почему это не то же самое, что обычные средства» — без конкретики, ответ только в основном тексте. ЗАПРЕЩЕНЫ эмодзи-подсказки по составу (например 🍵, если по смыслу выдаёт чай), если они заменяют то, что должен открыть текст. Не закрывай интригу формулировками уровня «Perché X e Y supportano…»',
106163
107992
  textApproach: 'Начни с ФАКТА/утверждения об экспертизе («Włoska receptura», «Hecho en Italia», «3 składniki naturalne», «Разработано фармацевтами»). Акцент на составе, происхождении или механизме действия. Почему это работает — объясни просто и убедительно.',
106164
107993
  },
106165
107994
  {
106166
107995
  name: 'страх бездействия',
106167
- titleApproach: 'последствия промедления — что будет, если не решить проблему сейчас (дедлайн по здоровью, не по скидке)',
106168
- textApproach: 'Начни с описания негативного сценария бездействия («С каждым днём становится хуже…», «Если не взять под контроль сейчас…»). Покажи, что проблема прогрессирует. CTA — не про скидку, а про заботу о себе прямо сейчас.',
107996
+ titleApproach: 'узнаваемый паттерн промедления — ОДНА СВЯЗНАЯ фраза (допустимы многоточие, союз «но», тире), а не перечень обрывков через запятую. Пример уровня: «Rimandi a lunedì… ma la fame non aspetta 😣» — смысл течёт от начала к концу',
107997
+ textApproach: 'Начни с описания негативного сценария бездействия («С каждым днём становится хуже…», «Если не взять под контроль сейчас…»). Покажи, что проблема прогрессирует. Финальный CTA — ТОЛЬКО про заботу о себе / начать сейчас / не откладывать (на языке GEO). ЗАПРЕЩЕНЫ прямые призывы к заказу в финале: «ordina ora», «закажи», «купи сейчас», «clicca e acquista» — вместо них: взять под контроль, сделать первый шаг, начать сегодня и т.п.',
106169
107998
  },
106170
107999
  {
106171
108000
  name: 'прямой оффер/выгода',
106172
- titleApproach: 'конкретная числовая выгода в заголовке — сколько экономишь или что получаешь (например «-50%», «Вторая упаковка бесплатно», «Цена как раньше»). НЕ просто «скидка есть» — а ЧТО именно и сколько',
108001
+ titleApproach: 'конкретная числовая выгода в заголовке — сколько экономишь или что получаешь (например «-50%», «Вторая упаковка бесплатно», «Цена как раньше»). НЕ просто «скидка есть» — а ЧТО именно и сколько. ОБЯЗАТЕЛЬНО минимум один эмодзи в заголовке (💸 🔥 ✨ 🎁 ⏳ 📦 и т.п.) — как у остальных подходов в наборе, без эмодзи заголовок считается ошибкой',
106173
108002
  textApproach: 'Аудитория уже думает о покупке — текст снимает последнее сомнение, а не убеждает в проблеме. Начни с оффера числом: скидка -50%, конкретная цена, что получаешь за эти деньги. Ответь на вопрос «почему взять сейчас, а не завтра» — цена вырастет, акция закончится, запас ограничен. ЗАПРЕЩЕНО объяснять пользу продукта или описывать проблему — читатель уже всё знает. Только сделка, только экономика, только CTA с акцентом на выгоде прямо сейчас.',
106174
108003
  },
106175
108004
  {
106176
108005
  name: 'ситуационный/узнаваемый момент',
106177
- titleApproach: 'конкретный момент из жизни, узнаваемая сцена, ситуативный крючок',
108006
+ titleApproach: 'одна яркая узнаваемая сцена в 1–2 коротких связных сегментах (лучше одна картинка), без перечня симптомов через запятую. Пример уровня: «Dopo pranzo i pantaloni tirano 😩» — сразу видно момент и боль; ЗАПРЕЩЕНО нагромождать «после обеда 😩 джинсы, живот, тесно» отдельными ярлыками',
106178
108007
  textApproach: 'Начни с конкретной жизненной сцены, где проблема ощущается («[ключевой симптом категории продукта]…», «Вечером перед сном не можешь уснуть из-за дискомфорта…» — адаптируй под категорию). Создай узнаваемую ситуацию — читатель должен сказать «это про меня» — и предложи решение.',
106179
108008
  },
106180
108009
  ];
@@ -106379,6 +108208,12 @@ function getPairsSystemPrompt(geo, noOverride, count = 3, selectedIndices) {
106379
108208
  const distributionLines = pairs
106380
108209
  .map((p, i) => `Пара ${i + 1} → [${p.name}]:\n Заголовок: ${p.titleApproach}\n Текст: ${p.textApproach}`)
106381
108210
  .join('\n');
108211
+ const hasUrgencyScarcity = pairs.some(p => p.name === 'срочность/дефицит');
108212
+ const hasFearInaction = pairs.some(p => p.name === 'страх бездействия');
108213
+ const hasSocialProof = pairs.some(p => p.name === 'социальное доказательство');
108214
+ const hasAuthorityExpertise = pairs.some(p => p.name === 'авторитет/экспертиза');
108215
+ const hasDirectOffer = pairs.some(p => p.name === 'прямой оффер/выгода');
108216
+ const hasTransformAndTestimonial = pairs.some(p => p.name === 'трансформация до/после') && pairs.some(p => p.isTestimonial);
106382
108217
  const deadlineNote = n >= 2
106383
108218
  ? `- В Тексте 1 ИЛИ Тексте 2 ОБЯЗАТЕЛЬНО укажи ожидаемый срок результата 7–14 дней (на языке ${geo}).`
106384
108219
  : `- В Тексте 1 ОБЯЗАТЕЛЬНО укажи ожидаемый срок результата 7–14 дней (на языке ${geo}).`;
@@ -106393,6 +108228,11 @@ function getPairsSystemPrompt(geo, noOverride, count = 3, selectedIndices) {
106393
108228
 
106394
108229
  ... и так для всех ${n} пар. Каждая пара отделена пустой строкой.
106395
108230
 
108231
+ КРИТИЧНО ДЛЯ РАЗБОРА:
108232
+ - Служебные метки в начале строки пиши РОВНО как в примере: слово «ЗАГОЛОВОК» целиком кириллицей (не ZAG, не смесь латиницы и кириллицы), слово «ТЕКСТ» целиком кириллицей.
108233
+ - Не вставляй строки «ЗАГОЛОВОК N:» внутрь текста объявления; каждый заголовок — отдельная строка перед своим «ТЕКСТ N:».
108234
+ - Контент объявления (заголовок и текст) — на языке ${geo}; только метки ЗАГОЛОВОК/ТЕКСТ остаются кириллицей как шаблон.
108235
+
106396
108236
  РАСПРЕДЕЛЕНИЕ ПОДХОДОВ ПО ПАРАМ:
106397
108237
  ${distributionLines}
106398
108238
 
@@ -106400,20 +108240,24 @@ ${distributionLines}
106400
108240
  - Заголовок — короткий крючок (боль или триггер)
106401
108241
  - Текст — раскрывает тот же угол глубже, добавляет детали, заканчивается CTA
106402
108242
  - Текст НЕ повторяет заголовок дословно, но развивает его смысл
108243
+ - Не подмешивай чужие углы: например в «трансформация до/после» не используй формулировки соцдоказательства («многие отмечают», «клиенты говорят»)
108244
+ ${hasTransformAndTestimonial ? '\n- РАЗВЕДЕНИЕ «трансформация до/после» и «testimonial» в одном ответе: у трансформации заголовок = контраст ощущений/состояния (без −кг и без «минус X kg за N дней»); у testimonial заголовок может содержать −кг, весы, срок — как убедительный отзыв. Не делай два заголовка в одном формате «цифра + срок на весах».' : ''}
106403
108245
 
106404
108246
  ТРЕБОВАНИЯ К ЗАГОЛОВКУ:
106405
108247
  - До 55–60 символов, максимум 6–7 слов
108248
+ - Цельность: заголовок читается как одно высказывание (или один связный вопрос целиком). ЗАПРЕЩЕНО склеивать несвязные ярлыки запятыми ради ключевых слов; эмодзи не должно разрывать грамматику так, что фраза перестаёт быть человеческой
106406
108249
  - ЗАПРЕЩЕНО двоеточие (:) — используй тире (—) или переформулируй
106407
- - 1–2 эмодзи естественно внутри (не только в конце); избегай ⚠️ и 🚨
106408
- - Хотя бы одно ключевое слово проблемы, релевантное продукту
106409
- - НЕ упоминай название продукта — заголовок = боль + триггер
108250
+ - 1–2 эмодзи естественно (часто в конце фразы или после целого смыслового блока); избегай ⚠️ и 🚨${hasDirectOffer ? '\n- Для пары «прямой оффер/выгода» эмодзи в заголовке ОБЯЗАТЕЛЕН (минимум один) — визуально вровень с остальными парами набора' : ''}
108251
+ - Хотя бы одно ключевое слово проблемы, релевантное продукту${hasUrgencyScarcity ? '\n- ИСКЛЮЧЕНИЕ: для пары с подходом «срочность/дефицит» в заголовке ЗАПРЕЩЕНЫ симптомы, проблема, тело, продукт — только лимит оффера (время, количество, дедлайн)' : ''}${hasAuthorityExpertise ? '\n- Пара «авторитет/экспертиза»: заголовок держит information gap — без ингредиентов и без прямого названия механизма; состав и «как это работает» — только в тексте пары' : ''}
108252
+ - НЕ упоминай название продукта — заголовок = боль + триггер${hasUrgencyScarcity ? ' (кроме пары «срочность/дефицит»: там заголовок = только дефицит/дедлайн, без продукта и без боли)' : ''}${hasSocialProof ? '\n- Исключение: в паре «социальное доказательство» название продукта в заголовке допустимо, если оно входит в цельную фразу про массовый выбор (например «N persone hanno già scelto [продукт]»)' : ''}
106410
108253
  - Звучит как живая рекламная фраза, а не строка ключевых слов
106411
108254
 
106412
108255
  ТРЕБОВАНИЯ К ТЕКСТУ:
106413
108256
  - 150–280 символов (testimonial — до 300)
106414
- - Хотя бы одно ключевое слово проблемы
106415
- - Сильный явный CTA в конце («кликни», «попробуй сейчас», «закажи», «не жди»)
108257
+ - Хотя бы одно ключевое слово проблемы (для «срочность/дефицит» в тексте допустимо слабее, если весь фокус — на лимите оффера)
108258
+ - Сильный явный CTA в конце («кликни», «попробуй сейчас», «закажи», «не жди»)${hasFearInaction ? '\n- ИСКЛЮЧЕНИЕ: для пары «страх бездействия» финальная фраза — не заказ, а забота о себе / начать сейчас; без «ordina ora», «закажи», «купи», «clicca e acquista» в конце' : ''}
106416
108259
  - Короткие рубленые фразы, императивы, FOMO допустим${hasTestimonial ? '\n- Testimonial: строго от первого лица, начинается с «Имя, возраст:», конкретный результат с таймингом' : ''}
108260
+ - Ингредиенты и состав из доп. информации — только в углах «авторитет/экспертиза» (и сходных); в «болевой точке» и чисто эмоциональных углах состав не перечислять
106417
108261
  ${deadlineNote}
106418
108262
 
106419
108263
  ОБЩИЕ ТРЕБОВАНИЯ:
@@ -106472,7 +108316,9 @@ function getImageCheckPrompt(product, geo, noOverride) {
106472
108316
  /**
106473
108317
  * Промпт для валидации рекламных креативов
106474
108318
  */
106475
- function getValidationPrompt(product, geo, keywords, approachName, noOverride) {
108319
+ function getValidationPrompt(product, geo, keywords, approachName, noOverride,
108320
+ /** Краткий эталон цен из приложения (новая + ожидаемая старая при -50%); пусто — без сверки чисел */
108321
+ priceBrief) {
106476
108322
  if (!noOverride) {
106477
108323
  const override = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_0__.getPromptOverride)('getValidationPrompt');
106478
108324
  if (override?.enabled && override.customPrompt) {
@@ -106481,63 +108327,49 @@ function getValidationPrompt(product, geo, keywords, approachName, noOverride) {
106481
108327
  .replace(/\$\{product\}/g, product)
106482
108328
  .replace(/\$\{geo\}/g, geo)
106483
108329
  .replace(/\$\{keywords\}/g, keywords.join(', '))
106484
- .replace(/\$\{approachLine\}/g, approachLine);
108330
+ .replace(/\$\{approachLine\}/g, approachLine)
108331
+ .replace(/\$\{priceBrief\}/g, priceBrief?.trim() || 'В приложении бриф цены не задан — сверяй только визуально две цены и -50%.');
106485
108332
  }
106486
108333
  }
106487
108334
  const approachLine = approachName?.trim() ? `\nПОДХОД: ${approachName.trim()}\n` : '\n';
106488
- // Resolve no-bullets conditions in code — don't leave "if approach = X" for the LLM
106489
- const noBulletsApproachNames = CREO_APPROACHES.filter(a => a.noBullets).map(a => a.name);
106490
- const isNoBullets = noBulletsApproachNames.includes(approachName?.trim() ?? '');
106491
108335
  const isScreenshotReviews = (approachName?.trim() ?? '') === 'Скрин отзывов';
106492
- // ШАГ 0 hint for BULLETS depends on approach
106493
- const step0BulletsHint = isNoBullets
106494
- ? `BULLETS: [] (для данного подхода буллиты запрещены ожидается 0)`
106495
- : `BULLETS: ["...","...","..."] (если буллетов не 3перечисли сколько есть)`;
106496
- // ШАГ 2 completely different rules for no-bullets approaches vs normal
106497
- const step2Bullets = isNoBullets
106498
- ? `ШАГ 2 — BULLETS (критично):
106499
- - Данный подход НЕ допускает буллитов. Буллетов должно быть РОВНО 0.
106500
- - Если на креативе есть ЛЮБЫЕ буллиты — это ОШИБКА.`
106501
- : `ШАГ 2 — BULLETS (критично):
106502
- - РОВНО 3 буллета. Если буллетов не 3 — ОШИБКА.
106503
- - Каждый буллет должен быть читабельным (хорошо читается на телефоне, не микрошрифт)
106504
- - Буллеты: крупные, с иконками/галочками (), на контрастных подложках. Буллеты НЕ на упаковке/банке.
106505
- - Формат бенефита РАЗРЕШЁН: «Чувствуешь себя легче», «Больше энергии», «Без дискомфорта», «Лёгкость движений»это бенефиты, НЕ предложения
106506
- - ПРЕДЛОЖЕНИЕ (ошибка) = полная грамматическая конструкция с подлежащим + сказуемым + дополнением, например «Продукт быстро снижает дискомфорт». Короткие бенефиты — не считать предложениями
106507
- - Буллиты с глаголом во 2-м лице («Чувствуешь...», «Получаешь...») или безличные («Больше энергии», «Без дискомфорта») — НЕ ошибка
106508
- - Буллеты = свойства, характеристики ИЛИ бенефиты. Разрешено: «Reduce disconfortul», «Mai puține treziri», «Efect în 14 zile», цифры соц. доказательства.
106509
- - Буллиты должны быть расположены вертикально (столбиком). Если буллиты идут горизонтально в одну строкуОШИБКА: плохая читаемость на мобиле
106510
- - Цена визуально ОТЛИЧНА от буллитов (цена компактный блок без иконок; буллетыс иконками/галочками). Если цена выглядит как буллет ОШИБКА.`;
106511
- // ШАГ 3 TEXT LIMIT: PVP has no badges allowed, normal allows urgency/trust (без проверок по длине/количеству слов)
106512
- const step3TextLimit = isScreenshotReviews
106513
- ? `ШАГ 3OTHER_TEXT (критично):
106514
- - Для «Скрин отзывов» блок отзывов (аватарки, имена, возраст, 5 звёзд, текст отзывов) — это НЕ ошибка, это основной контент.
106515
- - Допускаются также trust‑печати (0–3 шт). URGENCY не рекомендуется, но не ошибка.
106516
- - На креативе допустимы: HOOK, блок отзывов, цена, скидка, CTA, опционально trust‑печати.`
106517
- : isNoBullets
106518
- ? `ШАГ 3 — OTHER_TEXT (критично):
106519
- - OTHER_TEXT должен быть ПУСТЫМ (0 элементов). Никаких дополнительных бейджей, подписей, ярлыков, trust‑печатей/urgency — НИЧЕГО.
106520
- - Любой дополнительный текст (бейджи/подписи/пояснения/urgency/trust‑печати) ОШИБКА: слишком много текста для punch‑креатива.
106521
- - На креативе допустимы ТОЛЬКО: HOOK, цена, скидка, кнопка CTA.`
106522
- : `ШАГ 3OTHER_TEXT (критично):
106523
- - По умолчанию любой другой рекламный текст (бейджи/подписи/пояснения) запрещён.
106524
- - НО допускаются (не обязательно) дополнительные бейджи ВНЕ упаковки — это НЕ ошибка, если ВСЕ элементы OTHER_TEXT подпадают под разрешённые типы:
106525
- A) URGENCY (0–1 шт): бейдж срочности/дефицита — только ясные формулировки («только сегодня», «последние штуки», «акция до конца дня»). ЗАПРЕЩЕНО: «24h» и подобные — непонятно что означает.
106526
- B) TRUST (0–3 шт, для «Минимализм / Clean Big Text» — макс 1): печати цветные, яркие, очень похожие на печать FDA. Подчёркивают: натуральность состава, премиальность, безопасность. Допустимо: качество, натуральные ингредиенты, экологичность, контроль качества. Печати — размер как минимум как у буллитов, крупные. Даже одна печать — крупная.
106527
- Правила для каждого элемента OTHER_TEXT:
106528
- * строго на языке ${geo} (без английских слов)
106529
- * без цены/скидки/процентов (кроме обязательного поля DISCOUNT), без доменов/ссылок
106530
- * TRUST‑печати — про натуральность/премиальность/безопасность (не про доставку/поддержку)
106531
- Примеры стиля (адаптируй к языку GEO, не требуются):
106532
- - URGENCY: «Ostatnie sztuki», «Tylko dziś», «Koniec dziś» (НЕ «24h» — непонятно)
106533
- - TRUST: «Naturalna formuła», «Wysoka jakość» (для PL); «Ingrediente naturale», «Calitate» (для RO). ЗАПРЕЩЕНО: «NATURAL», «QUALITY», «100% NATURAL» — английские слова.
106534
- - Если OTHER_TEXT содержит что-то вне этих типов, или URGENCY > 1, или TRUST > 3 (для Минимализма — TRUST > 1) — ОШИБКА.`;
108336
+ // Буллеты валидатором не проверяются (ни количество, ни наличие)
108337
+ const step0BulletsHint = 'BULLETS: кратко опиши, что видишь на макете (для справки). Количество и наличие буллетов НЕ валидируются.';
108338
+ const step2Bullets = `ШАГ 2БУЛЛЕТЫ:
108339
+ - Не проверяй и не оценивай количество, отсутствие или наличие буллетов. 0, 1, 2, 3 и большевсё допустимо.
108340
+ - НЕ добавляй в финальный список ошибок ни одного пункта, связанного с буллетами (вертикальность, «ровно 3», иконки, читаемость буллетов и т.п.).`;
108341
+ const priceBriefTrim = priceBrief?.trim() || '';
108342
+ const stepPriceBrief = priceBriefTrim
108343
+ ? `ШАГ P ЦЕНЫ (сначала макет, потом бриф):
108344
+ Эталон из приложения:
108345
+ ${priceBriefTrim}
108346
+
108347
+ 1) ВНУТРЕННЯЯ ЛОГИКА НА МАКЕТЕ (главное):
108348
+ - Должны быть видны две суммы: новая (акционная) и старая (зачёркнутая). Старая новой при скидке -50% (допуск до ~2% из‑за округления; «1 180» и «1180» — одно и то же).
108349
+ - Если отношение старая/новая 2 пределах допуска) это уже доказательство корректной пары -50% на макете. В этом случае ЗАПРЕЩЕНО выводить ОШИБКУ формулировками вроде «выдуманные цены», «неверные суммы», «не соответствуют брифу» даже если цифры в брифе другие или бриф кажется не тем.
108350
+ - Если пара математически согласована с -50% и процент «-50%» где‑либо читаем в зоне оффера (см. ШАГ 4) — не придумывай расхождение с брифом из‑за символа валюты (€ / EUR / MXN и т.д.) или пробелов.
108351
+
108352
+ 2) СВЕРКА С БРИФОМ (только когда сопоставимо):
108353
+ - Сравнивай число НОВОЙ цены с брифом ТОЛЬКО если валюта на макете явно та же, что в брифе (EUR↔EUR, MXN↔MXN и т.д.; символ € и код EUR одна валюта). Допускается разное оформление числа (пробелы тысяч, запятая/точка).
108354
+ - Если валюта на креативе другая, чем в брифе, или не уверен в коде валюты не требуй совпадения цифр с брифом: достаточно пункта (1).
108355
+ - Ошибку по ценам ставь только если: (а) на макете нет двух цен / нет согласованности -50%, ИЛИ (б) валюта однозначно совпадает с брифом, а число новой цены явно другое (не в пределах округления).
108356
+
108357
+ 3) Цена не должна быть оформлена как строка буллета с галочкой отдельный блок.`
108358
+ : `ШАГ P ЦЕНЫ (бриф числом не задан):
108359
+ - На макете должны быть ДВЕ цены, старая зачёркнута толсто, новая выразительна; пара должна визуально соответствовать -50% (старая ≈ 2× новой). Конкретные суммы с приложением не сверяй.`;
108360
+ const step3OtherText = isScreenshotReviews
108361
+ ? `ШАГ 3 — Подход «Скрин отзывов»:
108362
+ - Блок отзывов (аватары, имена, звёзды, текст) это нормальный контент креатива, не считай его лишним OTHER_TEXT.`
108363
+ : `ШАГ 3 Доп. текст, бейджи, печати:
108364
+ - Не валидируй объём текста и не отклоняй креатив за «слишком много элементов», punch vs не punch, количество плашек или пустоту OTHER_TEXT.
108365
+ - Не требуй отсутствия trust/urgency/подписей для любого подхода это не ошибка.
108366
+ - Язык рекламного текста (включая бейджи) по-прежнему ШАГ 5. Неясные срочности вроде «24h» — по-прежнему ШАГ 6.`;
106535
108367
  return `Ты — СТРОГИЙ валидатор рекламных креативов (1:1). Не улучшай и не предлагай идеи — только проверка и вердикт.
106536
108368
  Продукт: ${product}. GEO/язык: ${geo}.${approachLine}
106537
108369
 
106538
108370
  ВАЖНО:
106539
- - Проверяй язык ТОЛЬКО для рекламного текста на макете (заголовок/буллеты/CTA/цена/скидка/разрешённые бейджи из OTHER_TEXT). Текст на самой упаковке/этикетке игнорируй (включая название/бренд вроде "${product}").
106540
- - Если сомневаешься, где расположен текст (на упаковке или вне её) — считай, что он НА упаковке и НЕ записывай его в OTHER_TEXT.
108371
+ - Проверяй язык ТОЛЬКО для рекламного текста на макете (заголовок/CTA/цена/скидка/разрешённые бейджи из OTHER_TEXT; если есть буллеты — и их текст). Текст на самой упаковке/этикетке игнорируй (включая название/бренд вроде "${product}").
108372
+ - Если сомневаешься, мелкий текст на банке — этикетка или нет: для языка считай этикеткой и не валидируй. Исключение: **нижний оффер-блок** макета (две цены, зачёркивание, «-50%», кнопка CTA в одной полосе/ряду под картинкой продукта) — это всегда рекламный слой **вне упаковки**, даже рядом с фото банки; цены и скидку оттуда учитывай в PRICE/DISCOUNT и не считай «на упаковке».
106541
108373
  - Если текст плохо читается/микрошрифт — это ошибка.
106542
108374
 
106543
108375
  ШАГ 0 — Сначала выпиши распознанный текст (как ты его видишь на макете):
@@ -106547,9 +108379,7 @@ PRICE: "..." (если нет — "нет")
106547
108379
  DISCOUNT: "..." (если нет — "нет")
106548
108380
  CTA: "..." (если нет — "нет")
106549
108381
  OTHER_TEXT: ["..."] (любой другой рекламный текст на макете ВНЕ упаковки и ВНЕ элементов выше; название/бренд на упаковке НЕ включай)
106550
- (если можешь, для ясности — не обязательно):
106551
- URGENCY_BADGE: "..." (бейдж срочности, если есть; «24h» — ОШИБКА, непонятно что означает)
106552
- TRUST_BADGES: ["..."] (печати цветные, яркие, в стиле FDA; про натуральность/премиальность/безопасность; размер как у буллитов — крупные, если есть)
108382
+ (опционально, для ясности): URGENCY_BADGE, TRUST_BADGES перечисли, если есть
106553
108383
 
106554
108384
  ШАГ 1 — HOOK/HEADLINE (критично):
106555
108385
  - Должен быть ВЫШЕ всех элементов и читабелен (хорошо читается на телефоне)
@@ -106562,35 +108392,38 @@ TRUST_BADGES: ["..."] (печати цветные, яркие, в стиле FD
106562
108392
 
106563
108393
  ${step2Bullets}
106564
108394
 
108395
+ ${stepPriceBrief}
108396
+
106565
108397
  ШАГ 2.5 — CLAIMS CHECK:
106566
108398
  - Клеймы по результату (жёсткие/абсолютные или мягкие) — НЕ проверяются и НЕ запрещаются. Не блокируй за формулировки обещаний результата.
106567
108399
 
106568
- ${step3TextLimit}
108400
+ ${step3OtherText}
106569
108401
 
106570
- ШАГ 4 — CTA > PRICE (критично):
108402
+ ШАГ 4 — CTA и визуал цены/скидки (критично):
106571
108403
  - CTA: на языке ${geo}, хорошо заметная кнопка (позиция НЕ важна: можно вправо/влево/по центру). Главное — CTA читабельна и выглядит как кнопка.
106572
- - Цена: ОБЯЗАТЕЛЬНО ДВЕ старая (до скидки) + новая. Если только одна цена ОШИБКА. Старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Тонкое/незаметное зачёркивание — ОШИБКА.
106573
- - Скидка ОБЯЗАТЕЛЬНА: «-50%» отдельным видимым бейджем (процент должен быть явно читаем, не только в цене). Ярко, заметно. Строго НЕ на упаковке/банке.
108404
+ - Блок цен: две суммы, старая зачёркнута ТОЛСТОЙ линией, новая выразительно (детали и сверка чисел с брифом в ШАГ P). Если только одна цена — ОШИБКА.
108405
+ - Скидка ОБЯЗАТЕЛЬНА: читаемое «-50%». **Отдельный видимый бейдж** = любая заметная плашка/круг/прямоугольник с текстом «-50в **той же зоне оффера**, что и цены (сбоку от сумм, над/под ценовой строкой, между ценой и CTA) это ОК, не требуй отдельного «далёкого» элемента. «НЕ на упаковке» означает только: не напечатано на этикетке/банке товара; плашка в нижней рекламной полосе макета **не** считается упаковкой.
108406
+ - Если в ШАГ 0 в DISCOUNT ты указал «-50%» (или эквивалент) — ЗАПРЕЩЕНО ставить ошибку «скидка не отображается» / «нет отдельного бейджа».
106574
108407
  - Не считать ошибкой, если скидка/цена конкурируют с CTA по акценту — это допустимо, пока CTA остаётся хорошо заметной и читабельной.
106575
108408
  - Если скидка указана и она не равна -50% — ошибка.
106576
108409
 
106577
108410
  ШАГ 5 — ЯЗЫК (критично):
106578
- - В рекламном тексте (HOOK/HEADLINE/BULLETS/CTA/PRICE/DISCOUNT/OTHER_TEXT) НЕТ английских слов. Если есть — ошибка.
108411
+ - В рекламном тексте (HOOK/HEADLINE, текст на буллетах если есть, CTA/PRICE/DISCOUNT/OTHER_TEXT) НЕТ английских слов. Если есть — ошибка.
108412
+ - ЗАПРЕЩЁННЫЕ служебные подписи на макете (частая ошибка модели): слова HOOK, CTA, CAPS, BULLET, HEADLINE, PRICE, DISCOUNT как видимый текст на плашках или кнопке — ОШИБКА (это метки из брифа, не для читателя).
106579
108413
  - Все слова соответствуют GEO/языку ${geo}. Если смешение языков — ошибка.
106580
108414
 
106581
108415
  ШАГ 6 — КОМПОЗИЦИЯ:
106582
108416
  - Если креатив без человека (lifestyle/clean), проверь наличие контекста использования (кухня, стол, тумбочка, и т.д.). Продукт на полностью пустом/белом фоне без контекста — РЕКОМЕНДАЦИЯ к улучшению (не критичная ошибка, но слабый визуал)
106583
- - КОНТРАСТ ПЛАШЕК: если хотя бы одна текстовая плашка (HOOK, буллеты, CTA или цена) визуально сливается с фоном и текст плохо читается — это ОШИБКА.
106584
- - ЦЕНА: ОБЯЗАТЕЛЬНО ДВЕ старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Одна цена или тонкое зачёркивание ОШИБКА. Цена не должна выглядеть как буллет.
106585
- - TRUST‑печати: если печати мелкие или текст нечитабелен на телефоне — ОШИБКА (размер как минимум как у буллитов).
106586
- - СКИДКА «-50%»: ОБЯЗАТЕЛЬНО отдельным видимым бейджем (процент явно читаем). Если скидка не отображается или только в цене без отдельного «-50%» ОШИБКА. Ярко, заметно, НЕ на упаковке.
106587
- - ЦЕНА: ОБЯЗАТЕЛЬНО ДВЕ — старая зачёркнута ТОЛСТОЙ линией (не тонкой!), новая выразительно. Одна цена или тонкое зачёркивание — ОШИБКА.
108417
+ - КОНТРАСТ ПЛАШЕК: если HOOK, CTA или блок цен визуально сливается с фоном и текст плохо читается — это ОШИБКА. (Контраст буллетов не проверяй.)
108418
+ - Две цены и зачёркивание старой см. ШАГ 4 и ШАГ P. Цена не должна быть оформлена как элемент списка с галочкой в стиле бенефитов.
108419
+ - TRUST‑печати: если печати мелкие или текст нечитабелен на телефоне — ОШИБКА (должны быть крупными).
108420
+ - СКИДКА «-50%»: как в ШАГ 4 плашка рядом с ценами в оффер-блоке засчитывается; если DISCOUNT в ШАГ 0 заполненне дублируй ошибку про бейдж.
106588
108421
  - Бейджи срочности: «24h» и подобные неясные формулировки — ОШИБКА (непонятно что означает). Ясные («только сегодня», «последние штуки») — ок.
106589
108422
 
106590
108423
  ФИНАЛ:
106591
108424
  Выведи строго:
106592
108425
  СТАТУС: OK / НУЖНА ПЕРЕСБОРКА
106593
- Затем список ошибок, каждая строка начинается с "ОШИБКА:" (кратко, по делу). Если ошибок нет — напиши "ОШИБКА: нет".
108426
+ Затем список ошибок, каждая строка начинается с "ОШИБКА:" (кратко, по делу). Одну и ту же проблему не повторяй — не больше одной строки на один тип нарушения. Если СТАТУС: НУЖНА ПЕРЕСБОРКА — ОБЯЗАТЕЛЬНО минимум одна конкретная строка "ОШИБКА: ..." (что именно не так); нельзя писать только "ОШИБКА: нет". Если ошибок нет — СТАТУС: OK и "ОШИБКА: нет".
106594
108427
  Затем список рекомендаций (если есть), каждая строка начинается с "РЕКОМЕНДАЦИЯ:" (кратко, по делу). Если рекомендаций нет — напиши "РЕКОМЕНДАЦИЯ: нет".
106595
108428
  Не блокируй за клеймы по результату или формулировки обещаний.`;
106596
108429
  }
@@ -106626,6 +108459,9 @@ function getImageGenerationBasePrompt(generateGeo, generatePrice, generateCurren
106626
108459
  ВАЖНО: изображение должно быть ${ratioShape} — строго соблюдай пропорции холста.
106627
108460
  Язык текста: ${generateGeo}.
106628
108461
 
108462
+ 🚫 СЛУЖЕБНЫЕ СЛОВА НЕ РИСОВАТЬ НА КАРТИНКЕ (КРИТИЧНО):
108463
+ Слова HOOK, CTA, CAPS, BULLET, HEADLINE, PRICE, DISCOUNT, BULLETS, LAYER и любые похожие английские метки из этой инструкции (в т.ч. thumb‑stop) — только для тебя; на макете их НЕТ ни на кнопке, ни на плашках, ни мелким текстом. Кнопка: только реальный призыв на языке ${generateGeo} (1–2 слова), без префикса «CTA». Заголовок: только живой текст оффера, без слова HOOK. Заголовок делай прописными буквами на языке ${generateGeo}, но не пиши на изображении слово CAPS и не подписывай блоки ярлыками.
108464
+
106629
108465
  🚨 КРИТИЧНО — РЕЛЕВАНТНОСТЬ ПРОДУКТУ (читай ЭТО ПЕРВЫМ):
106630
108466
  - Название продукта передано в начале промпта (строка «🏷️ ПРОДУКТ: ...»). Прочитай его ПРЯМО СЕЙЧАС и определи категорию.
106631
108467
  - Категории и их проблемы: суставы/колени → боль в суставах, скованность, тугоподвижность; пищеварение → дискомфорт после еды, тяжесть; сон → бессонница, усталость; похудение → лишний вес; простата → частые позывы, дискомфорт.
@@ -106656,7 +108492,7 @@ HOOK / HEADLINE (строгое правило):
106656
108492
  - 1–4 строки; до 12 слов. Без переноса внутри слова
106657
108493
  - ОБЯЗАТЕЛЬНО содержит ключевое слово проблемы ЯВНО. Примеры по категориям: простата → простатит, простата; похудение → лишний вес, похудение; суставы → боль в суставах, колени, скованность; пищеварение → дискомфорт, вздутие, тяжесть; сон → бессонница, усталость. Без ключевого слова — ОШИБКА
106658
108494
  - HOOK ВЫШЕ всех элементов (продукт, буллеты, CTA, цена). Самый крупный текстовый элемент на креативе
106659
- - HOOK должен быть ВИЗУАЛЬНО “тяжёлым”: ОЧЕНЬ крупный, ТОЛСТЫЙ/жирный шрифт, ВСЕ БУКВЫ ПРОПИСНЫЕ (CAPS), на яркой контрастной плашке/подложке. Это верхний главный “thumb‑stop” элемент
108495
+ - HOOK должен быть ВИЗУАЛЬНО “тяжёлым”: ОЧЕНЬ крупный, ТОЛСТЫЙ/жирный шрифт, весь текст заголовка ПРОПИСНЫМИ буквами на языке ${generateGeo}, на яркой контрастной плашке/подложке. Это верхний главный элемент, цепляющий внимание в ленте
106660
108496
  - Можно (не обязательно) включить СРОК прямо в HOOK (например «7 dni», «14 dni») как триггер
106661
108497
  - Заголовок должен быть РЕЗКИМ и призывным: короткие рубленые фразы, вопросы и предупреждения допустимы. Можно использовать обращение на «ты» (в языке GEO: «Masz…», «Twój…») и вопросительный знак
106662
108498
  - заголовок НЕ должен быть абстрактным слоганом/лозунгом или метафорой без конкретной боли. Допускается «thumb‑stop» стиль (вызов/вопрос/предупреждение), если это конкретно и релевантно категории
@@ -106707,7 +108543,7 @@ CTA > PRICE:
106707
108543
  ❗ ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → цена и «-50%» могут быть более крупными и заметными, но CTA всё равно должен оставаться очень заметным и выглядеть как кнопка (не теряется на фоне)
106708
108544
 
106709
108545
  ПОКАЗЫВАЙ ТОЛЬКО ЭТИ ТЕКСТОВЫЕ ЭЛЕМЕНТЫ:
106710
- - HOOK (1–4 строки; выше всех элементов; самый крупный; CAPS; жирный; на яркой контрастной подложке; ключевое слово проблемы явно)
108546
+ - HOOK (1–4 строки; выше всех элементов; самый крупный; прописные буквы; жирный; на яркой контрастной подложке; ключевое слово проблемы явно)
106711
108547
  - 3 буллета (крупные, с иконками/галочками ✓, на контрастных подложках, НЕ на банке/упаковке)
106712
108548
  - Цена: ОБЯЗАТЕЛЬНО ДВЕ — старая (2×${generatePrice} ${generateCurrency}) зачёркнута ТОЛСТОЙ контрастной линией + новая ${generatePrice} ${generateCurrency} выразительно. Одна цена = ОШИБКА. Тонкая линия зачёркивания = ОШИБКА. Без слов. Не на упаковке.
106713
108549
  - Скидка: «-50%» ОБЯЗАТЕЛЬНО отдельным видимым бейджем (не только в цене!). Процент скидки должен быть явно читаем. Ярко, заметно, строго НЕ на банке/упаковке, визуально слабее CTA
@@ -106743,11 +108579,11 @@ ANTI-TEMPLATE DIVERSITY (КРИТИЧНО):
106743
108579
  * 🎯 ПОДХОД: Визуализация проблемы → Инфографика/схема: слева проблема (иконка/схема зоны тела, релевантной продукту), справа решение + продукт. HOOK сверху по центру, BULLETS справа или снизу (вертикально), CTA снизу справа, PRICE/DISCOUNT возле CTA. Trust‑печати (если есть) — компактно по низу, размер как минимум как у буллитов (крупные, читабельны на телефоне). Красный акцент только на проблеме.
106744
108580
  * 🎯 ПОДХОД: Power / Сила решения → БЕЗ человека. ДИНАМИЧНЫЙ комикс‑кадр, диагональная композиция. Продукт как “герой” + power‑иконки (щит/молния/бёрст). HOOK сверху слева на яркой плашке, BULLETS слева ниже, CTA снизу справа, PRICE/DISCOUNT возле CTA. Trust‑печати (если есть) — компактно по низу, размер как минимум как у буллитов (крупные, читабельны на телефоне).
106745
108581
  * 🎯 ПОДХОД: Минимализм / Clean Big Text → Белый/градиентный фон, минимум элементов. ОГРОМНЫЙ HOOK занимает верх/центр, продукт крупно (центр/право), CTA снизу по центру, PRICE/DISCOUNT рядом (слабее CTA). Trust‑печати (если есть) — размер как минимум как у буллитов, крупные и читабельные.
106746
- * 🎯 ПОДХОД: Problem Visual Punch → БЕЗ человека. Яркий сплошной фон (красный/оранжевый) или агрессивный градиент. В центре КРУПНАЯ иконка/схема зоны тела, релевантной продукту (для суставов — колено; для пищеварения — желудок), с красным свечением. Продукт крупно рядом. HOOK 1–4 строки, до 12 слов, огромный CAPS, выше всех. БЕЗ буллитов. PRICE + «-50%» крупно и заметно. CTA контрастной кнопкой
106747
- * 🎯 ПОДХОД: Любительский Примитивизм → БЕЗ человека. Чёрный или кислотный сплошной фон. Продукт по центру или справа без декора. HOOK сверху — 1–4 строки, до 12 слов, крупный, грубый bold/рукописный, CAPS, выше всех. Крупные надписи цены/скидки вокруг продукта. CTAплоская кнопка без градиентов. БЕЗ буллитов, бейджей, теней, иконок.
108582
+ * 🎯 ПОДХОД: Problem Visual Punch → БЕЗ человека. Яркий сплошной фон (красный/оранжевый) или агрессивный градиент. В центре КРУПНАЯ иконка/схема зоны тела, релевантной продукту (для суставов — колено; для пищеварения — желудок), с красным свечением. Продукт крупно рядом. HOOK 1–4 строки, до 12 слов, огромный прописной текст, выше всех. БЕЗ буллитов. Две цены + «-50%» крупно и заметно. Кнопка призыва контрастная (только текст на языке ${generateGeo}, без слова CTA)
108583
+ * 🎯 ПОДХОД: Любительский Примитивизм → БЕЗ человека. Чёрный или кислотный сплошной фон. Продукт по центру или справа без декора. HOOK сверху — 1–4 строки, до 12 слов, крупный, грубый bold/рукописный, прописные буквы, выше всех. Крупные надписи цены/скидки вокруг продукта. Кнопка призыва плоская, без градиентов (только короткая фраза на языке ${generateGeo}). БЕЗ буллитов, бейджей, теней, иконок.
106748
108584
 
106749
108585
  AUTO-CHECK (перед финалом):
106750
- - HOOK: 1–4 строки, до 12 слов, CAPS, жирный на контрастной плашке, выше всех элементов, ключевое слово проблемы явно, язык ${generateGeo} без английских слов
108586
+ - HOOK: 1–4 строки, до 12 слов, прописные буквы, жирный на контрастной плашке, выше всех элементов, ключевое слово проблемы явно, язык ${generateGeo} без английских слов (включая метки HOOK/CTA/CAPS)
106751
108587
  - Буллеты: по умолчанию ровно 3, каждый <= 4 слов, без запятых, не предложения. ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → буллетов 0 (запрещены)
106752
108588
  - Нет лишнего текста кроме: HOOK, буллетов, цены, скидки, кнопки (+ опционально 1 бейдж срочности + опционально 1–3 trust‑печати)
106753
108589
  - Есть скидка «-50%» (вне упаковки) и она слабее CTA
@@ -106791,37 +108627,37 @@ const CREO_APPROACHES = [
106791
108627
  {
106792
108628
  name: 'Эксперт / Авторитет',
106793
108629
  prompt: `ЭКСПЕРТ / АВТОРИТЕТ (без человека): стиль “рекомендация эксперта”, но БЕЗ человека. Профессиональный контекст — аптечные полки на фоне / медицинский планшет / стетоскоп / рецептурный блокнот как реквизит рядом с продуктом. Продукт в центре как “рекомендованное решение”. Чистый профессиональный фон, высокий контраст. Trust‑печати (1–3 шт): цветные, яркие, очень похожие на печать FDA; подчёркивают натуральность состава, премиальность, безопасность. Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная.`,
106794
- headlineAngle: `HOOK: угол «предупреждение / интрига / специалисты знают». Формат: вопрос‑предупреждение ИЛИ “специалисты знают/используют” (адаптируй под GEO). 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108630
+ headlineAngle: `HOOK: угол «предупреждение / интрига / специалисты знают». Формат: вопрос‑предупреждение ИЛИ “специалисты знают/используют” (адаптируй под GEO). 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106795
108631
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (действие + срок + соц.доказательство/формула) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор для этого подхода — не повторяй комбинации из других креативов.`
106796
108632
  },
106797
108633
  {
106798
108634
  name: 'Lifestyle / Момент приёма',
106799
108635
  prompt: `LIFESTYLE / МОМЕНТ ПРИЁМА: продукт в контексте использования (кухня/стол/спальня/тумбочка). Без человека, но с "историей" (стакан воды, чай, тарелка, будильник/часы/календарь). Срочность: реквизит (часы/таймер‑иконка) и/или опциональный urgency‑бейдж (1–3 слова) в углу кадра — только ясные формулировки («только сегодня», «последние штуки»), ЗАПРЕЩЕНО «24h». Высокий контраст, яркий акцент на продукте. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. ВАЖНО: буллиты располагаются вертикально и всегда читабельны на экране телефона без зума — даже если уходят вбок, минимальный размер шрифта буллитов не уменьшается. Если буллиты не вмещаются сбоку с нужным шрифтом — переставь их вниз.`,
106800
- headlineAngle: `HOOK: угол «цифры + срочность». Формат: число/процент + ограничение времени/“сейчас/сегодня” (адаптируй под GEO), 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108636
+ headlineAngle: `HOOK: угол «цифры + срочность». Формат: число/процент + ограничение времени/“сейчас/сегодня” (адаптируй под GEO), 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106801
108637
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (срок + цифра + действие/формула) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор — не повторяй комбинации из других креативов.`
106802
108638
  },
106803
108639
  {
106804
108640
  name: 'Эмоция / Портрет',
106805
108641
  prompt: `ЭМОЦИЯ / ПОРТРЕТ: один из двух подходов с человеком в серии. Используй максимально: ОЧЕНЬ крупный план лица (thumb‑stop), прямой взгляд в камеру, сильная эмоция облегчения/надежды (без широкой стоковой улыбки). Возраст человека подбери под категорию и ЦА продукта: по умолчанию 50–60, но для категорий с более молодой аудиторией (например похудение/фитнес) допускается 35–55. Продукт в руке на уровне лица или рядом, хорошо виден. Свет "тень → свет" на лице допустим. Минимум отвлекающих деталей, высокий контраст. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. ИЕРАРХИЯ: лицо — главный и доминирующий визуальный элемент (верхние 2/3 кадра). Все текстовые блоки (HOOK исключение — сверху) уходят в нижнюю треть. Буллиты, цена, CTA НЕ перекрывают лицо и НЕ конкурируют с ним по визуальному весу — они заметно меньше и ниже.`,
106806
- headlineAngle: `HOOK: угол «персонально на “ты” + результат/облегчение». 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно. Тон максимально личный и прямой.`,
108642
+ headlineAngle: `HOOK: угол «персонально на “ты” + результат/облегчение». 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно. Тон максимально личный и прямой.`,
106807
108643
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (качество жизни + действие + срок/цифра) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор — не повторяй комбинации из других креативов.`
106808
108644
  },
106809
108645
  {
106810
108646
  name: 'Визуализация проблемы',
106811
108647
  prompt: `ВИЗУАЛИЗАЦИЯ ПРОБЛЕМЫ (без человека): схема/иконка проблемной зоны тела, строго соответствующей категории продукта (для суставов — колено/сустав/позвоночник; для пищеварения — желудок; для простаты — силуэт мужчины) + мягкий красный акцент на этой зоне (не шок‑контент, без графики). Рядом продукт как решение. Можно добавить простую стрелку/переход “проблема → облегчение” как графику (без лишнего текста). Чистый фон, высокая читабельность. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. БЕЗ человека.`,
106812
- headlineAngle: `HOOK: прямой вопрос о боли/дискомфорте (релевантно категории). 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно, вопросительный знак допустим.`,
108648
+ headlineAngle: `HOOK: прямой вопрос о боли/дискомфорте (релевантно категории). 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно, вопросительный знак допустим.`,
106813
108649
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (действие + срок + соц.доказательство) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор — не повторяй комбинации из других креативов.`
106814
108650
  },
106815
108651
  {
106816
108652
  name: 'Power / Сила решения',
106817
108653
  prompt: `POWER / СИЛА РЕШЕНИЯ (без человека): метафоры силы и победы над проблемой: щит, молния, энергия, взрыв‑бёрст, мощные стикеры/иконки. Продукт как “герой” в центре, высокая энергия, контрастные агрессивные цвета. Можно комикс/anti‑design подачу, но всё должно быть читабельно. Без лишнего текста. Опционально: 1–3 trust‑печати по низу (цветные, яркие, очень похожие на печать FDA; натуральность/премиальность/безопасность). Размер как минимум как у буллитов — крупные, читабельны на телефоне. Даже одна печать — крупная. БЕЗ человека. Только продукт + power‑иконки.`,
106818
- headlineAngle: `HOOK: угол «было → стало / победа над проблемой». Можно использовать стрелку “→” как часть перехода. 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108654
+ headlineAngle: `HOOK: угол «было → стало / победа над проблемой». Можно использовать стрелку “→” как часть перехода. 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106819
108655
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (действие + скорость + цифра) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор — не повторяй комбинации из других креативов.`
106820
108656
  },
106821
108657
  {
106822
108658
  name: 'Минимализм / Clean Big Text',
106823
- prompt: `МИНИМАЛИЗМ / CLEAN BIG TEXT (без человека): белый или мягкий градиентный фон, премиальное ощущение. ОГРОМНЫЙ HOOK как главный элемент (CAPS, жирный, на контрастной плашке). Продукт крупно, минимум реквизита, минимум шума. Тени/премиальные материалы допустимы, но без лишнего текста. БЕЗ человека. Urgency и trust‑печати в этом подходе НЕ рекомендуются — они нарушают чистоту и ощущение премиальности. Добавляй печати только если это критически необходимо, не более 1, но крупную — размер как у буллитов.`,
106824
- headlineAngle: `HOOK: одна максимально простая сильная фраза (коротко и ясно), 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108659
+ prompt: `МИНИМАЛИЗМ / CLEAN BIG TEXT (без человека): белый или мягкий градиентный фон, премиальное ощущение. ОГРОМНЫЙ HOOK как главный элемент (прописные буквы, жирный, на контрастной плашке). Продукт крупно, минимум реквизита, минимум шума. Тени/премиальные материалы допустимы, но без лишнего текста. БЕЗ человека. Urgency и trust‑печати в этом подходе НЕ рекомендуются — они нарушают чистоту и ощущение премиальности. Добавляй печати только если это критически необходимо, не более 1, но крупную — размер как у буллитов.`,
108660
+ headlineAngle: `HOOK: одна максимально простая сильная фраза (коротко и ясно), 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106825
108661
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (действие + срок + формула/цифра) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор — не повторяй комбинации из других креативов.`
106826
108662
  },
106827
108663
  {
@@ -106831,14 +108667,14 @@ const CREO_APPROACHES = [
106831
108667
  - Фон: яркий сплошной цвет (красный/оранжевый) или агрессивный градиент
106832
108668
  - Центр: КРУПНАЯ иконка/схема проблемной зоны тела, строго соответствующей категории продукта (для суставов — колено/сустав; для простаты — силуэт мужчины; для пищеварения — желудок), с красным свечением
106833
108669
  - Продукт: крупно рядом
106834
- - HOOK: 1–4 строки, до 12 слов, огромный, CAPS, ключевое слово проблемы явно
108670
+ - HOOK: 1–4 строки, до 12 слов, огромный, прописные буквы, ключевое слово проблемы явно
106835
108671
  - БЕЗ буллитов
106836
108672
  - Цена + скидка: крупно, заметно
106837
108673
  - CTA: контрастная яркая кнопка
106838
108674
 
106839
108675
  Цель: считывание за 1 секунду. Минимум текста, максимум визуального удара.
106840
108676
  БЕЗ человека. Никаких trust‑печатей/urgency бейджей — только HOOK + PRICE + -50% + CTA.`,
106841
- headlineAngle: `HOOK: «ПРОЩАЙ/КОНЕЦ/СТОП + [проблема]!». Эмоция победы/избавления. 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108677
+ headlineAngle: `HOOK: «ПРОЩАЙ/КОНЕЦ/СТОП + [проблема]!». Эмоция победы/избавления. 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106842
108678
  bulletsFocus: `БУЛЛИТЫ: ЗАПРЕЩЕНЫ. Вся информация — в HOOK и крупных надписях.`
106843
108679
  },
106844
108680
  {
@@ -106853,7 +108689,7 @@ const CREO_APPROACHES = [
106853
108689
  - Крупные текстовые надписи рядом с продуктом: цена, скидка; допустимо одно короткое слово-восклицание («РАБОТАЕТ!», «ПРОВЕРЕНО!») на языке GEO
106854
108690
  - Кнопка CTA: плоская, без градиентов, контрастный сплошной цвет
106855
108691
  - НИКАКИХ буллитов, trust‑печатей, urgency‑бейджей, иконок — только продукт и текст`,
106856
- headlineAngle: `HOOK: максимально прямолинейный — короткий, грубый, без украшений. 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно, как объявление на столбе. Никакого маркетингового лоска, никаких абстрактных слоганов.`,
108692
+ headlineAngle: `HOOK: максимально прямолинейный — короткий, грубый, без украшений. 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно, как объявление на столбе. Никакого маркетингового лоска, никаких абстрактных слоганов.`,
106857
108693
  bulletsFocus: `БУЛЛИТЫ: ЗАПРЕЩЕНЫ. Всё — в HOOK и крупных надписях вокруг продукта (цена, скидка, одно слово-восклицание).`
106858
108694
  },
106859
108695
  {
@@ -106865,7 +108701,7 @@ const CREO_APPROACHES = [
106865
108701
  - Фон: профессиональный (кабинет, аптечные полки, медицинский контекст). Высокий контраст, читабельность.
106866
108702
  - Опционально: 1–3 trust‑печати по низу (цветные, яркие, в стиле FDA). Размер как минимум как у буллитов.
106867
108703
  - ИЕРАРХИЯ: врач + продукт — главные элементы. HOOK сверху, BULLETS сбоку или снизу, CTA и PRICE/DISCOUNT в нижнем блоке.`,
106868
- headlineAngle: `HOOK: угол «врач/специалист рекомендует» или «эксперты знают». 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108704
+ headlineAngle: `HOOK: угол «врач/специалист рекомендует» или «эксперты знают». 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106869
108705
  bulletsFocus: `БУЛЛИТЫ: выбери 3 СЛУЧАЙНЫХ из пула (действие + срок + соц.доказательство) в ПРОИЗВОЛЬНОМ порядке. Уникальный набор — не повторяй комбинации из других креативов.`
106870
108706
  },
106871
108707
  {
@@ -106874,11 +108710,11 @@ const CREO_APPROACHES = [
106874
108710
  prompt: `СКРИН ОТЗЫВОВ: имитация реалистичного скриншота с положительными благодарными отзывами и оценками 5 звёзд.
106875
108711
  - Визуал: реалистичный стиль — как скриншот приложения/сайта отзывов (App Store, Google Play, или страница отзывов). Высокое качество, читабельный текст.
106876
108712
  - Отзывы: 2–4 отзыва с аватарками, именами и возрастом (формат «Имя, 45 лет»), ОБЯЗАТЕЛЬНО 5 звёзд (★★★★★) в каждом, короткий текст благодарности. Текст отзывов СТРОГО на языке GEO — никакого английского. Релевантен категории продукта.
106877
- - HOOK ОБЯЗАТЕЛЕН: крупно, выше блока отзывов или поверх, CAPS, на яркой подложке. Ключевое слово проблемы явно.
108713
+ - HOOK ОБЯЗАТЕЛЕН: крупно, выше блока отзывов или поверх, прописные буквы, на яркой подложке. Ключевое слово проблемы явно.
106878
108714
  - Продукт: виден в кадре (рядом со скрином или интегрирован в композицию).
106879
108715
  - Цена, скидка «-50%», CTA — в нижней части. БЕЗ буллитов — отзывы заменяют их.
106880
108716
  - Стиль: не мультяшный, не комикс — максимально реалистичный скрин.`,
106881
- headlineAngle: `HOOK: угол «тысячи довольны» / «9 из 10 рекомендуют» / «реальный результат». 1–4 строки, до 12 слов, CAPS, ключевое слово проблемы явно.`,
108717
+ headlineAngle: `HOOK: угол «тысячи довольны» / «9 из 10 рекомендуют» / «реальный результат». 1–4 строки, до 12 слов, прописные буквы, ключевое слово проблемы явно.`,
106882
108718
  bulletsFocus: `БУЛЛИТЫ: ЗАПРЕЩЕНЫ. Вся информация — в HOOK, отзывах (с 5 звёздами), цене и CTA.`
106883
108719
  }
106884
108720
  ];