docs-combiner 0.1.14 → 0.1.16

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
@@ -3056,29 +3056,6 @@ __webpack_require__.r(__webpack_exports__);
3056
3056
 
3057
3057
  /***/ }),
3058
3058
 
3059
- /***/ "./node_modules/@mui/icons-material/esm/InfoOutlined.js":
3060
- /*!**************************************************************!*\
3061
- !*** ./node_modules/@mui/icons-material/esm/InfoOutlined.js ***!
3062
- \**************************************************************/
3063
- /***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
3064
-
3065
- "use strict";
3066
- __webpack_require__.r(__webpack_exports__);
3067
- /* harmony export */ __webpack_require__.d(__webpack_exports__, {
3068
- /* harmony export */ "default": () => (__WEBPACK_DEFAULT_EXPORT__)
3069
- /* harmony export */ });
3070
- /* harmony import */ var _utils_createSvgIcon_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utils/createSvgIcon.js */ "./node_modules/@mui/material/esm/utils/createSvgIcon.js");
3071
- /* harmony import */ var react_jsx_runtime__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react/jsx-runtime */ "./node_modules/react/jsx-runtime.js");
3072
- "use client";
3073
-
3074
-
3075
-
3076
- /* 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", {
3077
- d: "M11 7h2v2h-2zm0 4h2v6h-2zm1-9C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2m0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8"
3078
- }), 'InfoOutlined'));
3079
-
3080
- /***/ }),
3081
-
3082
3059
  /***/ "./node_modules/@mui/icons-material/esm/KeyboardArrowDown.js":
3083
3060
  /*!*******************************************************************!*\
3084
3061
  !*** ./node_modules/@mui/icons-material/esm/KeyboardArrowDown.js ***!
@@ -100879,50 +100856,53 @@ __webpack_require__.r(__webpack_exports__);
100879
100856
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Card/Card.js");
100880
100857
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CardContent/CardContent.js");
100881
100858
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Stack/Stack.js");
100882
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Accordion/Accordion.js");
100883
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionSummary/AccordionSummary.js");
100884
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionDetails/AccordionDetails.js");
100885
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/TextField/TextField.js");
100859
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/TextField/TextField.js");
100860
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormHelperText/FormHelperText.js");
100861
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CircularProgress/CircularProgress.js");
100862
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Alert/Alert.js");
100886
100863
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Divider/Divider.js");
100887
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Button/Button.js");
100888
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/CircularProgress/CircularProgress.js");
100889
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormHelperText/FormHelperText.js");
100890
- /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Alert/Alert.js");
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");
100864
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Accordion/Accordion.js");
100865
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionSummary/AccordionSummary.js");
100866
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/AccordionDetails/AccordionDetails.js");
100867
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Button/Button.js");
100868
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControlLabel/FormControlLabel.js");
100869
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Checkbox/Checkbox.js");
100870
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputAdornment/InputAdornment.js");
100871
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Tooltip/Tooltip.js");
100872
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_25__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/FormControl/FormControl.js");
100873
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_26__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/InputLabel/InputLabel.js");
100874
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_27__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Select/Select.js");
100875
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_28__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/MenuItem/MenuItem.js");
100899
100876
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_29__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButtonGroup/ToggleButtonGroup.js");
100900
100877
  /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_30__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/ToggleButton/ToggleButton.js");
100901
100878
  /* 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__);
100879
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_32__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/Dialog/Dialog.js");
100880
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_33__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogTitle/DialogTitle.js");
100881
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_34__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogContent/DialogContent.js");
100882
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_35__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/DialogActions/DialogActions.js");
100883
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_36__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/createTheme.js");
100884
+ /* harmony import */ var _mui_material__WEBPACK_IMPORTED_MODULE_37__ = __webpack_require__(/*! @mui/material */ "./node_modules/@mui/material/esm/styles/ThemeProvider.js");
100885
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_38__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AccountBalance.js");
100886
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_39__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AttachMoney.js");
100887
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_40__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/AutoAwesome.js");
100888
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness4.js");
100889
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Brightness7.js");
100890
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CheckCircle.js");
100891
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/CloudDownload.js");
100892
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_45__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ContentCopy.js");
100893
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_46__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/DeleteOutline.js");
100894
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_47__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/ExpandMore.js");
100895
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_48__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Login.js");
100896
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_49__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Logout.js");
100897
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_50__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/NoteAdd.js");
100898
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_51__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Replay.js");
100899
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_52__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Settings.js");
100900
+ /* harmony import */ var _mui_icons_material__WEBPACK_IMPORTED_MODULE_53__ = __webpack_require__(/*! @mui/icons-material */ "./node_modules/@mui/icons-material/esm/Visibility.js");
100901
+ /* harmony import */ var _PromptManagerDialog__WEBPACK_IMPORTED_MODULE_54__ = __webpack_require__(/*! ./PromptManagerDialog */ "./src/PromptManagerDialog.tsx");
100902
+ /* harmony import */ var _promptOverrides__WEBPACK_IMPORTED_MODULE_55__ = __webpack_require__(/*! ./promptOverrides */ "./src/promptOverrides.ts");
100903
+ /* harmony import */ var xlsx__WEBPACK_IMPORTED_MODULE_56__ = __webpack_require__(/*! xlsx */ "./node_modules/xlsx/xlsx.mjs");
100904
+ /* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_57__ = __webpack_require__(/*! jszip */ "./node_modules/jszip/dist/jszip.min.js");
100905
+ /* harmony import */ var jszip__WEBPACK_IMPORTED_MODULE_57___default = /*#__PURE__*/__webpack_require__.n(jszip__WEBPACK_IMPORTED_MODULE_57__);
100926
100906
 
100927
100907
 
100928
100908
 
@@ -100983,15 +100963,65 @@ const INSTRUCTION_ROW = [
100983
100963
  "# Обязательно | 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.",
100984
100964
  "# Обязательно | Фирменное название товара. Не более 100 символов."
100985
100965
  ];
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) {
100966
+ /** Доп. query-параметры для ссылки каталога (RedTrack / utm / макросы Meta; не URL-encode — подстановка на стороне FB). */
100967
+ const DEFAULT_CATALOG_LINK_EXTRA_MACROS = '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';
100968
+ const DEFAULT_CATALOG_LINK_KEITARO_MACROS = 'utm_campaign={{campaign.name}}&utm_source={{site_source_name}}&utm_placement={{placement}}&campaign_id={{campaign.id}}&adset_id={{adset.id}}&ad_id={{ad.id}}&adset_name={{adset.name}}&ad_name={{ad.name}}';
100969
+ /** 8 случайных hex-символов для уникального суффикса имени файла на Drive. */
100970
+ function randomHex8() {
100971
+ const a = new Uint8Array(4);
100972
+ crypto.getRandomValues(a);
100973
+ return Array.from(a, b => b.toString(16).padStart(2, '0')).join('');
100974
+ }
100975
+ /** Имя файла при загрузке крео: N_xxxxxxxx.png — N = номер строки подхода в UI (1–10). */
100976
+ function creativeImageUploadFilename(creoApproachUiNumber) {
100977
+ return `${creoApproachUiNumber}_${randomHex8()}.png`;
100978
+ }
100979
+ /**
100980
+ * Из имени файла картинки на Drive — номер строки подхода к крео (1–10) для каталога/трекера.
100981
+ * Формат: N_xxxxxxxx; снимаются расширение, суффиксы « (N)» от дубликатов Google.
100982
+ * Старый формат (текст_hex8) — возвращается «лейбл» после снятия hex (не только цифры).
100983
+ */
100984
+ function parseCreoApproachLabelFromImageFileName(fileName) {
100985
+ let s = fileName.replace(/\.[^/.]+$/i, '').trim();
100986
+ if (!s)
100987
+ return undefined;
100988
+ while (/\s+\(\d+\)$/.test(s)) {
100989
+ s = s.replace(/\s+\(\d+\)$/, '').trim();
100990
+ }
100991
+ const m = /^(\d+)_([0-9a-fA-F]{8})$/i.exec(s);
100992
+ if (m)
100993
+ return m[1];
100994
+ const legacy = s.replace(/_[0-9a-fA-F]{8}$/i, '').trim();
100995
+ return legacy || undefined;
100996
+ }
100997
+ const DEFAULT_CATALOG_TEXT_APPROACH_PARAM = 'sub19';
100998
+ const DEFAULT_CATALOG_CREO_APPROACH_PARAM = 'sub20';
100999
+ /** Имя query-параметра для трекера: латиница, цифры, _, - */
101000
+ function sanitizeCatalogUrlParamKey(raw, fallback) {
101001
+ const t = raw.trim();
101002
+ if (!t)
101003
+ return fallback;
101004
+ const cleaned = t.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 64);
101005
+ return cleaned || fallback;
101006
+ }
101007
+ /** Добавляет к URL лендинга creative_id, опционально кастомные параметры подходов (имена редактируются в UI) и строку доп. макросов. */
101008
+ function appendCreativeIdToCatalogLink(baseUrl, creativeId, catalogAnalytics, extraMacrosQueryString) {
100990
101009
  const u = baseUrl.trim();
100991
101010
  if (!u)
100992
101011
  return u;
100993
101012
  const sep = u.includes('?') ? '&' : '?';
100994
- return `${u}${sep}creative_id=${encodeURIComponent(creativeId)}&${CATALOG_LINK_TRACKING_SUFFIX}`;
101013
+ const q = [`creative_id=${encodeURIComponent(creativeId)}`];
101014
+ const textKey = sanitizeCatalogUrlParamKey(catalogAnalytics?.textParamKey ?? '', DEFAULT_CATALOG_TEXT_APPROACH_PARAM);
101015
+ const creoKey = sanitizeCatalogUrlParamKey(catalogAnalytics?.creoParamKey ?? '', DEFAULT_CATALOG_CREO_APPROACH_PARAM);
101016
+ if (catalogAnalytics?.textApproach) {
101017
+ q.push(`${textKey}=${encodeURIComponent(catalogAnalytics.textApproach)}`);
101018
+ }
101019
+ if (catalogAnalytics?.creoApproach) {
101020
+ q.push(`${creoKey}=${encodeURIComponent(catalogAnalytics.creoApproach)}`);
101021
+ }
101022
+ const core = `${u}${sep}${q.join('&')}`;
101023
+ const tail = (extraMacrosQueryString ?? '').trim();
101024
+ return tail ? `${core}&${tail}` : core;
100995
101025
  }
100996
101026
  /** Текст ответа из OpenRouter/OpenAI chat completion (string или массив частей). */
100997
101027
  function extractChatCompletionText(choice) {
@@ -101160,6 +101190,82 @@ function extractLeadingPriceNumber(value) {
101160
101190
  return m[1].replace(',', '.');
101161
101191
  return '99';
101162
101192
  }
101193
+ /** Фон карточки крео: после 1-й переделки — светло-жёлтый, далее темнеет с каждой следующей. */
101194
+ function getRemakeHighlightBackground(remakeCount, dark) {
101195
+ if (remakeCount <= 0)
101196
+ return undefined;
101197
+ const step = Math.min(remakeCount - 1, 7);
101198
+ if (dark) {
101199
+ const opacities = [0.11, 0.16, 0.22, 0.28, 0.34, 0.42, 0.5, 0.58];
101200
+ return `rgba(255, 193, 7, ${opacities[step]})`;
101201
+ }
101202
+ const light = ['#fffde7', '#fff9c4', '#fff59d', '#ffee58', '#ffeb3b', '#fdd835', '#fbc02d', '#f9a825'];
101203
+ return light[step];
101204
+ }
101205
+ function sortedPairIndicesEqual(a, b) {
101206
+ const sa = [...a].sort((x, y) => x - y);
101207
+ const sb = [...b].sort((x, y) => x - y);
101208
+ if (sa.length !== sb.length)
101209
+ return false;
101210
+ return sa.every((v, i) => v === sb[i]);
101211
+ }
101212
+ function imageApproachCountsEqual(a, b) {
101213
+ if (a.length !== b.length)
101214
+ return false;
101215
+ return a.every((v, i) => v === b[i]);
101216
+ }
101217
+ function formatPairApproachesForDisplay(indices) {
101218
+ return [...indices]
101219
+ .sort((x, y) => x - y)
101220
+ .map(i => {
101221
+ const p = _prompts__WEBPACK_IMPORTED_MODULE_1__.PAIR_APPROACH_POOL[i];
101222
+ const label = p?.name ?? '?';
101223
+ return `${i + 1}. ${label}`;
101224
+ })
101225
+ .join('\n');
101226
+ }
101227
+ function formatImageCountsForDisplay(counts) {
101228
+ const lines = counts
101229
+ .map((c, i) => (c > 0 ? `${_prompts__WEBPACK_IMPORTED_MODULE_1__.CREO_APPROACHES[i]?.name ?? `№${i + 1}`}: ×${c}` : null))
101230
+ .filter((x) => x != null);
101231
+ return lines.length > 0 ? lines.join('\n') : 'ни один подход (все 0)';
101232
+ }
101233
+ /** Один раз прошли экран «Application Error» — больше не показывать (localStorage + Electron config). */
101234
+ const SECRET_UNLOCK_STORAGE_KEY = 'docs_combiner_secret_unlocked';
101235
+ async function fetchDriveFilePermissions(token, fileId) {
101236
+ const permissionsUrl = `https://www.googleapis.com/drive/v3/files/${fileId}?fields=permissions(id,type,role)&supportsAllDrives=true`;
101237
+ const permissionsResponse = await fetch(permissionsUrl, {
101238
+ headers: { Authorization: `Bearer ${token}` }
101239
+ });
101240
+ if (!permissionsResponse.ok) {
101241
+ return { ok: false, errorText: await permissionsResponse.text() };
101242
+ }
101243
+ const permissionsData = await permissionsResponse.json();
101244
+ return { ok: true, permissions: permissionsData.permissions || [] };
101245
+ }
101246
+ /** Доступ «любой по ссылке» / публичный читатель — нужен для скачивания референса по URL без OAuth. */
101247
+ function permissionsIncludeAnyoneLink(permissions) {
101248
+ return permissions.some(p => p.type === 'anyone');
101249
+ }
101250
+ async function verifyOfferFolderHasAnyoneLinkForImageGen(token, folderId) {
101251
+ const offerPermResult = await fetchDriveFilePermissions(token, folderId);
101252
+ if (!offerPermResult.ok) {
101253
+ return {
101254
+ ok: false,
101255
+ message: 'Не удалось проверить доступ к папке оффера в Google Диске.\n\n' +
101256
+ 'Генерация изображений с референсом может не работать без доступа по ссылке.\n\n' +
101257
+ (offerPermResult.errorText.trim().slice(0, 280) || 'Ошибка API')
101258
+ };
101259
+ }
101260
+ if (!permissionsIncludeAnyoneLink(offerPermResult.permissions)) {
101261
+ return {
101262
+ ok: false,
101263
+ message: 'Папка оффера закрыта для доступа по ссылке: нет права «Все, у кого есть ссылка» (тип anyone).\n\n' +
101264
+ 'Сервисы генерации скачивают product.png по публичному URL. Включите в Google Диске общий доступ с ролью «Читатель» для этой папки (или согласитесь, когда приложение предложит сделать это автоматически).'
101265
+ };
101266
+ }
101267
+ return { ok: true };
101268
+ }
101163
101269
  function App() {
101164
101270
  const [clientId, setClientId] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
101165
101271
  const [clientSecret, setClientSecret] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
@@ -101174,8 +101280,12 @@ function App() {
101174
101280
  // Переводы сгенерированных пар на русский: ключ = 0-based индекс пары
101175
101281
  const [pairTranslations, setPairTranslations] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)({});
101176
101282
  const [translatingPairs, setTranslatingPairs] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101283
+ /** Папка оффера: загрузка/сохранение контента и крео (как раньше) */
101177
101284
  const [driveFolderUrl, setDriveFolderUrl] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
101285
+ /** Корневая папка: только поле + проверка общего доступа и подпапки OFFERS (отдельно от папки оффера) */
101286
+ const [rootDriveFolderUrl, setRootDriveFolderUrl] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
101178
101287
  const [link, setLink] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
101288
+ const linkInputRef = (0,react__WEBPACK_IMPORTED_MODULE_0__.useRef)(null);
101179
101289
  const [openaiApiKey, setOpenaiApiKey] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
101180
101290
  const [openRouterBalance, setOpenRouterBalance] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
101181
101291
  const [openRouterAccountBalance, setOpenRouterAccountBalance] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
@@ -101378,10 +101488,17 @@ function App() {
101378
101488
  const [uploadingImages, setUploadingImages] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101379
101489
  const [uploadingProduct, setUploadingProduct] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101380
101490
  const [folderFilesInfo, setFolderFilesInfo] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
101491
+ const [rootFolderInfo, setRootFolderInfo] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
101381
101492
  const productFileInputRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(null);
101382
101493
  const [checkingFolderFiles, setCheckingFolderFiles] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101494
+ const [checkingRootFolder, setCheckingRootFolder] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101495
+ const [drivePublicAccessWarning, setDrivePublicAccessWarning] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101496
+ /** Уже обработали запрос доступа по ссылке для корневой папки (OFFERS) */
101383
101497
  const permissionCheckedFoldersRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(new Set());
101498
+ /** Уже спрашивали про доступ по ссылке для папки оффера (нужен OpenRouter по uc?export=view) */
101499
+ const driveFolderPublicLinkPromptedRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(new Set());
101384
101500
  const folderCheckRunningRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(false);
101501
+ const rootFolderCheckRunningRef = react__WEBPACK_IMPORTED_MODULE_0___default().useRef(false);
101385
101502
  const [imagesProcessStartTime, setImagesProcessStartTime] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
101386
101503
  const [contentProcessStartTime, setContentProcessStartTime] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
101387
101504
  const [contentGenerationLogs, setContentGenerationLogs] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
@@ -101396,6 +101513,16 @@ function App() {
101396
101513
  // const [availability, setAvailability] = useState('in stock');
101397
101514
  // const [condition, setCondition] = useState('new');
101398
101515
  const [linkError, setLinkError] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)('');
101516
+ /** В ссылку каталога: имя подхода к паре текстов (под трекер) */
101517
+ const [catalogUrlIncludeTextApproach, setCatalogUrlIncludeTextApproach] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101518
+ /** В ссылку каталога: подход крео — если крео загружены из приложения (есть file id на Drive) */
101519
+ const [catalogUrlIncludeCreoApproach, setCatalogUrlIncludeCreoApproach] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101520
+ /** Имя query-параметра для подхода к тексту (по умолчанию sub19) */
101521
+ const [catalogUrlTextApproachParam, setCatalogUrlTextApproachParam] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(DEFAULT_CATALOG_TEXT_APPROACH_PARAM);
101522
+ /** Имя query-параметра для подхода к крео (по умолчанию sub20) */
101523
+ const [catalogUrlCreoApproachParam, setCatalogUrlCreoApproachParam] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(DEFAULT_CATALOG_CREO_APPROACH_PARAM);
101524
+ /** Query-хвост после creative_id / sub19 / sub20 (редактируемый; пресет RedTrack). */
101525
+ const [catalogLinkExtraMacros, setCatalogLinkExtraMacros] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
101399
101526
  const [loading, setLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101400
101527
  const [authLoading, setAuthLoading] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101401
101528
  const [generatedData, setGeneratedData] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
@@ -101412,9 +101539,36 @@ function App() {
101412
101539
  const saved = localStorage.getItem('themeMode');
101413
101540
  return saved === 'dark';
101414
101541
  });
101415
- // Secret unlock state - always start locked
101416
- const [unlocked, setUnlocked] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101542
+ // Secret unlock state восстанавливаем из localStorage; при старте Electron подмешивает config.secretUnlockPassed
101543
+ const [unlocked, setUnlocked] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(() => {
101544
+ try {
101545
+ return localStorage.getItem(SECRET_UNLOCK_STORAGE_KEY) === '1';
101546
+ }
101547
+ catch {
101548
+ return false;
101549
+ }
101550
+ });
101417
101551
  const [clickSequence, setClickSequence] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)([]);
101552
+ const persistSecretUnlockPassed = () => {
101553
+ try {
101554
+ localStorage.setItem(SECRET_UNLOCK_STORAGE_KEY, '1');
101555
+ }
101556
+ catch {
101557
+ // ignore
101558
+ }
101559
+ void (async () => {
101560
+ try {
101561
+ const api = getElectronAPI();
101562
+ if (api) {
101563
+ const current = await api.loadConfig();
101564
+ await api.saveConfig({ ...current, secretUnlockPassed: true });
101565
+ }
101566
+ }
101567
+ catch {
101568
+ // ignore
101569
+ }
101570
+ })();
101571
+ };
101418
101572
  // Handle secret unlock clicks - simplified to left then right
101419
101573
  const handleSecretClick = (e) => {
101420
101574
  if (unlocked)
@@ -101439,6 +101593,7 @@ function App() {
101439
101593
  // Second click: right side (after left)
101440
101594
  setUnlocked(true);
101441
101595
  setClickSequence([]);
101596
+ persistSecretUnlockPassed();
101442
101597
  }
101443
101598
  else {
101444
101599
  // Wrong click or wrong sequence, reset
@@ -101453,7 +101608,7 @@ function App() {
101453
101608
  }
101454
101609
  };
101455
101610
  // Create theme based on mode
101456
- const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"])({
101611
+ const theme = react__WEBPACK_IMPORTED_MODULE_0___default().useMemo(() => (0,_mui_material__WEBPACK_IMPORTED_MODULE_36__["default"])({
101457
101612
  palette: {
101458
101613
  mode: darkMode ? 'dark' : 'light',
101459
101614
  ...(darkMode
@@ -101508,6 +101663,8 @@ function App() {
101508
101663
  applyThemeStyles(darkMode);
101509
101664
  }, [darkMode]);
101510
101665
  const [promptManagerOpen, setPromptManagerOpen] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
101666
+ /** После загрузки project-settings.json: спросить, подставить подходы из файла или оставить локальные. */
101667
+ const [approachLoadChoice, setApproachLoadChoice] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
101511
101668
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101512
101669
  // Load config on mount
101513
101670
  const loadKey = async () => {
@@ -101528,6 +101685,15 @@ function App() {
101528
101685
  setOpenaiApiKey(config.openaiApiKey);
101529
101686
  // Balance will be fetched automatically by useEffect when openaiApiKey changes
101530
101687
  }
101688
+ if (config.secretUnlockPassed === true) {
101689
+ setUnlocked(true);
101690
+ try {
101691
+ localStorage.setItem(SECRET_UNLOCK_STORAGE_KEY, '1');
101692
+ }
101693
+ catch {
101694
+ // ignore
101695
+ }
101696
+ }
101531
101697
  }
101532
101698
  catch (err) {
101533
101699
  // Silent fail
@@ -101536,8 +101702,11 @@ function App() {
101536
101702
  // effect (which depends on [driveFolderUrl]) will have valid tokens available
101537
101703
  try {
101538
101704
  const cachedDriveFolderUrl = localStorage.getItem('cached_driveFolderUrl');
101705
+ const cachedRootDriveFolderUrl = localStorage.getItem('cached_rootDriveFolderUrl');
101539
101706
  if (cachedDriveFolderUrl)
101540
101707
  setDriveFolderUrl(cachedDriveFolderUrl);
101708
+ if (cachedRootDriveFolderUrl)
101709
+ setRootDriveFolderUrl(cachedRootDriveFolderUrl);
101541
101710
  }
101542
101711
  catch (err) {
101543
101712
  // Silent fail
@@ -101545,7 +101714,7 @@ function App() {
101545
101714
  };
101546
101715
  loadKey();
101547
101716
  // Load prompt overrides from Electron config
101548
- (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.loadOverridesFromElectron)();
101717
+ (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.loadOverridesFromElectron)();
101549
101718
  }, []);
101550
101719
  // Save form fields to localStorage whenever they change
101551
101720
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
@@ -101558,6 +101727,22 @@ function App() {
101558
101727
  // Silent fail
101559
101728
  }
101560
101729
  }, [driveFolderUrl]);
101730
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101731
+ try {
101732
+ if (rootDriveFolderUrl) {
101733
+ localStorage.setItem('cached_rootDriveFolderUrl', rootDriveFolderUrl);
101734
+ }
101735
+ else {
101736
+ localStorage.removeItem('cached_rootDriveFolderUrl');
101737
+ }
101738
+ }
101739
+ catch (err) {
101740
+ // Silent fail
101741
+ }
101742
+ }, [rootDriveFolderUrl]);
101743
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101744
+ setDrivePublicAccessWarning(false);
101745
+ }, [rootDriveFolderUrl]);
101561
101746
  // Auto-save AI Generation Settings, brand and link to Google Drive when they change
101562
101747
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101563
101748
  if (!driveFolderUrl)
@@ -101587,7 +101772,21 @@ function App() {
101587
101772
  }
101588
101773
  }, 1000);
101589
101774
  return () => clearTimeout(timeoutId);
101590
- }, [generateProduct, generateGeo, generateAdditionalInfo, generatePriceWithCurrency, brand, link, driveFolderUrl, loadingContentFromDrive]);
101775
+ }, [
101776
+ generateProduct,
101777
+ generateGeo,
101778
+ generateAdditionalInfo,
101779
+ generatePriceWithCurrency,
101780
+ brand,
101781
+ link,
101782
+ catalogUrlIncludeTextApproach,
101783
+ catalogUrlIncludeCreoApproach,
101784
+ catalogUrlTextApproachParam,
101785
+ catalogUrlCreoApproachParam,
101786
+ catalogLinkExtraMacros,
101787
+ driveFolderUrl,
101788
+ loadingContentFromDrive
101789
+ ]);
101591
101790
  // Load generated content from Google Drive when driveFolderUrl changes
101592
101791
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101593
101792
  if (!driveFolderUrl) {
@@ -101602,7 +101801,9 @@ function App() {
101602
101801
  setTexts(['']);
101603
101802
  setLink('');
101604
101803
  setUploadedLink('');
101804
+ setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
101605
101805
  setPairTranslations({});
101806
+ setApproachLoadChoice(null);
101606
101807
  return;
101607
101808
  }
101608
101809
  const folderId = extractFolderId(driveFolderUrl);
@@ -101618,7 +101819,9 @@ function App() {
101618
101819
  setTexts(['']);
101619
101820
  setLink('');
101620
101821
  setUploadedLink('');
101822
+ setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
101621
101823
  setPairTranslations({});
101824
+ setApproachLoadChoice(null);
101622
101825
  return;
101623
101826
  }
101624
101827
  logToTerminal('log', '[Load] driveFolderUrl changed, clearing old data and loading from folderId:', folderId);
@@ -101630,7 +101833,9 @@ function App() {
101630
101833
  setTexts(['']);
101631
101834
  setLink('');
101632
101835
  setUploadedLink('');
101836
+ setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
101633
101837
  setPairTranslations({});
101838
+ setApproachLoadChoice(null);
101634
101839
  setLoadingContentFromDrive(true);
101635
101840
  setDriveFilesFound({ content: false });
101636
101841
  // Load content from Google Drive
@@ -101787,11 +101992,132 @@ function App() {
101787
101992
  fetchValidationModels();
101788
101993
  // eslint-disable-next-line react-hooks/exhaustive-deps
101789
101994
  }, [openaiApiKey]);
101790
- // Check folder files when driveFolderUrl changes
101995
+ // Корневая папка: общий доступ и подпапка OFFERS
101996
+ (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101997
+ let cancelled = false;
101998
+ const checkRootFolder = async () => {
101999
+ if (rootFolderCheckRunningRef.current)
102000
+ return;
102001
+ if (!rootDriveFolderUrl.trim()) {
102002
+ setRootFolderInfo(null);
102003
+ setDrivePublicAccessWarning(false);
102004
+ return;
102005
+ }
102006
+ const validToken = await getValidAccessToken();
102007
+ if (!validToken || cancelled) {
102008
+ if (!cancelled)
102009
+ setRootFolderInfo(null);
102010
+ return;
102011
+ }
102012
+ const rootFolderId = extractFolderId(rootDriveFolderUrl);
102013
+ if (!rootFolderId || cancelled) {
102014
+ if (!cancelled)
102015
+ setRootFolderInfo(null);
102016
+ return;
102017
+ }
102018
+ rootFolderCheckRunningRef.current = true;
102019
+ setCheckingRootFolder(true);
102020
+ try {
102021
+ if (!permissionCheckedFoldersRef.current.has(rootFolderId)) {
102022
+ const permissionsUrl = `https://www.googleapis.com/drive/v3/files/${rootFolderId}?fields=permissions(id,type,role)&supportsAllDrives=true`;
102023
+ const permissionsResponse = await fetch(permissionsUrl, {
102024
+ headers: {
102025
+ 'Authorization': `Bearer ${validToken}`
102026
+ }
102027
+ });
102028
+ if (cancelled)
102029
+ return;
102030
+ permissionCheckedFoldersRef.current.add(rootFolderId);
102031
+ if (permissionsResponse.ok) {
102032
+ const permissionsData = await permissionsResponse.json();
102033
+ const anyonePerms = (permissionsData.permissions || []).filter((p) => p.type === 'anyone' && p.id);
102034
+ if (anyonePerms.length > 0) {
102035
+ if (cancelled)
102036
+ return;
102037
+ const revoke = window.confirm('У этой папки включён общий доступ по ссылке («Все, у кого есть ссылка» или публично в интернете).\n\n' +
102038
+ 'Приложение использует ваш аккаунт Google — открывать папку всем не обязательно.\n\n' +
102039
+ 'Убрать общий доступ для этой папки автоматически?');
102040
+ if (cancelled)
102041
+ return;
102042
+ if (revoke) {
102043
+ const tok = await getValidAccessToken();
102044
+ if (!tok || cancelled) {
102045
+ if (!cancelled)
102046
+ setRootFolderInfo(null);
102047
+ return;
102048
+ }
102049
+ for (const p of anyonePerms) {
102050
+ if (cancelled)
102051
+ break;
102052
+ const delUrl = `https://www.googleapis.com/drive/v3/files/${rootFolderId}/permissions/${p.id}?supportsAllDrives=true`;
102053
+ const delRes = await fetch(delUrl, {
102054
+ method: 'DELETE',
102055
+ headers: { 'Authorization': `Bearer ${tok}` }
102056
+ });
102057
+ if (!delRes.ok) {
102058
+ const errText = await delRes.text();
102059
+ logToTerminal('error', 'Failed to remove Drive permission:', errText);
102060
+ }
102061
+ }
102062
+ if (!cancelled)
102063
+ setDrivePublicAccessWarning(false);
102064
+ }
102065
+ else if (!cancelled) {
102066
+ setDrivePublicAccessWarning(true);
102067
+ }
102068
+ }
102069
+ else if (!cancelled) {
102070
+ setDrivePublicAccessWarning(false);
102071
+ }
102072
+ }
102073
+ }
102074
+ if (cancelled)
102075
+ return;
102076
+ const currentToken = await getValidAccessToken();
102077
+ if (!currentToken || cancelled) {
102078
+ if (!cancelled)
102079
+ setRootFolderInfo(null);
102080
+ return;
102081
+ }
102082
+ const fields = 'files(id, name)';
102083
+ const qOffers = `'${rootFolderId}' in parents and trashed = false and mimeType = 'application/vnd.google-apps.folder'`;
102084
+ const offersUrl = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(qOffers)}&fields=${encodeURIComponent(fields)}&supportsAllDrives=true`;
102085
+ const offersResponse = await fetch(offersUrl, {
102086
+ headers: { 'Authorization': `Bearer ${currentToken}` }
102087
+ });
102088
+ if (cancelled)
102089
+ return;
102090
+ let hasOffersFolder = false;
102091
+ if (offersResponse.ok) {
102092
+ const offersData = await offersResponse.json();
102093
+ hasOffersFolder = (offersData.files || []).some((f) => (f.name || '').toUpperCase() === 'OFFERS');
102094
+ }
102095
+ if (!cancelled) {
102096
+ setRootFolderInfo({ hasOffersFolder });
102097
+ }
102098
+ }
102099
+ catch (err) {
102100
+ if (!cancelled)
102101
+ setRootFolderInfo(null);
102102
+ }
102103
+ finally {
102104
+ rootFolderCheckRunningRef.current = false;
102105
+ if (!cancelled)
102106
+ setCheckingRootFolder(false);
102107
+ }
102108
+ };
102109
+ const timeoutId = setTimeout(() => {
102110
+ checkRootFolder();
102111
+ }, 500);
102112
+ return () => {
102113
+ cancelled = true;
102114
+ clearTimeout(timeoutId);
102115
+ };
102116
+ }, [rootDriveFolderUrl, accessToken, refreshToken]);
102117
+ // Рабочая папка Google Drive: product и крео-изображения
101791
102118
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
101792
102119
  let cancelled = false;
101793
102120
  const checkFolderFiles = async () => {
101794
- // Prevent concurrent runs (e.g. if token refresh re-triggers the effect while a check is in progress)
101795
102121
  if (folderCheckRunningRef.current)
101796
102122
  return;
101797
102123
  if (!driveFolderUrl.trim()) {
@@ -101813,47 +102139,38 @@ function App() {
101813
102139
  folderCheckRunningRef.current = true;
101814
102140
  setCheckingFolderFiles(true);
101815
102141
  try {
101816
- // Only check/ask about permissions if we haven't already handled this folder
101817
- if (!permissionCheckedFoldersRef.current.has(folderId)) {
101818
- const permissionsUrl = `https://www.googleapis.com/drive/v3/files/${folderId}?fields=permissions(id,type,role)`;
101819
- const permissionsResponse = await fetch(permissionsUrl, {
101820
- headers: {
101821
- 'Authorization': `Bearer ${validToken}`
101822
- }
101823
- });
102142
+ if (!driveFolderPublicLinkPromptedRef.current.has(folderId)) {
102143
+ const permResult = await fetchDriveFilePermissions(validToken, folderId);
101824
102144
  if (cancelled)
101825
102145
  return;
101826
- if (permissionsResponse.ok) {
101827
- const permissionsData = await permissionsResponse.json();
101828
- const hasPublicLinkAccess = permissionsData.permissions?.some((p) => p.type === 'anyone' && p.role === 'reader');
102146
+ if (!permResult.ok) {
102147
+ logToTerminal('warn', 'Could not read offer folder permissions (will retry on next check):', permResult.errorText);
102148
+ }
102149
+ else {
102150
+ const hasPublicLinkAccess = permissionsIncludeAnyoneLink(permResult.permissions);
101829
102151
  if (hasPublicLinkAccess) {
101830
- // Already accessible — remember so we don't ask again
101831
- permissionCheckedFoldersRef.current.add(folderId);
102152
+ driveFolderPublicLinkPromptedRef.current.add(folderId);
101832
102153
  }
101833
102154
  else {
101834
- // Mark as checked BEFORE showing confirm to prevent duplicate prompts
101835
- permissionCheckedFoldersRef.current.add(folderId);
101836
102155
  if (cancelled)
101837
102156
  return;
101838
- // Ask user for consent to enable public link access
101839
- const userConsent = confirm('⚠️ Папка Google Drive не доступна всем по ссылке.\n\n' +
101840
- 'Для работы приложения необходимо сделать папку доступной по ссылке.\n\n' +
101841
- 'Разрешить автоматически включить доступ по ссылке для этой папки?');
102157
+ const userConsent = window.confirm('⚠️ Папка оффера на Google Диске не открыта для всех по ссылке.\n\n' +
102158
+ 'Сервисы генерации изображений (OpenRouter) скачивают картинки по публичному URL без доступа по ссылке запросы могут падать с ошибкой.\n\n' +
102159
+ 'Включить доступ по ссылке для этой папки (читатель) автоматически?');
101842
102160
  if (cancelled)
101843
102161
  return;
101844
102162
  if (userConsent) {
101845
- // Automatically enable public link access via API
101846
- const currentToken = await getValidAccessToken();
101847
- if (!currentToken || cancelled) {
102163
+ const tok = await getValidAccessToken();
102164
+ if (!tok || cancelled) {
101848
102165
  if (!cancelled)
101849
102166
  setFolderFilesInfo(null);
101850
102167
  return;
101851
102168
  }
101852
- const createPermissionUrl = `https://www.googleapis.com/drive/v3/files/${folderId}/permissions`;
102169
+ const createPermissionUrl = `https://www.googleapis.com/drive/v3/files/${folderId}/permissions?supportsAllDrives=true`;
101853
102170
  const createPermissionResponse = await fetch(createPermissionUrl, {
101854
102171
  method: 'POST',
101855
102172
  headers: {
101856
- 'Authorization': `Bearer ${currentToken}`,
102173
+ 'Authorization': `Bearer ${tok}`,
101857
102174
  'Content-Type': 'application/json'
101858
102175
  },
101859
102176
  body: JSON.stringify({
@@ -101865,22 +102182,34 @@ function App() {
101865
102182
  return;
101866
102183
  if (!createPermissionResponse.ok) {
101867
102184
  const errorText = await createPermissionResponse.text();
101868
- logToTerminal('error', 'Failed to enable public link access:', errorText);
101869
- alert('⚠️ Не удалось автоматически включить доступ по ссылке для папки Google Drive.\n\nПожалуйста, сделайте папку доступной по ссылке вручную:\n1. Откройте папку в Google Drive\n2. Нажмите "Настройки доступа"\n3. Выберите "Все, у кого есть ссылка"\n4. Убедитесь, что роль установлена как "Читатель"');
102185
+ logToTerminal('error', 'Failed to enable public link access for offer folder:', errorText);
102186
+ window.alert('⚠️ Не удалось автоматически включить доступ по ссылке.\n\n' +
102187
+ 'Сделайте папку доступной по ссылке вручную в Google Диске (роль «Читатель»).');
102188
+ // Не помечаем folderId — при следующей проверке снова предложим / повторим
101870
102189
  }
101871
102190
  else {
101872
- logToTerminal('log', '✅ Public link access enabled for folder');
102191
+ const verify = await fetchDriveFilePermissions(tok, folderId);
102192
+ if (verify.ok && permissionsIncludeAnyoneLink(verify.permissions)) {
102193
+ driveFolderPublicLinkPromptedRef.current.add(folderId);
102194
+ logToTerminal('log', '✅ Public link access enabled for offer folder (verified)');
102195
+ }
102196
+ else {
102197
+ logToTerminal('warn', 'Permission API succeeded but anyone-link not visible on re-fetch; user should verify in Drive UI');
102198
+ window.alert('⚠️ Запрос на доступ отправлен, но повторная проверка не увидела права «для всех по ссылке».\n\n' +
102199
+ 'Проверьте папку в Google Диске вручную: общий доступ → «Все, у кого есть ссылка» → Читатель.');
102200
+ }
101873
102201
  }
101874
102202
  }
101875
102203
  else {
101876
- alert('⚠️ Папка должна быть доступна по ссылке для работы приложения.\n\nПожалуйста, сделайте папку доступной по ссылке вручную:\n1. Откройте папку в Google Drive\n2. Нажмите "Настройки доступа"\n3. Выберите "Все, у кого есть ссылка"\n4. Убедитесь, что роль установлена как "Читатель"');
102204
+ driveFolderPublicLinkPromptedRef.current.add(folderId);
102205
+ window.alert('⚠️ Без доступа по ссылке генерация с референсами из этой папки может не работать.\n\n' +
102206
+ 'Включите вручную: Настройки доступа → «Все, у кого есть ссылка» → Читатель.');
101877
102207
  }
101878
102208
  }
101879
102209
  }
101880
102210
  }
101881
102211
  if (cancelled)
101882
102212
  return;
101883
- // Then check folder files
101884
102213
  const currentToken = await getValidAccessToken();
101885
102214
  if (!currentToken || cancelled) {
101886
102215
  if (!cancelled)
@@ -101889,7 +102218,7 @@ function App() {
101889
102218
  }
101890
102219
  const q = `'${folderId}' in parents and trashed = false and mimeType contains 'image/'`;
101891
102220
  const fields = 'files(id, name)';
101892
- const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}`;
102221
+ const url = `https://www.googleapis.com/drive/v3/files?q=${encodeURIComponent(q)}&fields=${encodeURIComponent(fields)}&supportsAllDrives=true`;
101893
102222
  const response = await fetch(url, {
101894
102223
  headers: {
101895
102224
  'Authorization': `Bearer ${currentToken}`
@@ -101897,30 +102226,28 @@ function App() {
101897
102226
  });
101898
102227
  if (cancelled)
101899
102228
  return;
101900
- if (response.ok) {
101901
- const data = await response.json();
101902
- const hasProduct = data.files.some((f) => {
101903
- const name = f.name?.toLowerCase() || '';
101904
- return name === 'product.png' || name === 'product.jpg' || name === 'product.webp';
101905
- });
101906
- const hasCreativeImages = data.files.some((f) => {
101907
- const name = f.name?.toLowerCase() || '';
101908
- return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
101909
- });
101910
- if (!cancelled) {
101911
- setFolderFilesInfo({ hasProduct, hasCreativeImages });
101912
- // If product not found, poll every 10 seconds until found
101913
- if (!hasProduct) {
101914
- pollTimeoutId = setTimeout(() => {
101915
- if (!cancelled)
101916
- checkFolderFiles();
101917
- }, 10_000);
101918
- }
101919
- }
101920
- }
101921
- else {
102229
+ if (!response.ok) {
101922
102230
  if (!cancelled)
101923
102231
  setFolderFilesInfo(null);
102232
+ return;
102233
+ }
102234
+ const data = await response.json();
102235
+ const hasProduct = data.files.some((f) => {
102236
+ const name = f.name?.toLowerCase() || '';
102237
+ return name === 'product.png' || name === 'product.jpg' || name === 'product.webp';
102238
+ });
102239
+ const hasCreativeImages = data.files.some((f) => {
102240
+ const name = f.name?.toLowerCase() || '';
102241
+ return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
102242
+ });
102243
+ if (!cancelled) {
102244
+ setFolderFilesInfo({ hasProduct, hasCreativeImages });
102245
+ if (!hasProduct) {
102246
+ pollTimeoutId = setTimeout(() => {
102247
+ if (!cancelled)
102248
+ checkFolderFiles();
102249
+ }, 10_000);
102250
+ }
101924
102251
  }
101925
102252
  }
101926
102253
  catch (err) {
@@ -101934,7 +102261,6 @@ function App() {
101934
102261
  }
101935
102262
  };
101936
102263
  let pollTimeoutId = null;
101937
- // Debounce check
101938
102264
  const timeoutId = setTimeout(() => {
101939
102265
  checkFolderFiles();
101940
102266
  }, 500);
@@ -103041,7 +103367,7 @@ function App() {
103041
103367
  setTexts(['']);
103042
103368
  setPairTranslations({});
103043
103369
  // Read pairs count from settings (3–10, default 3)
103044
- const pairsCountInit = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getPairsCount)();
103370
+ const pairsCountInit = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getPairsCount)();
103045
103371
  // Initialize placeholders
103046
103372
  const initialTitles = Array.from({ length: pairsCountInit }, (_, index) => ({
103047
103373
  index: index + 1,
@@ -103070,7 +103396,7 @@ function App() {
103070
103396
  }
103071
103397
  // Generate all pairs (title + text) in a single request
103072
103398
  addLog(formatLogMessage('log', '📋 Generating title+text pairs in a single request...'));
103073
- const selectedIndices = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getSelectedPairApproaches)();
103399
+ const selectedIndices = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getSelectedPairApproaches)();
103074
103400
  setLastUsedApproachIndices(selectedIndices);
103075
103401
  const pairsCount = selectedIndices.length;
103076
103402
  addLog(formatLogMessage('log', `⚙️ Generating ${pairsCount} pairs (approaches: ${selectedIndices.join(', ')})`));
@@ -104009,7 +104335,7 @@ function App() {
104009
104335
  addLog(formatLogMessage(level, ...args));
104010
104336
  };
104011
104337
  logMsg('log', '📦 Creating ZIP archive with HTML and product image...');
104012
- const zip = new (jszip__WEBPACK_IMPORTED_MODULE_54___default())();
104338
+ const zip = new (jszip__WEBPACK_IMPORTED_MODULE_57___default())();
104013
104339
  // Replace product image path in HTML to match actual filename (png/jpg/webp)
104014
104340
  const htmlWithProductPath = htmlContent.replace(/src=["']product\.(png|jpe?g|webp)["']/gi, `src="${productImageName}"`);
104015
104341
  zip.file('index.html', htmlWithProductPath);
@@ -104331,6 +104657,15 @@ function App() {
104331
104657
  throw new Error(errorMsg);
104332
104658
  }
104333
104659
  addLog(formatLogMessage('log', '✅ Folder ID extracted:', folderId));
104660
+ addLog(formatLogMessage('log', '🔒 Проверка доступа по ссылке к папке оффера (нужен для референса)...'));
104661
+ const pubGate = await verifyOfferFolderHasAnyoneLinkForImageGen(validToken, folderId);
104662
+ if (!pubGate.ok) {
104663
+ addLog(formatLogMessage('error', '❌ ' + pubGate.message));
104664
+ alert(pubGate.message);
104665
+ setGeneratingImages(false);
104666
+ return;
104667
+ }
104668
+ addLog(formatLogMessage('log', '✅ Доступ по ссылке к папке оффера подтверждён'));
104334
104669
  // Check for product image (png/jpg/webp)
104335
104670
  addLog(formatLogMessage('log', '🔍 Checking for product image...'));
104336
104671
  const productImage = await fetchProductImage(folderId);
@@ -104341,8 +104676,8 @@ function App() {
104341
104676
  }
104342
104677
  addLog(formatLogMessage('log', '✅ Product image found'));
104343
104678
  // Generate images with different approaches (количество по каждому подходу)
104344
- const approaches = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getCreoApproaches)();
104345
- if (approaches.length === 0) {
104679
+ const expandedTasks = (0,_prompts__WEBPACK_IMPORTED_MODULE_1__.getCreoApproachExpandedTasks)();
104680
+ if (expandedTasks.length === 0) {
104346
104681
  addLog(formatLogMessage('error', '❌ Укажите количество изображений (хотя бы 1) в настройках подходов'));
104347
104682
  alert('Укажите количество изображений (1–4) хотя бы для одного подхода в настройках');
104348
104683
  setGeneratingImages(false);
@@ -104351,11 +104686,15 @@ function App() {
104351
104686
  // При "both" — на каждый подход генерируем и 1:1, и 2:3
104352
104687
  const useBoth = imageAspectRatio === 'both';
104353
104688
  const tasks = useBoth
104354
- ? approaches.flatMap(a => [
104355
- { approach: a, ratio: '1:1' },
104356
- { approach: a, ratio: '2:3' }
104689
+ ? expandedTasks.flatMap(t => [
104690
+ { approach: t.approach, poolIndex: t.poolIndex, ratio: '1:1' },
104691
+ { approach: t.approach, poolIndex: t.poolIndex, ratio: '2:3' }
104357
104692
  ])
104358
- : approaches.map(a => ({ approach: a, ratio: imageAspectRatio }));
104693
+ : expandedTasks.map(t => ({
104694
+ approach: t.approach,
104695
+ poolIndex: t.poolIndex,
104696
+ ratio: imageAspectRatio
104697
+ }));
104359
104698
  const additionalInfoLine = generateAdditionalInfo.trim()
104360
104699
  ? `\n📋 ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ О ПРОДУКТЕ: ${generateAdditionalInfo.trim()}`
104361
104700
  : '';
@@ -104374,6 +104713,7 @@ function App() {
104374
104713
  index: index + 1,
104375
104714
  imageUrl: undefined,
104376
104715
  approach: t.approach.name + (useBoth ? ` (${t.ratio})` : ''),
104716
+ creoApproachUiNumber: t.poolIndex + 1,
104377
104717
  aspectRatio: t.ratio,
104378
104718
  uploaded: false,
104379
104719
  checking: false,
@@ -104385,7 +104725,8 @@ function App() {
104385
104725
  regenerating: false,
104386
104726
  customRegeneratePrompt: '',
104387
104727
  failed: false,
104388
- generating: false // In sequential mode, images start queued (not generating)
104728
+ generating: false, // In sequential mode, images start queued (not generating)
104729
+ remakeCount: 0
104389
104730
  }));
104390
104731
  setGeneratedImagesData(initialPlaceholders);
104391
104732
  addLog(formatLogMessage('log', `📝 Generated prompts for ${tasks.length} images${useBoth ? ' (1:1 + 2:3 на каждый подход)' : ''}`));
@@ -104542,7 +104883,7 @@ function App() {
104542
104883
  imageUrl: null,
104543
104884
  success: false,
104544
104885
  error: new Error('Generation did not complete'),
104545
- approach: approaches[i]?.name || 'Unknown',
104886
+ approach: tasks[i]?.approach.name || 'Unknown',
104546
104887
  originalPrompt: imagePrompts[i],
104547
104888
  productImageUrl: productImage.url
104548
104889
  });
@@ -104635,11 +104976,26 @@ function App() {
104635
104976
  alert('Не удалось найти оригинальный промпт или изображение продукта для переделки');
104636
104977
  return;
104637
104978
  }
104979
+ const regenFolderId = extractFolderId(driveFolderUrl);
104980
+ if (!regenFolderId) {
104981
+ alert('Укажите корректный URL папки оффера на Google Drive');
104982
+ return;
104983
+ }
104638
104984
  const addLog = (msg) => {
104639
104985
  setImagesGenerationLogs(prev => [...prev, msg]);
104640
104986
  logToTerminal('log', msg.replace(/\[.*?\]\s*/, ''));
104641
104987
  };
104642
104988
  try {
104989
+ const regenTok = await getValidAccessToken();
104990
+ if (!regenTok) {
104991
+ alert('Please log in with Google first');
104992
+ return;
104993
+ }
104994
+ const regenPub = await verifyOfferFolderHasAnyoneLinkForImageGen(regenTok, regenFolderId);
104995
+ if (!regenPub.ok) {
104996
+ alert(regenPub.message);
104997
+ return;
104998
+ }
104643
104999
  // Get current customRegeneratePrompt from state
104644
105000
  const currentImageData = generatedImagesData.find(img => img.index === imageData.index);
104645
105001
  const customPrompt = currentImageData?.customRegeneratePrompt?.trim() || '';
@@ -104794,7 +105150,8 @@ ${imageData.originalPrompt}
104794
105150
  checkErrors: undefined,
104795
105151
  uploaded: false, // Reset uploaded status since it's a new image
104796
105152
  customRegeneratePrompt: '', // Reset custom prompt after regeneration
104797
- failed: false // Mark as successful
105153
+ failed: false, // Mark as successful
105154
+ remakeCount: (img.remakeCount ?? 0) + 1
104798
105155
  }
104799
105156
  : img));
104800
105157
  // Run validation on the new image (skip if disabled)
@@ -104859,11 +105216,26 @@ ${imageData.originalPrompt}
104859
105216
  alert('Не удалось найти оригинальный промпт или изображение продукта для переделки');
104860
105217
  return;
104861
105218
  }
105219
+ const freshFolderId = extractFolderId(driveFolderUrl);
105220
+ if (!freshFolderId) {
105221
+ alert('Укажите корректный URL папки оффера на Google Drive');
105222
+ return;
105223
+ }
104862
105224
  const addLog = (msg) => {
104863
105225
  setImagesGenerationLogs(prev => [...prev, msg]);
104864
105226
  logToTerminal('log', msg.replace(/\[.*?\]\s*/, ''));
104865
105227
  };
104866
105228
  try {
105229
+ const freshTok = await getValidAccessToken();
105230
+ if (!freshTok) {
105231
+ alert('Please log in with Google first');
105232
+ return;
105233
+ }
105234
+ const freshPub = await verifyOfferFolderHasAnyoneLinkForImageGen(freshTok, freshFolderId);
105235
+ if (!freshPub.ok) {
105236
+ alert(freshPub.message);
105237
+ return;
105238
+ }
104867
105239
  // Mark as regenerating (show overlay timer) - clear old image URL immediately to force re-render
104868
105240
  setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
104869
105241
  ? {
@@ -104909,7 +105281,8 @@ ${imageData.originalPrompt}
104909
105281
  checkErrors: undefined,
104910
105282
  uploaded: false,
104911
105283
  customRegeneratePrompt: '',
104912
- failed: false
105284
+ failed: false,
105285
+ remakeCount: (img.remakeCount ?? 0) + 1
104913
105286
  }
104914
105287
  : img));
104915
105288
  // Validate new image (skip if disabled)
@@ -105031,11 +105404,10 @@ ${imageData.originalPrompt}
105031
105404
  logToTerminal('log', msg.replace(/\[.*?\]\s*/, ''));
105032
105405
  };
105033
105406
  try {
105034
- const filename = `${generateProduct.replace(/\s+/g, '_')}_${imageData.index}_${Date.now()}.png`;
105407
+ const filename = creativeImageUploadFilename(imageData.creoApproachUiNumber);
105035
105408
  addLog(formatLogMessage('log', `📤 Uploading image ${imageData.index} to Drive: ${filename}`));
105036
105409
  const driveUrl = await uploadImageToDrive(imageData.imageUrl, filename, folderId, addLog);
105037
105410
  addLog(formatLogMessage('log', `✅ Image ${imageData.index} uploaded: ${driveUrl}`));
105038
- // Update uploaded status
105039
105411
  setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index ? { ...img, uploaded: true } : img));
105040
105412
  // (Removed legacy Generated Images links list)
105041
105413
  }
@@ -105075,9 +105447,8 @@ ${imageData.originalPrompt}
105075
105447
  : img));
105076
105448
  try {
105077
105449
  addLog(formatLogMessage('log', `📤 Uploading ${notUploaded.length} image(s) to Drive (parallel)...`));
105078
- const baseTs = Date.now();
105079
- const results = await Promise.allSettled(notUploaded.map((imageData, i) => {
105080
- const filename = `${generateProduct.replace(/\s+/g, '_')}_${imageData.index}_${baseTs}_${i}.png`;
105450
+ const results = await Promise.allSettled(notUploaded.map((imageData) => {
105451
+ const filename = creativeImageUploadFilename(imageData.creoApproachUiNumber);
105081
105452
  addLog(formatLogMessage('log', `📤 Starting upload image ${imageData.index}: ${filename}`));
105082
105453
  return uploadImageToDrive(imageData.imageUrl, filename, folderId, addLog).then(driveUrl => ({
105083
105454
  index: imageData.index,
@@ -105157,6 +105528,22 @@ ${imageData.originalPrompt}
105157
105528
  // invalid — leave as is
105158
105529
  }
105159
105530
  };
105531
+ const handleLinkPaste = (e) => {
105532
+ e.preventDefault();
105533
+ const pasted = e.clipboardData.getData('text/plain');
105534
+ const cleanedPaste = pasted.split('?')[0] ?? pasted;
105535
+ const input = e.currentTarget;
105536
+ const start = input.selectionStart ?? 0;
105537
+ const end = input.selectionEnd ?? 0;
105538
+ const newVal = link.slice(0, start) + cleanedPaste + link.slice(end);
105539
+ handleLinkChange(newVal);
105540
+ const pos = start + cleanedPaste.length;
105541
+ setTimeout(() => {
105542
+ const el = linkInputRef.current;
105543
+ if (el)
105544
+ el.setSelectionRange(pos, pos);
105545
+ }, 0);
105546
+ };
105160
105547
  const extractFolderId = (url) => {
105161
105548
  // Try to match format: /folders/([a-zA-Z0-9_-]+)
105162
105549
  const foldersMatch = url.match(/folders\/([a-zA-Z0-9_-]+)/);
@@ -105203,7 +105590,13 @@ ${imageData.originalPrompt}
105203
105590
  const name = f.name?.toLowerCase() || '';
105204
105591
  return name !== 'product.png' && name !== 'product.jpg' && name !== 'product.webp';
105205
105592
  });
105206
- return filteredFiles.map((f) => f.id ? `https://drive.google.com/file/d/${f.id}/view?usp=sharing` : '');
105593
+ return filteredFiles
105594
+ .filter((f) => f.id && f.name)
105595
+ .map((f) => ({
105596
+ fileId: f.id,
105597
+ name: f.name,
105598
+ viewUrl: `https://drive.google.com/file/d/${f.id}/view?usp=sharing`
105599
+ }));
105207
105600
  };
105208
105601
  const fetchProductImage = async (folderId) => {
105209
105602
  const validToken = await getValidAccessToken();
@@ -105336,8 +105729,13 @@ ${imageData.originalPrompt}
105336
105729
  },
105337
105730
  brand: brandValue !== undefined ? brandValue : brand || '',
105338
105731
  link: linkValue !== undefined ? linkValue : link || '',
105339
- selectedPairApproaches: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getSelectedPairApproaches)(),
105340
- imageApproachCounts: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_52__.getImageApproachCounts)(),
105732
+ catalogUrlIncludeTextApproach,
105733
+ catalogUrlIncludeCreoApproach,
105734
+ catalogUrlTextApproachParam,
105735
+ catalogUrlCreoApproachParam,
105736
+ catalogLinkExtraMacros,
105737
+ selectedPairApproaches: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getSelectedPairApproaches)(),
105738
+ imageApproachCounts: (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getImageApproachCounts)(),
105341
105739
  savedAt: new Date().toISOString()
105342
105740
  };
105343
105741
  const jsonContent = JSON.stringify(dataToSave, null, 2);
@@ -105486,9 +105884,41 @@ ${imageData.originalPrompt}
105486
105884
  setLink(loadedData.link || '');
105487
105885
  logToTerminal('log', '[Load Content] Loaded link:', loadedData.link || '(empty)');
105488
105886
  }
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');
105887
+ if (typeof loadedData.catalogUrlIncludeTextApproach === 'boolean') {
105888
+ setCatalogUrlIncludeTextApproach(loadedData.catalogUrlIncludeTextApproach);
105889
+ }
105890
+ if (typeof loadedData.catalogUrlIncludeCreoApproach === 'boolean') {
105891
+ setCatalogUrlIncludeCreoApproach(loadedData.catalogUrlIncludeCreoApproach);
105892
+ }
105893
+ if (typeof loadedData.catalogUrlTextApproachParam === 'string' && loadedData.catalogUrlTextApproachParam.trim()) {
105894
+ setCatalogUrlTextApproachParam(loadedData.catalogUrlTextApproachParam.trim());
105895
+ }
105896
+ if (typeof loadedData.catalogUrlCreoApproachParam === 'string' && loadedData.catalogUrlCreoApproachParam.trim()) {
105897
+ setCatalogUrlCreoApproachParam(loadedData.catalogUrlCreoApproachParam.trim());
105898
+ }
105899
+ if (typeof loadedData.catalogLinkExtraMacros === 'string') {
105900
+ setCatalogLinkExtraMacros(loadedData.catalogLinkExtraMacros);
105901
+ }
105902
+ else {
105903
+ setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS);
105904
+ }
105905
+ const parsedApproaches = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.parseApproachesFromDriveData)(loadedData);
105906
+ const currentPairs = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getSelectedPairApproaches)();
105907
+ const currentCounts = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.getImageApproachCounts)();
105908
+ const hasDrivePairs = parsedApproaches.pairs !== null;
105909
+ const hasDriveCounts = parsedApproaches.counts !== null;
105910
+ if (hasDrivePairs || hasDriveCounts) {
105911
+ const pairsDiffer = hasDrivePairs && !sortedPairIndicesEqual(parsedApproaches.pairs, currentPairs);
105912
+ const countsDiffer = hasDriveCounts && !imageApproachCountsEqual(parsedApproaches.counts, currentCounts);
105913
+ if (pairsDiffer || countsDiffer) {
105914
+ setApproachLoadChoice({
105915
+ savedPairs: parsedApproaches.pairs,
105916
+ savedCounts: parsedApproaches.counts,
105917
+ currentPairs,
105918
+ currentCounts,
105919
+ });
105920
+ logToTerminal('log', '[Load Content] Offer file contains approach settings — asking user to apply or keep current');
105921
+ }
105492
105922
  }
105493
105923
  logToTerminal('log', '[Load Content] Successfully loaded content');
105494
105924
  setDriveFilesFound(prev => ({ ...prev, content: false }));
@@ -105500,6 +105930,19 @@ ${imageData.originalPrompt}
105500
105930
  return { found: false };
105501
105931
  }
105502
105932
  };
105933
+ const handleApproachLoadApplyFromFile = () => {
105934
+ if (!approachLoadChoice)
105935
+ return;
105936
+ const applied = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.applyParsedApproachesFromDrive)(approachLoadChoice.savedPairs, approachLoadChoice.savedCounts);
105937
+ if (applied) {
105938
+ logToTerminal('log', '[Load Content] Applied approach settings from offer file (user choice)');
105939
+ }
105940
+ setApproachLoadChoice(null);
105941
+ };
105942
+ const handleApproachLoadKeepCurrent = () => {
105943
+ logToTerminal('log', '[Load Content] Kept local approach settings (user choice)');
105944
+ setApproachLoadChoice(null);
105945
+ };
105503
105946
  syncDriveAfterPromptSaveRef.current = () => {
105504
105947
  if (!driveFolderUrl || loadingContentFromDrive)
105505
105948
  return;
@@ -105518,8 +105961,8 @@ ${imageData.originalPrompt}
105518
105961
  };
105519
105962
  (0,react__WEBPACK_IMPORTED_MODULE_0__.useEffect)(() => {
105520
105963
  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);
105964
+ window.addEventListener(_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.PROMPT_OVERRIDES_SAVED_EVENT, listener);
105965
+ return () => window.removeEventListener(_promptOverrides__WEBPACK_IMPORTED_MODULE_55__.PROMPT_OVERRIDES_SAVED_EVENT, listener);
105523
105966
  }, []);
105524
105967
  const handleGenerate = async () => {
105525
105968
  if (!driveFolderUrl || !brand || !link) {
@@ -105574,9 +106017,17 @@ ${imageData.originalPrompt}
105574
106017
  for (let i = 0; i < pairCount; i++) {
105575
106018
  const title = titleList[i];
105576
106019
  const text = textList[i];
106020
+ const pairApproachIdx = lastUsedApproachIndices[i] ?? i;
106021
+ const textApproachUiNumber = String(pairApproachIdx + 1);
105577
106022
  for (const image of images) {
105578
106023
  const id = `${brand}${idCounter++}`;
105579
- const rowLink = appendCreativeIdToCatalogLink(link, id);
106024
+ const creoFromFileName = parseCreoApproachLabelFromImageFileName(image.name);
106025
+ const rowLink = appendCreativeIdToCatalogLink(link, id, {
106026
+ textApproach: catalogUrlIncludeTextApproach ? textApproachUiNumber : undefined,
106027
+ creoApproach: catalogUrlIncludeCreoApproach && creoFromFileName ? creoFromFileName : undefined,
106028
+ textParamKey: catalogUrlTextApproachParam,
106029
+ creoParamKey: catalogUrlCreoApproachParam
106030
+ }, catalogLinkExtraMacros);
105580
106031
  rows.push([
105581
106032
  id,
105582
106033
  title,
@@ -105585,15 +106036,15 @@ ${imageData.originalPrompt}
105585
106036
  'new',
105586
106037
  '10,00 USD',
105587
106038
  rowLink,
105588
- image,
106039
+ image.viewUrl,
105589
106040
  brand
105590
106041
  ]);
105591
106042
  }
105592
106043
  }
105593
106044
  setGeneratedData(rows);
105594
106045
  // Create workbook
105595
- const wb = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_new();
105596
- const ws = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.aoa_to_sheet(rows);
106046
+ const wb = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_new();
106047
+ const ws = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.aoa_to_sheet(rows);
105597
106048
  // Set column widths (approximate pixel width / 7)
105598
106049
  ws['!cols'] = [
105599
106050
  { wch: 20 }, // id
@@ -105606,9 +106057,9 @@ ${imageData.originalPrompt}
105606
106057
  { wch: 40 }, // image_link
105607
106058
  { wch: 20 } // brand
105608
106059
  ];
105609
- xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_append_sheet(wb, ws, "Products");
106060
+ xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_append_sheet(wb, ws, "Products");
105610
106061
  // Generate buffer
105611
- const wbout = xlsx__WEBPACK_IMPORTED_MODULE_53__.write(wb, { bookType: 'xlsx', type: 'array' });
106062
+ const wbout = xlsx__WEBPACK_IMPORTED_MODULE_56__.write(wb, { bookType: 'xlsx', type: 'array' });
105612
106063
  // Upload to Drive (имя файла по бренду)
105613
106064
  const dateStr = new Date().toISOString().split('T')[0];
105614
106065
  const fileName = `${brand}-${dateStr}.xlsx`;
@@ -105730,13 +106181,13 @@ ${imageData.originalPrompt}
105730
106181
  setTestLoading(true);
105731
106182
  try {
105732
106183
  // Create simple test workbook with structure
105733
- const wb = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.book_new();
106184
+ const wb = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_new();
105734
106185
  const rows = [
105735
106186
  INSTRUCTION_ROW,
105736
106187
  ['id', 'title', 'description', 'availability', 'condition', 'price', 'link', 'image_link', 'brand'],
105737
106188
  ['test1', 'Test Title', 'Test Description', 'in stock', 'new', '10.00 USD', 'http://test.com', 'http://test.com/img.jpg', 'TestBrand']
105738
106189
  ];
105739
- const ws = xlsx__WEBPACK_IMPORTED_MODULE_53__.utils.aoa_to_sheet(rows);
106190
+ const ws = xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.aoa_to_sheet(rows);
105740
106191
  // Set column widths
105741
106192
  ws['!cols'] = [
105742
106193
  { wch: 20 }, // id
@@ -105749,8 +106200,8 @@ ${imageData.originalPrompt}
105749
106200
  { wch: 40 }, // image_link
105750
106201
  { wch: 20 } // brand
105751
106202
  ];
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' });
106203
+ xlsx__WEBPACK_IMPORTED_MODULE_56__.utils.book_append_sheet(wb, ws, "Test");
106204
+ const wbout = xlsx__WEBPACK_IMPORTED_MODULE_56__.write(wb, { bookType: 'xlsx', type: 'array' });
105754
106205
  // Try to extract folder ID if available, otherwise upload to root
105755
106206
  const folderId = driveFolderUrl ? extractFolderId(driveFolderUrl) : undefined;
105756
106207
  const result = await uploadFileToDrive(wbout, 'test_table.xlsx', folderId || undefined);
@@ -105802,7 +106253,7 @@ ${imageData.originalPrompt}
105802
106253
  };
105803
106254
  // Show lock screen if not unlocked
105804
106255
  if (!unlocked) {
105805
- return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], { theme: theme },
106256
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_37__["default"], { theme: theme },
105806
106257
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
105807
106258
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { onClick: handleSecretClick, sx: {
105808
106259
  width: '100vw',
@@ -105842,35 +106293,49 @@ ${imageData.originalPrompt}
105842
106293
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("br", null),
105843
106294
  "Please contact system administrator"))));
105844
106295
  }
105845
- return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], { theme: theme },
106296
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_37__["default"], { theme: theme },
105846
106297
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_4__["default"], null),
105847
106298
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_7__["default"], { maxWidth: "lg", sx: { py: 4 } },
105848
106299
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 2 } },
105849
106300
  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"),
105850
106301
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
105851
106302
  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 } },
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)))),
106303
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_52__["default"], null)),
106304
+ 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_42__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], null)))),
105854
106305
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_9__["default"], { variant: "outlined", sx: { mb: 4 } },
105855
106306
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_10__["default"], null,
105856
106307
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 3 },
105857
106308
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
105858
106309
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Authentication"),
105859
- accessToken ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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) },
106310
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
106311
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle2", color: "text.secondary", gutterBottom: true }, "\u041A\u043E\u0440\u043D\u0435\u0432\u0430\u044F \u043F\u0430\u043F\u043A\u0430 \u043F\u0440\u043E\u0435\u043A\u0442\u0430"),
106312
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", sx: { mb: 1 } }, "\u0421\u0441\u044B\u043B\u043A\u0430 \u043D\u0430 \u043A\u043E\u0440\u043D\u0435\u0432\u0443\u044E \u043F\u0430\u043F\u043A\u0443 \u043D\u0430 Google \u0414\u0438\u0441\u043A\u0435 (\u0432\u043D\u0443\u0442\u0440\u0438 \u043D\u0435\u0451 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u043F\u0430\u043F\u043A\u0430 OFFERS)."),
106313
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "URL \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 \u043F\u0430\u043F\u043A\u0438 Google Drive", variant: "outlined", fullWidth: true, value: rootDriveFolderUrl, onChange: (e) => setRootDriveFolderUrl(e.target.value), placeholder: "https://drive.google.com/drive/folders/...", sx: { mb: 1 } }),
106314
+ checkingRootFolder && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null,
106315
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'inline-flex', alignItems: 'center', gap: 1 } },
106316
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 14 }),
106317
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 \u043F\u0430\u043F\u043A\u0438 (OFFERS, \u0434\u043E\u0441\u0442\u0443\u043F)...")))),
106318
+ drivePublicAccessWarning && extractFolderId(rootDriveFolderUrl) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "warning", sx: { mt: 1 } }, "\u041E\u0431\u0449\u0438\u0439 \u0434\u043E\u0441\u0442\u0443\u043F \u043F\u043E \u0441\u0441\u044B\u043B\u043A\u0435 \u0432\u0441\u0451 \u0435\u0449\u0451 \u0432\u043A\u043B\u044E\u0447\u0451\u043D. \u0417\u0430\u043A\u0440\u043E\u0439\u0442\u0435 \u0435\u0433\u043E \u0432\u0440\u0443\u0447\u043D\u0443\u044E \u0432 \u043D\u0430\u0441\u0442\u0440\u043E\u0439\u043A\u0430\u0445 \u0434\u043E\u0441\u0442\u0443\u043F\u0430 Google \u0414\u0438\u0441\u043A\u0430 \u0438\u043B\u0438 \u0441\u043C\u0435\u043D\u0438\u0442\u0435 \u043F\u0430\u043F\u043A\u0443 \u0438 \u0441\u043E\u0433\u043B\u0430\u0441\u0438\u0442\u0435\u0441\u044C \u0443\u0431\u0440\u0430\u0442\u044C \u0434\u043E\u0441\u0442\u0443\u043F \u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438.")),
106319
+ !checkingRootFolder && rootFolderInfo && !rootFolderInfo.hasOffersFolder && extractFolderId(rootDriveFolderUrl) && (accessToken || refreshToken) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0412 \u043A\u043E\u0440\u043D\u0435\u0432\u043E\u0439 \u043F\u0430\u043F\u043A\u0435 \u043D\u0435\u0442 \u043F\u043E\u0434\u043F\u0430\u043F\u043A\u0438 OFFERS. \u0421\u043E\u0437\u0434\u0430\u0439\u0442\u0435 \u043F\u0430\u043F\u043A\u0443 \u0441 \u0438\u043C\u0435\u043D\u0435\u043C OFFERS (\u0440\u0435\u0433\u0438\u0441\u0442\u0440 \u043D\u0435 \u0432\u0430\u0436\u0435\u043D) \u0438 \u043F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u0435 \u043F\u0440\u043E\u0432\u0435\u0440\u043A\u0443.")),
106320
+ !checkingRootFolder && !rootFolderInfo && rootDriveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, (accessToken || refreshToken)
106321
+ ? 'Введите корректную ссылку на корневую папку Google Drive'
106322
+ : 'Войдите в Google, чтобы проверить корневую папку и подпапку OFFERS'))),
106323
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
106324
+ accessToken ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_17__["default"], null,
106325
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { expandIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_47__["default"], null) },
105861
106326
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { sx: { display: 'flex', alignItems: 'center', color: 'success.main' } },
105862
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], { sx: { mr: 1 } }),
106327
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], { sx: { mr: 1 } }),
105863
106328
  " Logged In (Credentials Hidden)")),
105864
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], null,
106329
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null,
105865
106330
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
105866
- 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)" }),
105867
- 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) }),
106331
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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)" }),
106332
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }),
105868
106333
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], null),
105869
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai" }))))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
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)" }),
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) }))),
106334
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai" }))))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
106335
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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)" }),
106336
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Client Secret", variant: "outlined", fullWidth: true, value: clientSecret, onChange: (e) => handleClientSecretChange(e.target.value) }))),
105872
106337
  openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 2, mt: 2 } },
105873
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_34__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
106338
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_38__["default"], { color: openRouterAccountBalance !== null ? 'primary' : 'disabled' }),
105874
106339
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: openRouterAccountBalance !== null ? 'text.primary' : 'text.secondary' },
105875
106340
  "\u0411\u0430\u043B\u0430\u043D\u0441: ",
105876
106341
  openRouterBalanceLoading ? 'Loading...' : (openRouterAccountBalance !== null ? `$${openRouterAccountBalance.toFixed(2)}` : 'N/A')),
@@ -105879,28 +106344,30 @@ ${imageData.originalPrompt}
105879
106344
  "\u041B\u0438\u043C\u0438\u0442 \u043A\u043B\u044E\u0447\u0430: ",
105880
106345
  openRouterBalanceLoading ? 'Loading...' : (openRouterBalance === -1 ? 'Без лимита' : (openRouterBalance !== null ? `${openRouterBalance.toFixed(4)}` : 'N/A'))))),
105881
106346
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, alignItems: "center", sx: { mt: 2 } },
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")))),
106347
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["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_14__["default"], { size: 20, color: "inherit" }) : (accessToken ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_43__["default"], null) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_48__["default"], null)), sx: { flexGrow: 1 } }, authLoading ? 'Logging in...' : (accessToken ? 'Logged In' : 'Login with Google')),
106348
+ accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "outlined", color: "error", onClick: handleLogout, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_49__["default"], null) }, "Logout")))),
105884
106349
  !accessToken && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
105885
106350
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], null),
105886
106351
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
105887
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai", sx: { mb: 2 } })))),
106352
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "OpenRouter API Key", variant: "outlined", fullWidth: true, value: openaiApiKey, onChange: (e) => handleOpenaiApiKeyChange(e.target.value), helperText: "Required for AI generation (images and text). Your key is stored locally. Get your key at openrouter.ai", sx: { mb: 2 } })))),
105888
106353
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
105889
106354
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
105890
106355
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "Google Drive Folder"),
105891
106356
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
105892
106357
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flexGrow: 1 } },
105893
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Google Drive Folder URL", variant: "outlined", fullWidth: true, value: driveFolderUrl, onChange: (e) => setDriveFolderUrl(e.target.value), placeholder: "https://drive.google.com/drive/folders/...", error: false }),
105894
- checkingFolderFiles && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null,
106358
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Google Drive Folder URL", variant: "outlined", fullWidth: true, value: driveFolderUrl, onChange: (e) => setDriveFolderUrl(e.target.value), placeholder: "https://drive.google.com/drive/folders/..." }),
106359
+ checkingFolderFiles && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null,
105895
106360
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { component: "span", sx: { display: 'inline-flex', alignItems: 'center', gap: 1 } },
105896
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 14 }),
105897
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u043E\u0432...")))),
105898
- !checkingFolderFiles && folderFilesInfo && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_19__["default"], null,
106361
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 14 }),
106362
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null, "\u041F\u0440\u043E\u0432\u0435\u0440\u043A\u0430 \u0444\u0430\u0439\u043B\u043E\u0432 \u0432 \u043F\u0430\u043F\u043A\u0435...")))),
106363
+ !checkingFolderFiles && folderFilesInfo && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null,
105899
106364
  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"))))),
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"))))),
105901
- !driveFolderUrl.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "info", sx: { mt: 2 } },
106365
+ !checkingFolderFiles && !folderFilesInfo && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, (accessToken || refreshToken)
106366
+ ? 'Введите корректную ссылку на папку Google Drive'
106367
+ : 'Войдите в Google, чтобы проверить файлы в папке'))))),
106368
+ !driveFolderUrl.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "info", sx: { mt: 2 } },
105902
106369
  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"),
105903
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443 Google Drive. \u0412\u0441\u0435 \u0434\u0430\u043D\u043D\u044B\u0435 \u0431\u0443\u0434\u0443\u0442 \u0441\u043E\u0445\u0440\u0430\u043D\u044F\u0442\u044C\u0441\u044F \u0438 \u0437\u0430\u0433\u0440\u0443\u0436\u0430\u0442\u044C\u0441\u044F \u0438\u0437 \u044D\u0442\u043E\u0439 \u043F\u0430\u043F\u043A\u0438."))) : !extractFolderId(driveFolderUrl) ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { severity: "warning", sx: { mt: 2 } },
106370
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u0414\u043B\u044F \u0440\u0430\u0431\u043E\u0442\u044B \u0441 \u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u0435\u0439 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438 \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0439 \u043D\u0435\u043E\u0431\u0445\u043E\u0434\u0438\u043C\u043E \u0443\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443 Google Drive."))) : !extractFolderId(driveFolderUrl) ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "warning", sx: { mt: 2 } },
105904
106371
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { fontWeight: 'bold', mb: 1 } }, "\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"),
105905
106372
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u0421\u0441\u044B\u043B\u043A\u0430 \u0434\u043E\u043B\u0436\u043D\u0430 \u0431\u044B\u0442\u044C \u0432 \u0444\u043E\u0440\u043C\u0430\u0442\u0435: https://drive.google.com/drive/folders/..."))) : loadingContentFromDrive ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
105906
106373
  display: 'flex',
@@ -105916,64 +106383,80 @@ ${imageData.originalPrompt}
105916
106383
  ? 'rgba(25, 118, 210, 0.1)'
105917
106384
  : 'rgba(25, 118, 210, 0.05)'
105918
106385
  } },
105919
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
106386
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
105920
106387
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { color: 'text.secondary', fontWeight: 'bold' } }, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0434\u0430\u043D\u043D\u044B\u0445 \u0438\u0437 \u043F\u0430\u043F\u043A\u0438..."))) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
105921
106388
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
105922
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Brand (Short ID)", variant: "outlined", sx: { flex: '0 0 320px', minWidth: 280 }, value: brand, InputProps: { readOnly: true }, placeholder: "\u0410\u0432\u0442\u043E: \u0442\u043E\u0432\u0430\u0440-\u0433\u0435\u043E-\u0446\u0435\u043D\u0430", helperText: "\u0410\u0432\u0442\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0438\u0437 \u0442\u043E\u0432\u0430\u0440\u0430, \u0433\u0435\u043E \u0438 \u0446\u0435\u043D\u044B" }),
106389
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Brand (Short ID)", variant: "outlined", sx: { flex: '0 0 320px', minWidth: 280 }, value: brand, InputProps: { readOnly: true }, placeholder: "\u0410\u0432\u0442\u043E: \u0442\u043E\u0432\u0430\u0440-\u0433\u0435\u043E-\u0446\u0435\u043D\u0430", helperText: "\u0410\u0432\u0442\u043E\u0433\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F \u0438\u0437 \u0442\u043E\u0432\u0430\u0440\u0430, \u0433\u0435\u043E \u0438 \u0446\u0435\u043D\u044B" }),
105923
106390
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { flex: 1, minWidth: 0 } },
105924
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { label: "Link", variant: "outlined", fullWidth: true, value: link, onChange: (e) => handleLinkChange(e.target.value), onBlur: handleLinkBlur, error: !!linkError, helperText: linkError, placeholder: "https://example.com/product/" }))),
106391
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "Link", variant: "outlined", fullWidth: true, value: link, onChange: (e) => handleLinkChange(e.target.value), onBlur: handleLinkBlur, error: !!linkError, helperText: linkError, placeholder: "https://example.com/product/", inputRef: linkInputRef, InputProps: { onPaste: handleLinkPaste } }))),
106392
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', gap: 1, alignItems: 'flex-start', mt: 1.5 } },
106393
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u0414\u043E\u043F. \u043C\u0430\u043A\u0440\u043E\u0441\u044B (\u043A\u0430\u0442\u0430\u043B\u043E\u0433)", variant: "outlined", size: "small", fullWidth: true, multiline: true, minRows: 2, value: catalogLinkExtraMacros, onChange: (e) => setCatalogLinkExtraMacros(e.target.value), placeholder: DEFAULT_CATALOG_LINK_EXTRA_MACROS, helperText: "\u0414\u043E\u0431\u0430\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u043F\u043E\u0441\u043B\u0435 creative_id \u0438 \u043F\u0430\u0440\u0430\u043C\u0435\u0442\u0440\u043E\u0432 \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432. \u0421\u043E\u0445\u0440\u0430\u043D\u044F\u0435\u0442\u0441\u044F \u0432 JSON \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A \u043F\u0430\u043F\u043A\u0438.", sx: { '& .MuiInputBase-input': { fontFamily: 'monospace', fontSize: 12 } } }),
106394
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 0.5, sx: { flexShrink: 0, mt: 0.5 } },
106395
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", onClick: () => setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_EXTRA_MACROS), sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "redtrack"),
106396
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", onClick: () => setCatalogLinkExtraMacros(DEFAULT_CATALOG_LINK_KEITARO_MACROS), sx: { textTransform: 'none', whiteSpace: 'nowrap' } }, "keitaro"))),
106397
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 1.5, sx: { mt: 1 } },
106398
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2, alignItems: { xs: 'stretch', sm: 'flex-start' } },
106399
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { checked: catalogUrlIncludeTextApproach, onChange: e => setCatalogUrlIncludeTextApproach(e.target.checked), size: "small" }), label: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
106400
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u041F\u043E\u0434\u0445\u043E\u0434 \u043A \u0442\u0435\u043A\u0441\u0442\u0443 \u0432 URL \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430"),
106401
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 \u043D\u043E\u043C\u0435\u0440 \u0441\u0442\u0440\u043E\u043A\u0438 \u043F\u043E\u0434\u0445\u043E\u0434\u0430 \u0434\u043B\u044F \u043F\u0430\u0440 \u0432 \u0442\u0430\u0431\u043B\u0438\u0446\u0435 \u043D\u0430\u0441\u0442\u0440\u043E\u0435\u043A (1\u201310)")), sx: { alignItems: 'flex-start', mr: 0, flex: { sm: '1 1 200px' }, minWidth: 0 } }),
106402
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0434\u043B\u044F \u0442\u0435\u043A\u0441\u0442\u0430", size: "small", value: catalogUrlTextApproachParam, onChange: e => setCatalogUrlTextApproachParam(e.target.value), placeholder: DEFAULT_CATALOG_TEXT_APPROACH_PARAM, sx: { width: { xs: '100%', sm: 200 }, flexShrink: 0 }, helperText: `По умолчанию: ${DEFAULT_CATALOG_TEXT_APPROACH_PARAM}` })),
106403
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2, alignItems: { xs: 'stretch', sm: 'flex-start' } },
106404
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { checked: catalogUrlIncludeCreoApproach, onChange: e => setCatalogUrlIncludeCreoApproach(e.target.checked), size: "small" }), label: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
106405
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2" }, "\u041F\u043E\u0434\u0445\u043E\u0434 \u043A \u043A\u0440\u0435\u043E \u0432 URL \u043A\u0430\u0442\u0430\u043B\u043E\u0433\u0430"),
106406
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435 \u2014 \u043D\u043E\u043C\u0435\u0440 N \u0438\u0437 \u0438\u043C\u0435\u043D\u0438 \u0444\u0430\u0439\u043B\u0430 N_xxxxxxxx.png \u043D\u0430 Drive (N = \u0441\u0442\u0440\u043E\u043A\u0430 \u043F\u043E\u0434\u0445\u043E\u0434\u0430 \u043A \u043A\u0440\u0435\u043E, 1\u201310); \u00AB (1)\u00BB \u043E\u0442 \u0434\u0443\u0431\u043B\u0438\u043A\u0430\u0442\u0430 Google \u0441\u043D\u0438\u043C\u0430\u0435\u0442\u0441\u044F")), sx: { alignItems: 'flex-start', mr: 0, flex: { sm: '1 1 200px' }, minWidth: 0 } }),
106407
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 \u0434\u043B\u044F \u043A\u0440\u0435\u043E", size: "small", value: catalogUrlCreoApproachParam, onChange: e => setCatalogUrlCreoApproachParam(e.target.value), placeholder: DEFAULT_CATALOG_CREO_APPROACH_PARAM, sx: { width: { xs: '100%', sm: 200 }, flexShrink: 0 }, helperText: `По умолчанию: ${DEFAULT_CATALOG_CREO_APPROACH_PARAM}` }))),
105925
106408
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
105926
106409
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "h6", gutterBottom: true }, "AI Generation Settings"),
105927
106410
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
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 } })),
106411
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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 } })),
105929
106412
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
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" }),
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" },
106413
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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" }),
106414
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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: {
106415
+ endAdornment: (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_23__["default"], { position: "end" },
105933
106416
  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)" },
106417
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["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
106418
  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
106419
  const n = extractLeadingPriceNumber(generatePriceWithCurrency);
105937
106420
  setGeneratePriceWithCurrency(`$${n}`);
105938
106421
  }, 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)" },
106422
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_39__["default"], { sx: { fontSize: 20 } }))),
106423
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["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
106424
  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
106425
  const n = extractLeadingPriceNumber(generatePriceWithCurrency);
105943
106426
  setGeneratePriceWithCurrency(`€${n}`);
105944
106427
  }, 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)" },
106428
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["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
106429
  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
106430
  const n = extractLeadingPriceNumber(generatePriceWithCurrency);
105948
106431
  setGeneratePriceWithCurrency(`${n} zł`);
105949
106432
  }, edge: "end", sx: { minWidth: 36, fontSize: '0.8rem', fontWeight: 700, letterSpacing: -0.3 } }, "z\u0142"))))),
105950
106433
  } })),
105951
106434
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], null,
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 } })),
106435
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["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 } })),
105953
106436
  openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
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 },
106437
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { fullWidth: true, variant: "outlined" },
106438
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["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"),
106439
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["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_28__["default"], { disabled: true },
105957
106440
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
105958
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }),
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))))),
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
106441
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }),
106442
+ 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_28__["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_28__["default"], { key: model.id, value: model.id }, model.name))))),
106443
+ !loadingImageModels && imageModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, selectedImageModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.imageGeneration
105961
106444
  ? 'Используется модель по умолчанию'
105962
106445
  : 'Выбрана модель: ' + (imageModels.find(m => m.id === selectedImageModel)?.name || selectedImageModel)))),
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 },
106446
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_25__["default"], { fullWidth: true, variant: "outlined" },
106447
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_26__["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"),
106448
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_27__["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_28__["default"], { disabled: true },
105966
106449
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
105967
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }),
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))))),
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
106450
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }),
106451
+ 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_28__["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_28__["default"], { key: model.id, value: model.id }, model.name))))),
106452
+ !loadingValidationModels && validationModels.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_13__["default"], null, selectedValidationModel === _models__WEBPACK_IMPORTED_MODULE_2__.MODELS.creativeValidation
105970
106453
  ? 'Используется модель по умолчанию'
105971
106454
  : 'Выбрана модель: ' + (validationModels.find(m => m.id === selectedValidationModel)?.name || selectedValidationModel))),
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 } })))),
106455
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_21__["default"], { control: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["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 } })))),
105973
106456
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
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'),
106457
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "primary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: handleGenerateContent, disabled: generating || loadingContentFromDrive || !openaiApiKey || !generateProduct.trim() || !generateGeo.trim(), sx: { flexGrow: 1 }, size: "large" }, generating ? 'Generating...' : 'Generate Titles & Descriptions'),
105975
106458
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, alignItems: "center", sx: { flexGrow: 1 } },
105976
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: imageAspectRatio === '1:1'
106459
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: imageAspectRatio === '1:1'
105977
106460
  ? '1:1 — квадрат (1024×1024 px)'
105978
106461
  : imageAspectRatio === '2:3'
105979
106462
  ? '2:3 — портрет (1024×1536 px)'
@@ -105998,7 +106481,7 @@ ${imageData.originalPrompt}
105998
106481
  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
106482
  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
106483
  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 ||
106484
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: handleGenerateImages, disabled: generatingImages ||
106002
106485
  !openaiApiKey ||
106003
106486
  (!accessToken && !refreshToken) ||
106004
106487
  !generateProduct.trim() ||
@@ -106016,9 +106499,9 @@ ${imageData.originalPrompt}
106016
106499
  : !driveFolderUrl.trim()
106017
106500
  ? 'Заполните URL папки Google Drive'
106018
106501
  : undefined }, generatingImages ? 'Generating Images...' : 'Generate Images')),
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'),
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 } },
106021
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], { fontSize: "small" })) },
106502
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["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_14__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), sx: { py: 1.5, fontSize: '1.1rem', flexGrow: 1 } }, loading ? 'Generating...' : 'Generate Catalog'),
106503
+ uploadedLink && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["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 } },
106504
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], { fontSize: "small" })) },
106022
106505
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, flexWrap: 'wrap' } },
106023
106506
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
106024
106507
  "\u041A\u0430\u0442\u0430\u043B\u043E\u0433 \u0437\u0430\u0433\u0440\u0443\u0436\u0435\u043D!",
@@ -106028,17 +106511,17 @@ ${imageData.originalPrompt}
106028
106511
  getElectronAPI().openExternal(uploadedLink);
106029
106512
  }, style: { cursor: 'pointer', textDecoration: 'underline', color: 'inherit' } }, "\u041E\u0442\u043A\u0440\u044B\u0442\u044C \u0432 Google Drive")),
106030
106513
  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!"))))),
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\".")),
106514
+ folderFilesInfo !== null && !folderFilesInfo.hasProduct && driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["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\".")),
106032
106515
  !generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
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")),
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")),
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")),
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")),
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"))))),
106516
+ !openaiApiKey && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 OpenRouter API Key")),
106517
+ openaiApiKey && (!accessToken && !refreshToken) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0412\u043E\u0439\u0434\u0438\u0442\u0435 \u0432 Google Drive")),
106518
+ openaiApiKey && (accessToken || refreshToken) && !generateProduct.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0422\u043E\u0432\u0430\u0440")),
106519
+ openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && !generateGeo.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 \u043F\u043E\u043B\u0435 \u0413\u0435\u043E")),
106520
+ openaiApiKey && (accessToken || refreshToken) && generateProduct.trim() && generateGeo.trim() && !driveFolderUrl.trim() && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { severity: "error", sx: { mt: 1 } }, "\u0417\u0430\u043F\u043E\u043B\u043D\u0438\u0442\u0435 URL \u043F\u0430\u043F\u043A\u0438 Google Drive"))))),
106038
106521
  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 }),
106039
106522
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 2, sx: { mb: 2 } },
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 ||
106523
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "success", startIcon: uploadingProduct ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), onClick: handleUploadProductFile, disabled: uploadingProduct || !accessToken || !driveFolderUrl.trim(), sx: { flexGrow: 1 }, size: "large" }, uploadingProduct ? 'Загрузка...' : 'Загрузить product.png/jpg/webp'),
106524
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", color: "info", startIcon: generatingLanding ? react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20, color: "inherit" }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_50__["default"], null), onClick: handleCreateLanding, disabled: generatingLanding ||
106042
106525
  !openaiApiKey ||
106043
106526
  !accessToken ||
106044
106527
  !driveFolderUrl.trim() ||
@@ -106053,10 +106536,10 @@ ${imageData.originalPrompt}
106053
106536
  generatedImagesData.length,
106054
106537
  ")"),
106055
106538
  checkingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
106056
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16 }),
106539
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16 }),
106057
106540
  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
106541
  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})`))),
106542
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["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_14__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))),
106060
106543
  generatedImagesData.length > 0 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
106061
106544
  display: 'grid',
106062
106545
  gridTemplateColumns: { xs: '1fr', sm: 'repeat(2, 1fr)', md: 'repeat(3, 1fr)' },
@@ -106065,8 +106548,20 @@ ${imageData.originalPrompt}
106065
106548
  } }, generatedImagesData.map((imageData) => {
106066
106549
  const imgRatio = imageData.aspectRatio ?? (imageAspectRatio === 'both' ? '1:1' : imageAspectRatio);
106067
106550
  const aspectRatioCss = imgRatio === '2:3' ? '2 / 3' : '1 / 1';
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" },
106551
+ const remakeN = imageData.remakeCount ?? 0;
106552
+ const remakeBg = getRemakeHighlightBackground(remakeN, darkMode);
106553
+ return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { key: imageData.index, sx: {
106554
+ position: 'relative',
106555
+ ...(remakeBg
106556
+ ? {
106557
+ p: 1,
106558
+ borderRadius: 1,
106559
+ bgcolor: remakeBg,
106560
+ boxSizing: 'border-box'
106561
+ }
106562
+ : {})
106563
+ } },
106564
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043A\u0440\u0435\u0430\u0442\u0438\u0432" },
106070
106565
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
106071
106566
  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
106567
  position: 'absolute',
@@ -106093,7 +106588,7 @@ ${imageData.originalPrompt}
106093
106588
  imageData.generating ||
106094
106589
  !!imageData.regenerating ||
106095
106590
  !!imageData.uploading },
106096
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_42__["default"], { fontSize: "small" })))),
106591
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], { fontSize: "small" })))),
106097
106592
  imageData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
106098
106593
  width: '100%',
106099
106594
  aspectRatio: aspectRatioCss,
@@ -106109,7 +106604,7 @@ ${imageData.originalPrompt}
106109
106604
  gap: 2,
106110
106605
  p: 3
106111
106606
  } },
106112
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
106607
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
106113
106608
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary', textAlign: 'center', fontWeight: 'bold' } }, "\u0413\u0435\u043D\u0435\u0440\u0430\u0446\u0438\u044F..."),
106114
106609
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } }, imageData.approach),
106115
106610
  generatingImages && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', textAlign: 'center' } },
@@ -106129,7 +106624,7 @@ ${imageData.originalPrompt}
106129
106624
  gap: 2,
106130
106625
  p: 3
106131
106626
  } },
106132
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
106627
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
106133
106628
  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
106629
  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,
106135
106630
  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: {
@@ -106164,7 +106659,7 @@ ${imageData.originalPrompt}
106164
106659
  alignItems: 'center',
106165
106660
  gap: 1
106166
106661
  } },
106167
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
106662
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
106168
106663
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'white', fontWeight: 'bold', textShadow: '1px 1px 2px rgba(0,0,0,0.8)' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0430..."))))) : imageData.failed ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
106169
106664
  width: '100%',
106170
106665
  aspectRatio: aspectRatioCss,
@@ -106225,14 +106720,13 @@ ${imageData.originalPrompt}
106225
106720
  imageData.checkErrors.length > 2 && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'text.secondary', fontSize: '0.7rem' } },
106226
106721
  "+",
106227
106722
  imageData.checkErrors.length - 2,
106228
- " \u0435\u0449\u0451")))),
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")))),
106723
+ " \u0435\u0449\u0451")))))),
106230
106724
  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...")),
106231
106725
  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")),
106232
106726
  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")),
106233
106727
  imageData.uploaded && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { color: 'success.main', display: 'block', mt: 0.5 } }, "\u2713 \u0417\u0430\u0433\u0440\u0443\u0436\u0435\u043D\u043E"))),
106234
106728
  !imageData.generating && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', gap: 1, flexDirection: 'column', mt: 1 } },
106235
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_15__["default"], { size: "small", multiline: true, minRows: 2, maxRows: 4, fullWidth: true, placeholder: "\u0423\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0438 (\u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u043F\u0440\u0438 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430\u0445)", value: imageData.customRegeneratePrompt || '', onChange: (e) => {
106729
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { size: "small", multiline: true, minRows: 2, maxRows: 4, fullWidth: true, placeholder: "\u0423\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u044F \u0434\u043B\u044F \u043F\u0435\u0440\u0435\u0434\u0435\u043B\u043A\u0438 (\u0430\u0432\u0442\u043E\u043C\u0430\u0442\u0438\u0447\u0435\u0441\u043A\u0438 \u0437\u0430\u043F\u043E\u043B\u043D\u0435\u043D\u043E \u043F\u0440\u0438 \u043F\u0440\u043E\u0431\u043B\u0435\u043C\u0430\u0445)", value: imageData.customRegeneratePrompt || '', onChange: (e) => {
106236
106730
  setGeneratedImagesData(prev => prev.map(img => img.index === imageData.index
106237
106731
  ? { ...img, customRegeneratePrompt: e.target.value }
106238
106732
  : img));
@@ -106249,22 +106743,27 @@ ${imageData.originalPrompt}
106249
106743
  : 'transparent'
106250
106744
  }
106251
106745
  } }),
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 ||
106253
- imageData.uploading ||
106254
- imageData.checkStatus === 'checking' ||
106255
- !imageData.originalPrompt ||
106256
- !imageData.productImageUrl ||
106257
- (generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating), fullWidth: true }, imageData.regenerating
106258
- ? (imageData.failed ? 'Генерация...' : 'Переделка...')
106259
- : ((generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating)
106260
- ? очереди'
106261
- : (!imageData.imageUrl ? 'Сгенерировать' : 'Переделать'))),
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 ||
106746
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: "row", spacing: 1, sx: { width: '100%', alignItems: 'stretch' } },
106747
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["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_14__["default"], { size: 16 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_40__["default"], null), onClick: () => handleRegenerateImage(imageData), disabled: imageData.regenerating ||
106748
+ imageData.uploading ||
106749
+ imageData.checkStatus === 'checking' ||
106750
+ !imageData.originalPrompt ||
106751
+ !imageData.productImageUrl ||
106752
+ (generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating), sx: { flex: 1, minWidth: 0, py: 1, lineHeight: 1.2, whiteSpace: 'normal' } }, imageData.regenerating
106753
+ ? (imageData.failed ? 'Генерация...' : 'Переделка...')
106754
+ : ((generatingImages && !imageData.imageUrl && !imageData.failed && !imageData.generating)
106755
+ ? 'В очереди'
106756
+ : (!imageData.imageUrl ? 'Сгенерировать' : 'Переделать'))),
106757
+ imageData.imageUrl ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", color: "secondary", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null), onClick: () => handleRegenerateImageFresh(imageData), disabled: imageData.regenerating ||
106758
+ imageData.uploading ||
106759
+ imageData.checkStatus === 'checking' ||
106760
+ !imageData.originalPrompt ||
106761
+ !imageData.productImageUrl, sx: { flex: 1, minWidth: 0, py: 1, lineHeight: 1.2, whiteSpace: 'normal' } }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u043D\u043E\u0432\u043E")) : null),
106762
+ imageData.imageUrl && !validationDisabled && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", color: "warning", startIcon: imageData.checkStatus === 'checking' ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16, color: "inherit" })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_51__["default"], null)), onClick: () => handleRetryCheck(imageData), disabled: imageData.regenerating ||
106263
106763
  imageData.uploading ||
106264
- imageData.checkStatus === 'checking' ||
106265
- !imageData.originalPrompt ||
106266
- !imageData.productImageUrl, fullWidth: true }, "\u041F\u0435\u0440\u0435\u0434\u0435\u043B\u0430\u0442\u044C \u0437\u0430\u043D\u043E\u0432\u043E")),
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: () => {
106764
+ imageData.generating ||
106765
+ imageData.checkStatus === 'checking', fullWidth: true }, imageData.checkStatus === 'checking' ? 'Проверка…' : 'Перепроверить')),
106766
+ !imageData.uploaded && imageData.imageUrl && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { size: "small", variant: "outlined", startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), onClick: () => {
106268
106767
  const folderId = extractFolderId(driveFolderUrl);
106269
106768
  if (folderId) {
106270
106769
  handleUploadImage(imageData, folderId);
@@ -106272,7 +106771,7 @@ ${imageData.originalPrompt}
106272
106771
  }, disabled: imageData.uploading || imageData.regenerating || !driveFolderUrl.trim(), fullWidth: true }, imageData.uploading ? 'Загрузка...' : 'Загрузить'))))));
106273
106772
  }))),
106274
106773
  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 } },
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})`))))),
106774
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["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_14__["default"], { size: 20 }) : react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], null), fullWidth: true }, uploadingImages ? 'Загрузка...' : `Загрузить все (${generatedImagesData.filter(img => !img.uploaded && img.imageUrl).length})`))))),
106276
106775
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_16__["default"], { sx: { my: 2 } }),
106277
106776
  (generatedTitlesData.length > 0 || generatedTextsData.length > 0 || loadingContentFromDrive) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
106278
106777
  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 } },
@@ -106282,14 +106781,14 @@ ${imageData.originalPrompt}
106282
106781
  "/",
106283
106782
  Math.max(generatedTitlesData.length, generatedTextsData.length),
106284
106783
  ")"),
106285
- (generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_22__["default"], { title: pairsJsonCopied ? 'Скопировано' : 'Скопировать все пары как JSON-массив' },
106784
+ (generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: pairsJsonCopied ? 'Скопировано' : 'Скопировать все пары как JSON-массив' },
106286
106785
  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
106786
  opacity: 0.28,
106288
106787
  p: 0.35,
106289
106788
  color: 'text.secondary',
106290
106789
  '&:hover': { opacity: 0.75, color: 'text.primary' },
106291
106790
  } },
106292
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_41__["default"], { sx: { fontSize: 16 } }))))),
106791
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_45__["default"], { sx: { fontSize: 16 } }))))),
106293
106792
  loadingContentFromDrive && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: {
106294
106793
  display: 'flex',
106295
106794
  flexDirection: 'column',
@@ -106304,7 +106803,7 @@ ${imageData.originalPrompt}
106304
106803
  : 'rgba(25, 118, 210, 0.05)',
106305
106804
  mb: 2
106306
106805
  } },
106307
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 40, sx: { color: 'primary.main' } }),
106806
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 40, sx: { color: 'primary.main' } }),
106308
106807
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body1", sx: { color: 'text.secondary', fontWeight: 'bold' } }, "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043A\u043E\u043D\u0442\u0435\u043D\u0442\u0430 \u0438\u0437 Google Drive..."))),
106309
106808
  (generatedTitlesData.length > 0 || generatedTextsData.length > 0) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 }, Array.from({
106310
106809
  length: Math.max(generatedTitlesData.length, generatedTextsData.length)
@@ -106345,82 +106844,96 @@ ${imageData.originalPrompt}
106345
106844
  i + 1),
106346
106845
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary" }, pairLabel),
106347
106846
  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" },
106847
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_24__["default"], { title: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u043F\u0430\u0440\u0443" },
106349
106848
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("span", null,
106350
106849
  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,
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:"),
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),
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:"),
106356
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", sx: { display: 'block' } }, pairTranslations[i].textRu)), placement: "right", arrow: true, componentsProps: {
106357
- tooltip: { sx: { maxWidth: 360, fontSize: 12, lineHeight: 1.6, p: '10px 14px' } },
106358
- } },
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' } } },
106360
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_44__["default"], { sx: { fontSize: 14 } })))) : null),
106850
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_46__["default"], { fontSize: "small" })))),
106851
+ translatingPairs && !pairTranslations[i] ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 13, sx: { color: 'text.disabled', ml: 0.5 } })) : null),
106361
106852
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 1.5 },
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 } },
106363
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16, sx: { color: 'primary.main' } }),
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) => {
106380
- const newValue = e.target.value;
106381
- setGeneratedTitlesData(prev => {
106382
- const updated = prev.map(t => t.index === titleData.index ? { ...t, title: newValue } : t);
106383
- setTitles(updated.map(t => t.title).filter(Boolean).join('\n'));
106384
- return updated;
106385
- });
106386
- }, sx: {
106387
- '& .MuiInputBase-root': {
106388
- backgroundColor: (theme) => theme.palette.mode === 'dark'
106389
- ? 'rgba(76,175,80,0.08)'
106390
- : 'rgba(76,175,80,0.04)'
106391
- }
106392
- } }))),
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 } },
106394
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 16, sx: { color: 'primary.main' } }),
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) => {
106411
- const newValue = e.target.value;
106412
- setGeneratedTextsData(prev => {
106413
- const updated = prev.map(t => t.index === textData.index ? { ...t, text: newValue } : t);
106414
- setTexts(updated.map(t => t.text).filter(Boolean));
106415
- return updated;
106416
- });
106417
- }, sx: {
106418
- '& .MuiInputBase-root': {
106419
- backgroundColor: (theme) => theme.palette.mode === 'dark'
106420
- ? 'rgba(76,175,80,0.08)'
106421
- : 'rgba(76,175,80,0.04)'
106422
- }
106423
- } }))))));
106853
+ titleData && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
106854
+ titleData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
106855
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16, sx: { color: 'primary.main' } }),
106856
+ 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_12__["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) => {
106857
+ const newValue = e.target.value;
106858
+ setGeneratedTitlesData(prev => {
106859
+ const updated = prev.map(t => t.index === titleData.index
106860
+ ? { ...t, title: newValue, failed: false, errorMessage: undefined }
106861
+ : t);
106862
+ setTitles(updated.map(t => t.title).filter(Boolean).join('\n'));
106863
+ return updated;
106864
+ });
106865
+ }, sx: {
106866
+ '& .MuiInputBase-root': {
106867
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106868
+ ? 'rgba(244,67,54,0.08)'
106869
+ : 'rgba(244,67,54,0.04)'
106870
+ }
106871
+ } })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: `Заголовок ${i + 1}`, variant: "outlined", fullWidth: true, size: "small", value: titleData.title, onChange: (e) => {
106872
+ const newValue = e.target.value;
106873
+ setGeneratedTitlesData(prev => {
106874
+ const updated = prev.map(t => t.index === titleData.index ? { ...t, title: newValue } : t);
106875
+ setTitles(updated.map(t => t.title).filter(Boolean).join('\n'));
106876
+ return updated;
106877
+ });
106878
+ }, sx: {
106879
+ '& .MuiInputBase-root': {
106880
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106881
+ ? 'rgba(76,175,80,0.08)'
106882
+ : 'rgba(76,175,80,0.04)'
106883
+ }
106884
+ } })),
106885
+ !titleData.generating && pairTranslations[i]?.titleRu?.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "div", variant: "caption", sx: {
106886
+ mt: -0.5,
106887
+ pl: 1.5,
106888
+ pr: 1,
106889
+ fontSize: '0.7rem',
106890
+ lineHeight: 1.45,
106891
+ color: 'text.secondary',
106892
+ opacity: 0.92,
106893
+ } }, pairTranslations[i].titleRu)) : null)),
106894
+ textData && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
106895
+ textData.generating ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
106896
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 16, sx: { color: 'primary.main' } }),
106897
+ 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_12__["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) => {
106898
+ const newValue = e.target.value;
106899
+ setGeneratedTextsData(prev => {
106900
+ const updated = prev.map(t => t.index === textData.index
106901
+ ? { ...t, text: newValue, failed: false, errorMessage: undefined }
106902
+ : t);
106903
+ setTexts(updated.map(t => t.text));
106904
+ return updated;
106905
+ });
106906
+ }, sx: {
106907
+ '& .MuiInputBase-root': {
106908
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106909
+ ? 'rgba(244,67,54,0.08)'
106910
+ : 'rgba(244,67,54,0.04)'
106911
+ }
106912
+ } })) : (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_12__["default"], { label: `Текст ${i + 1}`, variant: "outlined", fullWidth: true, multiline: true, minRows: 3, value: textData.text, onChange: (e) => {
106913
+ const newValue = e.target.value;
106914
+ setGeneratedTextsData(prev => {
106915
+ const updated = prev.map(t => t.index === textData.index ? { ...t, text: newValue } : t);
106916
+ setTexts(updated.map(t => t.text).filter(Boolean));
106917
+ return updated;
106918
+ });
106919
+ }, sx: {
106920
+ '& .MuiInputBase-root': {
106921
+ backgroundColor: (theme) => theme.palette.mode === 'dark'
106922
+ ? 'rgba(76,175,80,0.08)'
106923
+ : 'rgba(76,175,80,0.04)'
106924
+ }
106925
+ } })),
106926
+ !textData.generating && pairTranslations[i]?.textRu?.trim() ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { component: "div", variant: "caption", sx: {
106927
+ mt: -0.25,
106928
+ pl: 1.5,
106929
+ pr: 1,
106930
+ fontSize: '0.7rem',
106931
+ lineHeight: 1.45,
106932
+ color: 'text.secondary',
106933
+ opacity: 0.92,
106934
+ whiteSpace: 'pre-wrap',
106935
+ wordBreak: 'break-word',
106936
+ } }, pairTranslations[i].textRu)) : null)))));
106424
106937
  }))))),
106425
106938
  (landingGenerationLogs.length > 0 || generatingLanding) && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { mb: 2 } },
106426
106939
  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"),
@@ -106448,10 +106961,38 @@ ${imageData.originalPrompt}
106448
106961
  'text.primary'
106449
106962
  } }, log)))))),
106450
106963
  generatingLanding && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { sx: { display: 'flex', alignItems: 'center', gap: 1, mb: 2 } },
106451
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_18__["default"], { size: 20 }),
106964
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_14__["default"], { size: 20 }),
106452
106965
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", sx: { color: 'text.secondary' } }, formatElapsedTime(elapsedTime.landing)))),
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) }))));
106966
+ !generatingLanding && generatedLandingHTML && generatedLandingImageBlob && (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "outlined", color: "primary", onClick: handlePreviewLanding, startIcon: react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_icons_material__WEBPACK_IMPORTED_MODULE_53__["default"], null), fullWidth: true }, "\u041F\u0440\u0435\u0434\u043F\u0440\u043E\u0441\u043C\u043E\u0442\u0440 \u043B\u0435\u043D\u0434\u0438\u043D\u0433\u0430"))))))))),
106967
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_32__["default"], { open: approachLoadChoice !== null, onClose: handleApproachLoadKeepCurrent, maxWidth: "md", fullWidth: true }, approachLoadChoice ? (react__WEBPACK_IMPORTED_MODULE_0___default().createElement((react__WEBPACK_IMPORTED_MODULE_0___default().Fragment), null,
106968
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_33__["default"], null, "\u041F\u043E\u0434\u0445\u043E\u0434\u044B \u0438\u0437 \u0444\u0430\u0439\u043B\u0430 \u043E\u0444\u0444\u0435\u0440\u0430"),
106969
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_34__["default"], null,
106970
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", color: "text.secondary", sx: { mb: 2 } }, "\u0412 project-settings.json \u0435\u0441\u0442\u044C \u0441\u043E\u0445\u0440\u0430\u043D\u0451\u043D\u043D\u044B\u0435 \u043F\u043E\u0434\u0445\u043E\u0434\u044B \u0434\u043B\u044F \u0437\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u043E\u0432/\u0442\u0435\u043A\u0441\u0442\u043E\u0432 \u0438 \u0434\u043B\u044F \u043A\u0440\u0435\u043E. \u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u0445 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438 \u0438\u043B\u0438 \u043E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u0442\u0435, \u0447\u0442\u043E \u0443\u0436\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u044B \u043B\u043E\u043A\u0430\u043B\u044C\u043D\u043E?"),
106971
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { spacing: 2 },
106972
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle2" }, "\u0417\u0430\u0433\u043E\u043B\u043E\u0432\u043A\u0438 \u0438 \u0442\u0435\u043A\u0441\u0442\u044B (\u043F\u0430\u0440\u044B \u043F\u043E\u0434\u0445\u043E\u0434\u043E\u0432)"),
106973
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
106974
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
106975
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438"),
106976
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, formatPairApproachesForDisplay(approachLoadChoice.currentPairs))),
106977
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
106978
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0412 \u0444\u0430\u0439\u043B\u0435 \u043E\u0444\u0444\u0435\u0440\u0430"),
106979
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, approachLoadChoice.savedPairs
106980
+ ? formatPairApproachesForDisplay(approachLoadChoice.savedPairs)
106981
+ : '— не указано (список для текстов не изменится)'))),
106982
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "subtitle2" }, "\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F (\u043A\u043E\u043B\u0438\u0447\u0435\u0441\u0442\u0432\u043E \u043F\u043E \u043F\u043E\u0434\u0445\u043E\u0434\u0443)"),
106983
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_11__["default"], { direction: { xs: 'column', sm: 'row' }, spacing: 2 },
106984
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
106985
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0421\u0435\u0439\u0447\u0430\u0441 \u0432 \u043F\u0440\u0438\u043B\u043E\u0436\u0435\u043D\u0438\u0438"),
106986
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, formatImageCountsForDisplay(approachLoadChoice.currentCounts))),
106987
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_31__["default"], { variant: "outlined", sx: { p: 1.5, flex: 1 } },
106988
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "caption", color: "text.secondary", display: "block", gutterBottom: true }, "\u0412 \u0444\u0430\u0439\u043B\u0435 \u043E\u0444\u0444\u0435\u0440\u0430"),
106989
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_6__["default"], { variant: "body2", component: "div", sx: { whiteSpace: 'pre-wrap', fontFamily: 'inherit' } }, approachLoadChoice.savedCounts
106990
+ ? formatImageCountsForDisplay(approachLoadChoice.savedCounts)
106991
+ : '— не указано (количества крео не изменятся)'))))),
106992
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_35__["default"], null,
106993
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { onClick: handleApproachLoadKeepCurrent }, "\u041E\u0441\u0442\u0430\u0432\u0438\u0442\u044C \u043A\u0430\u043A \u0441\u0435\u0439\u0447\u0430\u0441"),
106994
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_20__["default"], { variant: "contained", onClick: handleApproachLoadApplyFromFile }, "\u041F\u0440\u0438\u043C\u0435\u043D\u0438\u0442\u044C \u0438\u0437 \u0444\u0430\u0439\u043B\u0430")))) : null),
106995
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_PromptManagerDialog__WEBPACK_IMPORTED_MODULE_54__["default"], { open: promptManagerOpen, onClose: () => setPromptManagerOpen(false) }))));
106455
106996
  }
106456
106997
  /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (App);
106457
106998
 
@@ -107259,7 +107800,14 @@ function PromptManagerDialog({ open, onClose }) {
107259
107800
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(_mui_material__WEBPACK_IMPORTED_MODULE_5__["default"], { type: "number", size: "small", value: count, onChange: (e) => {
107260
107801
  const v = parseInt(e.target.value, 10);
107261
107802
  handleImageApproachCountChange(i, isNaN(v) ? 0 : v);
107262
- }, onBlur: handleImageCountBlur, inputProps: { min: 0, max: 4, step: 1 }, sx: { width: 56, '& .MuiInputBase-input': { textAlign: 'center', py: 0.5 } } })),
107803
+ }, onBlur: handleImageCountBlur, inputProps: {
107804
+ min: 0,
107805
+ max: 4,
107806
+ step: 1,
107807
+ onWheel: (e) => {
107808
+ e.preventDefault();
107809
+ },
107810
+ }, sx: { width: 56, '& .MuiInputBase-input': { textAlign: 'center', py: 0.5 } } })),
107263
107811
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', fontWeight: 500, whiteSpace: 'nowrap' } }, approach.name),
107264
107812
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement("td", { style: { padding: '4px 8px', color: '#777' } }, approach.prompt.split('\n')[0])));
107265
107813
  }))))),
@@ -107540,6 +108088,7 @@ __webpack_require__.r(__webpack_exports__);
107540
108088
  /* harmony export */ PRODUCT_TYPE_IMAGE_PRESETS: () => (/* binding */ PRODUCT_TYPE_IMAGE_PRESETS),
107541
108089
  /* harmony export */ PRODUCT_TYPE_TEXT_PAIR_PRESETS: () => (/* binding */ PRODUCT_TYPE_TEXT_PAIR_PRESETS),
107542
108090
  /* harmony export */ PROMPT_OVERRIDES_SAVED_EVENT: () => (/* binding */ PROMPT_OVERRIDES_SAVED_EVENT),
108091
+ /* harmony export */ applyParsedApproachesFromDrive: () => (/* binding */ applyParsedApproachesFromDrive),
107543
108092
  /* harmony export */ getCreoApproachOverride: () => (/* binding */ getCreoApproachOverride),
107544
108093
  /* harmony export */ getImageApproachCounts: () => (/* binding */ getImageApproachCounts),
107545
108094
  /* harmony export */ getPairsCount: () => (/* binding */ getPairsCount),
@@ -107550,6 +108099,7 @@ __webpack_require__.r(__webpack_exports__);
107550
108099
  /* harmony export */ mergePromptApproachesFromDriveFile: () => (/* binding */ mergePromptApproachesFromDriveFile),
107551
108100
  /* harmony export */ normalizeImageApproachCountsFromDrive: () => (/* binding */ normalizeImageApproachCountsFromDrive),
107552
108101
  /* harmony export */ normalizeSelectedPairApproachesFromDrive: () => (/* binding */ normalizeSelectedPairApproachesFromDrive),
108102
+ /* harmony export */ parseApproachesFromDriveData: () => (/* binding */ parseApproachesFromDriveData),
107553
108103
  /* harmony export */ productPresetNumbersToImageCounts: () => (/* binding */ productPresetNumbersToImageCounts),
107554
108104
  /* harmony export */ productPresetNumbersToIndices: () => (/* binding */ productPresetNumbersToIndices),
107555
108105
  /* harmony export */ resetAllOverrides: () => (/* binding */ resetAllOverrides),
@@ -107735,12 +108285,17 @@ function savePromptOverrides(overrides) {
107735
108285
  }
107736
108286
  /** Имя события после сохранения подходов в менеджере промптов — чтобы синхронизировать JSON на Drive. */
107737
108287
  const PROMPT_OVERRIDES_SAVED_EVENT = 'docs-combiner-prompt-overrides-saved';
108288
+ /** Прочитать валидные подходы из объекта настроек с диска (без записи в localStorage). */
108289
+ function parseApproachesFromDriveData(loadedData) {
108290
+ return {
108291
+ pairs: normalizeSelectedPairApproachesFromDrive(loadedData.selectedPairApproaches),
108292
+ counts: normalizeImageApproachCountsFromDrive(loadedData.imageApproachCounts),
108293
+ };
108294
+ }
107738
108295
  /**
107739
- * Подмешать в localStorage выбранные подходы из project-settings.json на Drive (если поля валидны).
108296
+ * Применить к localStorage только те части, для которых переданы ненулевые массивы.
107740
108297
  */
107741
- function mergePromptApproachesFromDriveFile(loadedData) {
107742
- const pairs = normalizeSelectedPairApproachesFromDrive(loadedData.selectedPairApproaches);
107743
- const counts = normalizeImageApproachCountsFromDrive(loadedData.imageApproachCounts);
108298
+ function applyParsedApproachesFromDrive(pairs, counts) {
107744
108299
  if (!pairs && !counts)
107745
108300
  return false;
107746
108301
  const overrides = loadPromptOverrides();
@@ -107759,6 +108314,13 @@ function mergePromptApproachesFromDriveFile(loadedData) {
107759
108314
  }
107760
108315
  return false;
107761
108316
  }
108317
+ /**
108318
+ * Подмешать в localStorage выбранные подходы из project-settings.json на Drive (если поля валидны).
108319
+ */
108320
+ function mergePromptApproachesFromDriveFile(loadedData) {
108321
+ const { pairs, counts } = parseApproachesFromDriveData(loadedData);
108322
+ return applyParsedApproachesFromDrive(pairs, counts);
108323
+ }
107762
108324
  /**
107763
108325
  * Получить оверрайд для простого промпта
107764
108326
  */
@@ -107873,6 +108435,7 @@ __webpack_require__.r(__webpack_exports__);
107873
108435
  /* harmony export */ PAIR_APPROACH_POOL: () => (/* binding */ PAIR_APPROACH_POOL),
107874
108436
  /* harmony export */ TEXTS_APPROACH_POOL: () => (/* binding */ TEXTS_APPROACH_POOL),
107875
108437
  /* harmony export */ TITLES_APPROACH_POOL: () => (/* binding */ TITLES_APPROACH_POOL),
108438
+ /* harmony export */ getCreoApproachExpandedTasks: () => (/* binding */ getCreoApproachExpandedTasks),
107876
108439
  /* harmony export */ getCreoApproaches: () => (/* binding */ getCreoApproaches),
107877
108440
  /* harmony export */ getImageCheckPrompt: () => (/* binding */ getImageCheckPrompt),
107878
108441
  /* harmony export */ getImageGenerationBasePrompt: () => (/* binding */ getImageGenerationBasePrompt),
@@ -107953,57 +108516,57 @@ function _debugLog(...args) {
107953
108516
  const PAIR_APPROACH_POOL = [
107954
108517
  {
107955
108518
  name: 'болевая точка',
107956
- titleApproach: 'одна ясная боль (не две проблемы в одном заголовке). Усиливай через несправедливость / ощущение «так несправедливо» (устал бороться, снова срыв, тело не слушается) — не только сухое перечисление симптомов. ЗАГОЛОВОК = КОНСТАТАЦИЯ, не вопрос: ЗАПРЕЩЕНО заканчивать на «почему?», «perché?», «why?» и подобное — боль называешь фактом, не спрашиваешь',
108519
+ titleApproach: 'одна ясная боль (не две проблемы в одном заголовке). Усиливай через несправедливость / ощущение «так несправедливо» (устал бороться, снова срыв, тело не слушается) — не только сухое перечисление симптомов. ЗАГОЛОВОК = КОНСТАТАЦИЯ, не вопрос: ЗАПРЕЩЕНО заканчивать на «почему?», «зачем?», «why?» и подобное — боль называешь фактом, не спрашиваешь',
107957
108520
  textApproach: 'Одна центральная проблема за текст — не распыляйся на несколько болей. ЗАПРЕЩЕНО перечислять ингредиенты, состав, matcha/MCT/«формулу» — это территория «авторитет/экспертиза», не болевой точки. Опиши дискомфорт и как продукт снимает именно эту боль; без каталога компонентов.',
107958
108521
  },
107959
108522
  {
107960
108523
  name: 'трансформация до/после',
107961
- titleApproach: 'контраст СОСТОЯНИЙ и ощущений до/после (вздутие/усталость → лёгкость, тяжесть → контроль, «не узнаю себя в зеркале» → спокойствие) с якорем во времени во фразе, но БЕЗ цифр на весах. ЗАПРЕЩЕНО в заголовке: −X kg, «persi N kg», весы, любой явный минус килограммов — это только у testimonial',
107962
- textApproach: 'СТРОГО от первого лица («Я / Io / Yo…»). Это не отзыв с именем — это МОЙ контраст «как было плохо / как стало лучше» по телу и эмоциям. ЗАПРЕЩЕНО копировать формат отзыва: не начинай как реклама «я попробовала продукт и минус X кг» подряд; сначала ощущения и жизнь до/после, продукт — связка, а не пересказ цифр с весов (цифры веса допустимы в тексте лишь второстепенно, если уместно; акцент — на смене состояния). ЗАПРЕЩЕНО соцдоказательство («многие отмечают», «molte persone»).',
108524
+ titleApproach: 'контраст СОСТОЯНИЙ и ощущений до/после (вздутие/усталость → лёгкость, тяжесть → контроль, «не узнаю себя в зеркале» → спокойствие) с якорем во времени во фразе, но БЕЗ цифр на весах. ЗАПРЕЩЕНО в заголовке: −X kg, «минус N кг», весы, любой явный минус килограммов (для похудения такой акцент — только у testimonial и только если продукт явно про вес)',
108525
+ textApproach: 'СТРОГО от первого лица (на языке GEO естественное «я» для локали). Это не отзыв с именем — это МОЙ контраст «как было плохо / как стало лучше» по телу и эмоциям. ЗАПРЕЩЕНО копировать формат отзыва: не начинай как реклама «я попробовала продукт и минус X кг» подряд; сначала ощущения и жизнь до/после, продукт — связка, а не пересказ цифр с весов (цифры веса допустимы в тексте лишь второстепенно, если уместно; акцент — на смене состояния). ЗАПРЕЩЕНО соцдоказательство («многие отмечают», «тысячи уже выбрали» вместо личной истории).',
107963
108526
  },
107964
108527
  {
107965
108528
  name: 'testimonial',
107966
108529
  isTestimonial: true,
107967
- titleApproach: 'короткая «живая» фраза с конкретикой результата на весах/сроке («−2,8 kg in 10 giorni… incredibile 😅»)здесь УМЕСТНЫ −кг и срок; это отличает testimonial от «трансформации». НЕ используй «Имя, возраст:» в заголовке — только в тексте',
108530
+ titleApproach: 'короткая «живая» фраза с **конкретным результатом по теме продукта** и сроком (7–14 дней). Цифры −кг, весы, «минус на весах» **только** если продукт явно про похудение / контроль веса. Для паразитов/ЖКТ/суставов/простаты/сна и т.п. результат = облегчение симптомов, комфорт, сон, подвижность, меньше дискомфорта (без выдуманных кг). Это отличает testimonial от «трансформации». НЕ используй «Имя, возраст:» в заголовке — только в тексте',
107968
108531
  textApproach: `Это единственный подход-ОТЗЫВ: читатель должен поверить в реального человека.
107969
- * Обязательно начало текста с «Имя, возраст:» («Giulia, 49 anni:», «Kasia, 41 lat:»)
108532
+ * Обязательно начало текста с «Имя, возраст:» (формат на языке GEO, например «Анна, 49 лет:», «Олег, 41 год:»)
107970
108533
  * История только от первого лица после имени
107971
- * Конкретный результат с таймингом (7–14 дней), можно килограммы и детали быта
108534
+ * Конкретный результат с таймингом (7–14 дней), релевантный категории продукта; килограммы упоминай только если оффер действительно про вес/похудение
107972
108535
  * Заканчивается приглашением попробовать + CTA`,
107973
108536
  },
107974
108537
  {
107975
108538
  name: 'срочность/дефицит',
107976
108539
  titleApproach: 'ТОЛЬКО дефицит оффера: время до конкретного дедлайна, остаток штук, «до полуночи», «осталось N упаковок» — ЗАПРЕЩЕНО в заголовке проблема, тело, продукт, «лишние кг», категория товара. Не баннер магазина — конкретная граница (день, час, число мест)',
107977
- textApproach: 'Начни с конкретного сигнала ограниченности — времени или количества («Tylko dziś», «Últimas unidades», «Осталось 12 упаковок», «Акция до конца дня»). Весь текст строится ИСКЛЮЧИТЕЛЬНО вокруг дефицита или дедлайна: осталось мало, время заканчивается, потом будет дороже или не будет вообще. ЗАПРЕЩЕНО упоминать состав, ингредиенты, свойства или пользу продукта — только ограниченность оффера. CTA максимально срочный.',
108540
+ textApproach: 'Начни с конкретного сигнала ограниченности — времени или количества («только сегодня», «последние упаковки», «Осталось 12 упаковок», «Акция до конца дня» — всё на языке GEO). Весь текст строится ИСКЛЮЧИТЕЛЬНО вокруг дефицита или дедлайна: осталось мало, время заканчивается, потом будет дороже или не будет вообще. ЗАПРЕЩЕНО упоминать состав, ингредиенты, свойства или пользу продукта — только ограниченность оффера. CTA максимально срочный.',
107978
108541
  },
107979
108542
  {
107980
108543
  name: 'социальное доказательство',
107981
- titleApproach: 'одна ЧИТАЕМАЯ фраза с крупной цифрой (например «50.000 italiane hanno già scelto 🔥») — грамматика и смысл на языке GEO должны сходиться; читатель понимает фразу с первого раза. ЗАПРЕЩЕНО несвязные склейки («9 su 10 scelgono controllo 🔥 fame») и обрывки, где цифра + существительные не составляют нормального высказывания',
107982
- textApproach: 'Начни с цифры или массового факта («Уже 50 000 клиентов», «9 din 10 femei observă diferența»). Акцент на том, что проблему уже решили тысячи — и ты тоже можешь.',
108544
+ titleApproach: 'одна ЧИТАЕМАЯ фраза с крупной цифрой (уровень: «Уже 50 000 женщин выбрали 🔥» на языке GEO) — грамматика и смысл на языке GEO должны сходиться; читатель понимает фразу с первого раза. ЗАПРЕЩЕНО несвязные склейки («9 из 10 выбирают контроль 🔥 голод» — бессмыслица) и обрывки, где цифра + существительные не составляют нормального высказывания',
108545
+ textApproach: 'Начни с цифры или массового факта («Уже 50 000 клиентов», «9 из 10 отмечают разницу» — на языке GEO). Акцент на том, что проблему уже решили тысячи — и ты тоже можешь.',
107983
108546
  },
107984
108547
  {
107985
108548
  name: 'любопытство/интрига',
107986
- titleApproach: 'провокационный вопрос или утверждение, которое ломает сразу ДВА привычных решения (диета И спорт / dieta e palestra…), — но ОДНОЙ ЦЕЛЬНОЙ фразой: связный синтаксис, без рубки на обрывки через запятую и эмодзи посередине. Пример уровня: «Dieta e palestra ma la pancia resta? 🤔» — а не три оторванных куска',
107987
- textApproach: 'Начни с провокационного вопроса или неожиданного инсайта («Знаете, почему обычные средства не помогают?», «¿Sabías que…?»). Раскрой неочевидный факт о проблеме или механизме решения и выведи к продукту.',
108549
+ titleApproach: 'провокационный вопрос или утверждение, которое ломает сразу ДВА привычных решения (например диета и спорт одновременно) — но ОДНОЙ ЦЕЛЬНОЙ фразой: связный синтаксис, без рубки на обрывки через запятую и эмодзи посередине. Пример уровня на русском для тона: «Диета и зал, а живот всё равно? 🤔» — на GEO перепиши естественно; не три оторванных куска',
108550
+ textApproach: 'Начни с провокационного вопроса или неожиданного инсайта («Знаете, почему обычные средства не помогают?», «А вы знали, что…» — на языке GEO). Раскрой неочевидный факт о проблеме или механизме решения и выведи к продукту.',
107988
108551
  },
107989
108552
  {
107990
108553
  name: 'авторитет/экспертиза',
107991
- titleApproach: 'information gap: в заголовке ЗАПРЕЩЕНО называть ингредиенты и раскрывать метод/механизм напрямую — никаких matcha, MCT, verde, «formula con…», «metodo naturale per…», «accelerare il metabolismo», «supporta il metabolismo» и т.п.; иначе ответ уже в заголовке и клик не нужен. Подай состав или подход как тайну / открытие / «что скрывают» / «почему это не то же самое, что обычные средства» — без конкретики, ответ только в основном тексте. ЗАПРЕЩЕНЫ эмодзи-подсказки по составу (например 🍵, если по смыслу выдаёт чай), если они заменяют то, что должен открыть текст. Не закрывай интригу формулировками уровня «Perché X e Y supportano…»',
107992
- textApproach: 'Начни с ФАКТА/утверждения об экспертизе («Włoska receptura», «Hecho en Italia», «3 składniki naturalne», «Разработано фармацевтами»). Акцент на составе, происхождении или механизме действия. Почему это работает — объясни просто и убедительно.',
108554
+ titleApproach: 'information gap: в заголовке ЗАПРЕЩЕНО называть ингредиенты и раскрывать метод/механизм напрямую — никаких matcha, MCT, «зелёный чай», «формула с…», «натуральный метод для…», «ускорить обмен веществ», «поддерживает обмен веществ» и т.п.; иначе ответ уже в заголовке и клик не нужен. Подай состав или подход как тайну / открытие / «что скрывают» / «почему это не то же самое, что обычные средства» — без конкретики, ответ только в основном тексте. ЗАПРЕЩЕНЫ эмодзи-подсказки по составу (например 🍵, если по смыслу выдаёт чай), если они заменяют то, что должен открыть текст. Не закрывай интригу сухими схемами вроде «Почему X и Y поддерживают…»',
108555
+ textApproach: 'Начни с ФАКТА/утверждения об экспертизе («Итальянская рецептура», «Произведено в Италии», «3 натуральных компонента», «Разработано фармацевтами» — перенеси смысл на язык GEO). Акцент на составе, происхождении или механизме действия. Почему это работает — объясни просто и убедительно.',
107993
108556
  },
107994
108557
  {
107995
108558
  name: 'страх бездействия',
107996
- titleApproach: 'узнаваемый паттерн промедления — ОДНА СВЯЗНАЯ фраза (допустимы многоточие, союз «но», тире), а не перечень обрывков через запятую. Пример уровня: «Rimandi a lunedì… ma la fame non aspetta 😣» — смысл течёт от начала к концу',
107997
- textApproach: 'Начни с описания негативного сценария бездействия («С каждым днём становится хуже…», «Если не взять под контроль сейчас…»). Покажи, что проблема прогрессирует. Финальный CTA — ТОЛЬКО про заботу о себе / начать сейчас / не откладывать (на языке GEO). ЗАПРЕЩЕНЫ прямые призывы к заказу в финале: «ordina ora», «закажи», «купи сейчас», «clicca e acquista» — вместо них: взять под контроль, сделать первый шаг, начать сегодня и т.п.',
108559
+ titleApproach: 'узнаваемый паттерн промедления — ОДНА СВЯЗНАЯ фраза (допустимы многоточие, союз «но», тире), а не перечень обрывков через запятую. Пример уровня: «Отложила на понедельник… а голод не ждёт 😣» — на GEO перепиши естественно; смысл течёт от начала к концу',
108560
+ textApproach: 'Начни с описания негативного сценария бездействия («С каждым днём становится хуже…», «Если не взять под контроль сейчас…»). Покажи, что проблема прогрессирует. Финальный CTA — ТОЛЬКО про заботу о себе / начать сейчас / не откладывать (на языке GEO). ЗАПРЕЩЕНЫ прямые призывы к заказу в финале: «закажи», «закажи сейчас», «купи», «купи сейчас», «оформи заказ» — вместо них: взять под контроль, сделать первый шаг, начать сегодня и т.п.',
107998
108561
  },
107999
108562
  {
108000
108563
  name: 'прямой оффер/выгода',
108001
- titleApproach: 'конкретная числовая выгода в заголовке сколько экономишь или что получаешь (например «-50%», «Вторая упаковка бесплатно», «Цена как раньше»). НЕ просто «скидка есть» а ЧТО именно и сколько. ОБЯЗАТЕЛЬНО минимум один эмодзи в заголовке (💸 🔥 ✨ 🎁 ⏳ 📦 и т.п.) как у остальных подходов в наборе, без эмодзи заголовок считается ошибкой',
108002
- textApproach: 'Аудитория уже думает о покупке текст снимает последнее сомнение, а не убеждает в проблеме. Начни с оффера числом: скидка -50%, конкретная цена, что получаешь за эти деньги. Ответь на вопрос «почему взять сейчас, а не завтра» цена вырастет, акция закончится, запас ограничен. ЗАПРЕЩЕНО объяснять пользу продукта или описывать проблему читатель уже всё знает. Только сделка, только экономика, только CTA с акцентом на выгоде прямо сейчас.',
108564
+ titleApproach: 'выгода в заголовке = **-50%** как есть (знак процента), плюс по желанию 2–4 слова срочности на языке GEO («только сегодня», «сейчас»). ОБЯЗАТЕЛЬНО минимум один эмодзи (💸 🔥 ✨ 🎁 ⏳ 📦). **Не придумывай** другую механику: никаких «2-й пакет», «вторая упаковка», «полцены» вместо простого **-50%**, если в задании пользователя явно не сказано иначе. **-50% = просто -50%.**',
108565
+ textApproach: 'Коротко про сделку: **-50% не перефразируй** длинно («платишь половину», «акция на сегодня», «скидка на вторую упаковку»), если пользователь этого не писал повтори **-50%** и добавь одну короткую фразу срочности + CTA. ЗАПРЕЩЕНО расписывать математику скидки и выдумывать условия акции. ЗАПРЕЩЕНО объяснять пользу продукта или боли — только **-50%**, срочность, CTA.',
108003
108566
  },
108004
108567
  {
108005
108568
  name: 'ситуационный/узнаваемый момент',
108006
- titleApproach: 'одна яркая узнаваемая сцена в 1–2 коротких связных сегментах (лучше одна картинка), без перечня симптомов через запятую. Пример уровня: «Dopo pranzo i pantaloni tirano 😩» — сразу видно момент и боль; ЗАПРЕЩЕНО нагромождать «после обеда 😩 джинсы, живот, тесно» отдельными ярлыками',
108569
+ titleApproach: 'одна яркая узнаваемая сцена в 1–2 коротких связных сегментах (лучше одна картинка), без перечня симптомов через запятую. Пример уровня: «После обеда джинсы жмут 😩» — на GEO перепиши естественно; сразу видно момент и боль; ЗАПРЕЩЕНО нагромождать «после обеда 😩 джинсы, живот, тесно» отдельными ярлыками',
108007
108570
  textApproach: 'Начни с конкретной жизненной сцены, где проблема ощущается («[ключевой симптом категории продукта]…», «Вечером перед сном не можешь уснуть из-за дискомфорта…» — адаптируй под категорию). Создай узнаваемую ситуацию — читатель должен сказать «это про меня» — и предложи решение.',
108008
108571
  },
108009
108572
  ];
@@ -108120,7 +108683,7 @@ ${distributionLines}
108120
108683
 
108121
108684
  КРИТИЧНО — СРОК + ОФФЕР ДЛЯ КОНВЕРСИИ:
108122
108685
  ${deadlineNote}
108123
- - Опционально (не обязательно): усили CTA упоминанием оффера «-50 и ограниченности по времени («только сегодня/ограничено») — но коротко и только в конце текста.${hasTestimonial ? '' : ''}
108686
+ - Опционально (не обязательно): усили CTA упоминанием **-50%** как есть и ограниченности по времени («только сегодня/ограничено») — коротко, в конце; **не** заменяй -50% на «полцены», «вторая упаковка» и т.п., если это не в задании.${hasTestimonial ? '' : ''}
108124
108687
 
108125
108688
  Требования к стилю и тону:
108126
108689
  - Копия должна звучать как прямая реклама, а не как рассказ
@@ -108141,7 +108704,7 @@ ${deadlineNote}
108141
108704
  - КРИТИЧНО: Каждый текст должен содержать хотя бы одно ясное ключевое слово проблемы, релевантное категории продукта (например, для суставов: боль/скованность/подвижность; для пищеварения: дискомфорт/тяжесть; для сна: бессонница/усталость — примеры только для формата, адаптируй под категорию). Если ключевое слово проблемы отсутствует — перепиши текст
108142
108705
  - КРИТИЧНО: Каждый текст должен заканчиваться сильным и явным призывом к действию (кликни, попробуй сейчас, закажи сегодня, узнай больше и т.д.)
108143
108706
  - Избегай слабых окончаний или информационного тона. Слабые или нейтральные окончания не допускаются
108144
- - CTA должен быть “нажимным”: допускаются формулировки «не откладывай», «последний шанс», «только сегодня», «забери -50%» (всё строго на языке GEO)
108707
+ - CTA должен быть “нажимным”: допускаются формулировки «не откладывай», «последний шанс», «только сегодня», «забери -50%» (всё строго на языке GEO). Если пишешь скидку — **-50%** буквально, без выдуманной механики акции
108145
108708
  - В каждом тексте строго следуй заданному формату старта согласно его подходу (см. распределение выше)
108146
108709
  - Если ингредиенты предоставлены в дополнительной информации, упоминай их ТОЛЬКО если они естественно подходят выбранному рекламному подходу. Например: подходы авторитета/экспертизы выигрывают от деталей ингредиентов, в то время как подходы срочности/эмоционального триггера могут не нуждаться в них. Упоминай только релевантные ингредиенты, не обязательно все из них. Если ингредиенты не подходят подходу или не предоставлены — полностью пропусти их упоминание и не изобретай и не упоминай никакие ингредиенты
108147
108710
  - Добавляй только существенные поддерживающие детали, которые усиливают убеждение или ясность, а не заполнители или общие утверждения. Будь кратким и прямым
@@ -108154,7 +108717,7 @@ ${deadlineNote}
108154
108717
  - Разделяй разные тексты пустой строкой (двойной перевод строки)
108155
108718
  - КРИТИЧНО: Каждый текст ДОЛЖЕН быть многострочным с естественными переносами строк. Используй переносы строк для разделения предложений, выделения ключевых моментов или создания визуальной структуры. НЕ пиши описания как одиночные непрерывные строки
108156
108719
  - КРИТИЧНО: Все тексты ДОЛЖНЫ быть написаны на языке ${geo}. Используй точное название языка "${geo}" — не используй русский, английский или любой другой язык
108157
- - ВСЕ слова в тексте должны быть на языке GEO. Английские фразы вроде «Made in Italy», «Made in Germany» ЗАПРЕЩЕНЫ — используй перевод: «Wyprodukowano we Włoszech», «Hecho en Italia», «Fabricat în Italia» и т.д.
108720
+ - ВСЕ слова в тексте должны быть на языке GEO. Английские фразы вроде «Made in Italy», «Made in Germany» ЗАПРЕЩЕНЫ — используй перевод на язык GEO (например «Произведено в Италии», «Сделано в Германии» и аналоги).
108158
108721
  - После создания проверь их правильность И убедись в максимальном разнообразии между текстами
108159
108722
  - Верни только финальные результаты. Не добавляй объяснений или комментариев`;
108160
108723
  }
@@ -108232,6 +108795,7 @@ function getPairsSystemPrompt(geo, noOverride, count = 3, selectedIndices) {
108232
108795
  - Служебные метки в начале строки пиши РОВНО как в примере: слово «ЗАГОЛОВОК» целиком кириллицей (не ZAG, не смесь латиницы и кириллицы), слово «ТЕКСТ» целиком кириллицей.
108233
108796
  - Не вставляй строки «ЗАГОЛОВОК N:» внутрь текста объявления; каждый заголовок — отдельная строка перед своим «ТЕКСТ N:».
108234
108797
  - Контент объявления (заголовок и текст) — на языке ${geo}; только метки ЗАГОЛОВОК/ТЕКСТ остаются кириллицей как шаблон.
108798
+ - Язык ${geo}: если это название страны — пиши на **официальном языке этой страны**; не путай близкие коды и локали (например Словения ≠ Словакия, хорватский ≠ словенский).
108235
108799
 
108236
108800
  РАСПРЕДЕЛЕНИЕ ПОДХОДОВ ПО ПАРАМ:
108237
108801
  ${distributionLines}
@@ -108241,27 +108805,28 @@ ${distributionLines}
108241
108805
  - Текст — раскрывает тот же угол глубже, добавляет детали, заканчивается CTA
108242
108806
  - Текст НЕ повторяет заголовок дословно, но развивает его смысл
108243
108807
  - Не подмешивай чужие углы: например в «трансформация до/после» не используй формулировки соцдоказательства («многие отмечают», «клиенты говорят»)
108244
- ${hasTransformAndTestimonial ? '\n- РАЗВЕДЕНИЕ «трансформация до/после» и «testimonial» в одном ответе: у трансформации заголовок = контраст ощущений/состояния (без −кг и без «минус X kg за N дней»); у testimonial заголовок может содержать −кг, весы, срок как убедительный отзыв. Не делай два заголовка в одном формате «цифра + срок на весах».' : ''}
108808
+ ${hasTransformAndTestimonial ? '\n- РАЗВЕДЕНИЕ «трансформация до/после» и «testimonial» в одном ответе: у трансформации заголовок = контраст ощущений/состояния (без −кг и без «минус X kg за N дней»); у testimonial −кг и весы в заголовке**только если продукт в задании явно про похудение**; иначе testimonial = конкретный симптомный/комфортный результат + срок. Не делай два заголовка в одном формате «цифра + срок на весах».' : ''}
108245
108809
 
108246
108810
  ТРЕБОВАНИЯ К ЗАГОЛОВКУ:
108247
108811
  - До 55–60 символов, максимум 6–7 слов
108248
108812
  - Цельность: заголовок читается как одно высказывание (или один связный вопрос целиком). ЗАПРЕЩЕНО склеивать несвязные ярлыки запятыми ради ключевых слов; эмодзи не должно разрывать грамматику так, что фраза перестаёт быть человеческой
108249
108813
  - ЗАПРЕЩЕНО двоеточие (:) — используй тире (—) или переформулируй
108250
108814
  - 1–2 эмодзи естественно (часто в конце фразы или после целого смыслового блока); избегай ⚠️ и 🚨${hasDirectOffer ? '\n- Для пары «прямой оффер/выгода» эмодзи в заголовке ОБЯЗАТЕЛЕН (минимум один) — визуально вровень с остальными парами набора' : ''}
108251
- - Хотя бы одно ключевое слово проблемы, релевантное продукту${hasUrgencyScarcity ? '\n- ИСКЛЮЧЕНИЕ: для пары с подходом «срочность/дефицит» в заголовке ЗАПРЕЩЕНЫ симптомы, проблема, тело, продукт — только лимит оффера (время, количество, дедлайн)' : ''}${hasAuthorityExpertise ? '\n- Пара «авторитет/экспертиза»: заголовок держит information gap — без ингредиентов и без прямого названия механизма; состав и «как это работает» — только в тексте пары' : ''}
108252
- - НЕ упоминай название продукта — заголовок = боль + триггер${hasUrgencyScarcity ? ' (кроме пары «срочность/дефицит»: там заголовок = только дефицит/дедлайн, без продукта и без боли)' : ''}${hasSocialProof ? '\n- Исключение: в паре «социальное доказательство» название продукта в заголовке допустимо, если оно входит в цельную фразу про массовый выбор (например «N persone hanno già scelto [продукт]»)' : ''}
108815
+ - Хотя бы одно ключевое слово проблемы, релевантное продукту${hasUrgencyScarcity ? '\n- ИСКЛЮЧЕНИЕ: для пары с подходом «срочность/дефицит» в заголовке ЗАПРЕЩЕНЫ симптомы, проблема, тело, продукт — только лимит оффера (время, количество, дедлайн)' : ''}${hasDirectOffer ? '\n- ИСКЛЮЧЕНИЕ: для пары «прямой оффер/выгода» ключевое слово проблемы в заголовке **не обязательно**; ядро — **-50%** (+эмодзи + короткая срочность). **Не выдумывай** «2-й пакет / вторая упаковка / полцены» без данных в задании — **-50% это просто -50%.**' : ''}${hasAuthorityExpertise ? '\n- Пара «авторитет/экспертиза»: заголовок держит information gap — без ингредиентов и без прямого названия механизма; состав и «как это работает» — только в тексте пары' : ''}
108816
+ - НЕ упоминай название продукта — заголовок = боль + триггер${hasUrgencyScarcity ? ' (кроме пары «срочность/дефицит»: там заголовок = только дефицит/дедлайн, без продукта и без боли)' : ''}${hasSocialProof ? '\n- Исключение: в паре «социальное доказательство» название продукта в заголовке допустимо, если оно входит в цельную фразу про массовый выбор (например «Уже N тысяч человек выбрали [продукт]» на языке GEO)' : ''}
108253
108817
  - Звучит как живая рекламная фраза, а не строка ключевых слов
108254
108818
 
108255
108819
  ТРЕБОВАНИЯ К ТЕКСТУ:
108256
- - 150–280 символов (testimonial — до 300)
108257
- - Хотя бы одно ключевое слово проблемы (для «срочность/дефицит» в тексте допустимо слабее, если весь фокус — на лимите оффера)
108258
- - Сильный явный CTA в конце («кликни», «попробуй сейчас», «закажи», «не жди»)${hasFearInaction ? '\n- ИСКЛЮЧЕНИЕ: для пары «страх бездействия» финальная фраза — не заказ, а забота о себе / начать сейчас; без «ordina ora», «закажи», «купи», «clicca e acquista» в конце' : ''}
108259
- - Короткие рубленые фразы, императивы, FOMO допустим${hasTestimonial ? '\n- Testimonial: строго от первого лица, начинается с «Имя, возраст:», конкретный результат с таймингом' : ''}
108820
+ - 150–280 символов (testimonial — до 300)${hasDirectOffer ? '; для пары «прямой оффер/выгода» достаточно **120–200** символов, если текст = **-50%** + срочность + CTA без воды' : ''}
108821
+ - Хотя бы одно ключевое слово проблемы (для «срочность/дефицит» в тексте допустимо слабее, если весь фокус — на лимите оффера)${hasDirectOffer ? '; для «прямой оффер/выгода» ключевое слово проблемы **не обязательно** — фокус на **-50%** и CTA' : ''}
108822
+ - Сильный явный CTA в конце («кликни», «попробуй сейчас», «закажи», «не жди»)${hasFearInaction ? '\n- ИСКЛЮЧЕНИЕ: для пары «страх бездействия» финальная фраза — не заказ, а забота о себе / начать сейчас; без «закажи», «купи», «оформи заказ» в конце' : ''}
108823
+ - Короткие рубленые фразы, императивы, FOMO допустим${hasTestimonial ? '\n- Testimonial: строго от первого лица, начинается с «Имя, возраст:», конкретный результат с таймингом; тема результата = как в названии/описании продукта (антипаразитарное → ЖКТ/вздутие/дискомфорт и т.д.), не минус кг если продукт не про вес' : ''}
108260
108824
  - Ингредиенты и состав из доп. информации — только в углах «авторитет/экспертиза» (и сходных); в «болевой точке» и чисто эмоциональных углах состав не перечислять
108261
108825
  ${deadlineNote}
108262
108826
 
108263
108827
  ОБЩИЕ ТРЕБОВАНИЯ:
108264
108828
  - Язык: ${geo} — все тексты строго на этом языке
108829
+ - Релевантность продукту из пользовательского сообщения: не подменяй категорию. Капли/средства от паразитов, детокс ЖКТ → симптомы и облегчение в этой зоне; **не делай главным мотивом −кг и весы**, если в задании нет явного похудения. Аналогично не смешивай суставы с простатой и т.д.
108265
108830
  - Естественный человеческий тон, без академизма и AI-звучания
108266
108831
  - Разные психологические триггеры в каждой паре, минимальное пересечение
108267
108832
  - Верни ТОЛЬКО пары в указанном формате, без объяснений и комментариев`;
@@ -108384,10 +108949,10 @@ OTHER_TEXT: ["..."] (любой другой рекламный текст на
108384
108949
  ШАГ 1 — HOOK/HEADLINE (критично):
108385
108950
  - Должен быть ВЫШЕ всех элементов и читабелен (хорошо читается на телефоне)
108386
108951
  - Допускается 1–4 строки (это НЕ ошибка). Ошибка только если текст нечитабелен или есть разрыв/перенос внутри слова.
108387
- - Смысл: релевантно проблеме/выгоде продукта. Допускаются и боль/дискомфорт, и обещание/выгода (например «Könnyebb napok»). НЕ считай ошибкой формулировки обещаний результата или клеймы.
108952
+ - Смысл: релевантно проблеме/выгоде продукта. Допускаются и боль/дискомфорт, и обещание/выгода (например «станет легче день ото дня» — смысл на языке GEO). НЕ считай ошибкой формулировки обещаний результата или клеймы.
108388
108953
  - ОБЯЗАТЕЛЬНО: ключевое слово проблемы явно в формулировке. Примеры по категориям: простата → простатит, простата; похудение → лишний вес, похудение; суставы → боль, колени, скованность; пищеварение → дискомфорт, вздутие; сон → бессонница, усталость. Отсутствие ключевого слова — ОШИБКА. Дополнительно для ориентира: ${keywords.join(', ')} (можно синонимы).
108389
- - Проверь вторую часть заголовка. Если она состоит только из абстрактных слов («Mai ușor», «Mai bine», «Soluția», «Ajutor») без конкретного бенефита — отметь: РЕКОМЕНДАЦИЯ: заголовок можно усилить конкретикой
108390
- - Если заголовок слишком общий/абстрактный («Mai ușor», «Mai bine» без конкретики) — отметь как РЕКОМЕНДАЦИЯ к улучшению (не ошибка, но слабо)
108954
+ - Проверь вторую часть заголовка. Если она состоит только из абстрактных слов («легче», «лучше», «решение», «помощь» без конкретики на языке GEO) без конкретного бенефита — отметь: РЕКОМЕНДАЦИЯ: заголовок можно усилить конкретикой
108955
+ - Если заголовок слишком общий/абстрактный («легче», «лучше» без конкретики) — отметь как РЕКОМЕНДАЦИЯ к улучшению (не ошибка, но слабо)
108391
108956
  - РЕКОМЕНДАЦИЯ (CTR): верхний текст лучше делать как HOOK — ОЧЕНЬ крупный, жирный, ВСЕ БУКВЫ ПРОПИСНЫЕ, на яркой контрастной плашке. Если это не так — не ошибка, но отметь рекомендацией
108392
108957
 
108393
108958
  ${step2Bullets}
@@ -108458,6 +109023,8 @@ function getImageGenerationBasePrompt(generateGeo, generatePrice, generateCurren
108458
109023
  Создай рекламный креатив для Facebook Ads ${ratio} (${ratioLabel}).
108459
109024
  ВАЖНО: изображение должно быть ${ratioShape} — строго соблюдай пропорции холста.
108460
109025
  Язык текста: ${generateGeo}.
109026
+ Если GEO — название страны (например «Чехия», «Румыния»), используй **основной официальный язык этой страны** на макете (Чехия → чешский; Румыния → румынский и т.д.). Валюта/символ цены из брифа и язык текста должны соответствовать одному рынку: при Kč — весь рекламный текст на чешском, не на румынском/польском/венгерском.
109027
+ ЗАПРЕЩЕНО копировать на макет примеры формулировок из этого промпта, если они на другом языке, чем требуется для ${generateGeo} — примеры только про структуру, слова придумывай на целевом языке.
108461
109028
 
108462
109029
  🚫 СЛУЖЕБНЫЕ СЛОВА НЕ РИСОВАТЬ НА КАРТИНКЕ (КРИТИЧНО):
108463
109030
  Слова HOOK, CTA, CAPS, BULLET, HEADLINE, PRICE, DISCOUNT, BULLETS, LAYER и любые похожие английские метки из этой инструкции (в т.ч. thumb‑stop) — только для тебя; на макете их НЕТ ни на кнопке, ни на плашках, ни мелким текстом. Кнопка: только реальный призыв на языке ${generateGeo} (1–2 слова), без префикса «CTA». Заголовок: только живой текст оффера, без слова HOOK. Заголовок делай прописными буквами на языке ${generateGeo}, но не пиши на изображении слово CAPS и не подписывай блоки ярлыками.
@@ -108493,20 +109060,20 @@ HOOK / HEADLINE (строгое правило):
108493
109060
  - ОБЯЗАТЕЛЬНО содержит ключевое слово проблемы ЯВНО. Примеры по категориям: простата → простатит, простата; похудение → лишний вес, похудение; суставы → боль в суставах, колени, скованность; пищеварение → дискомфорт, вздутие, тяжесть; сон → бессонница, усталость. Без ключевого слова — ОШИБКА
108494
109061
  - HOOK ВЫШЕ всех элементов (продукт, буллеты, CTA, цена). Самый крупный текстовый элемент на креативе
108495
109062
  - HOOK должен быть ВИЗУАЛЬНО “тяжёлым”: ОЧЕНЬ крупный, ТОЛСТЫЙ/жирный шрифт, весь текст заголовка ПРОПИСНЫМИ буквами на языке ${generateGeo}, на яркой контрастной плашке/подложке. Это верхний главный элемент, цепляющий внимание в ленте
108496
- - Можно (не обязательно) включить СРОК прямо в HOOK (например «7 dni», «14 dni») как триггер
108497
- - Заголовок должен быть РЕЗКИМ и призывным: короткие рубленые фразы, вопросы и предупреждения допустимы. Можно использовать обращение на «ты» (в языке GEO: «Masz…», «Twój…») и вопросительный знак
109063
+ - Можно (не обязательно) включить СРОК прямо в HOOK (например «7 дней», «14 дней» — перенеси число и слово «дней» на язык ${generateGeo}) как триггер
109064
+ - Заголовок должен быть РЕЗКИМ и призывным: короткие рубленые фразы, вопросы и предупреждения допустимы. Можно использовать обращение на «ты» (естественное для языка ${generateGeo}) и вопросительный знак
108498
109065
  - заголовок НЕ должен быть абстрактным слоганом/лозунгом или метафорой без конкретной боли. Допускается «thumb‑stop» стиль (вызов/вопрос/предупреждение), если это конкретно и релевантно категории
108499
109066
  - если не влезает: сначала измени композицию (расширь блок/переставь элементы), затем перепиши короче. НЕЛЬЗЯ уменьшать шрифт. HOOK всегда остаётся выше всех остальных элементов
108500
109067
  - Не повторяй один и тот же заголовок в разных подходах: для текущего подхода придумай новый, уникальный заголовок. Варьируй: угол боли, формулировку, акцент (проблема vs облегчение)
108501
- - Вторая часть заголовка = конкретное улучшение, не абстрактное слово. ПРАВИЛЬНО: «Zile fără dureri», «Mișcare ușoară», «Confort activ» (для суставов); «Zile fără disconfort», «Nopți liniștite» (для сна) адаптируй под категорию. НЕ ТАК: «Mai ușor», «Mai bine», «Soluția»
109068
+ - Вторая часть заголовка = конкретное улучшение, не абстрактное слово. ПРАВИЛЬНО (структура; на макете только язык ${generateGeo}): боль/вопрос + конкретное облегчение. НЕ ТАК: размытые «легче», «лучше», «решение» без конкретики
108502
109069
  - Специфические медицинские термины или диагнозы разрешены в заголовке, но не обязательны. Варьируй между прямыми формулировками (если релевантно категории) и мягкими формулировками, фокусирующимися на симптомах и дискомфорте, для разных креативов. Не используй один и тот же термин во всех креативах
108503
- ПРИМЕР (HU, только как формат НЕ копируй слова, определи категорию продукта сам):
108504
- - НЕ ТАК: «Makacs méreganyag ellen» (лозунг, абстрактно)
108505
- - ТАК (пищеварение): «Puffadás gond? Könnyebb napok»
108506
- - ТАК (суставы): «Ízületi fájdalom? Mozogj könnyebben»
108507
- - ТАК (сон): «Álmatlan éjszakák? Pihenj végre»
108508
- - ТАК (простата): «Prostată? Alinare rapidă»
108509
- - ТАК (похудение): «Greutate în plus? Fără diete extreme»
109070
+ ПРИМЕР (русский только формат и ритм; на макете пиши строго на языке ${generateGeo}, не копируй русский текст, если GEO не русскоязычный):
109071
+ - НЕ ТАК: «Борьба с токсинами» (лозунг, абстрактно)
109072
+ - ТАК (пищеварение): «Вздутие мучает? Легче к вечеру»
109073
+ - ТАК (суставы): «Боль в суставах? Двигайся свободнее»
109074
+ - ТАК (сон): «Бессонные ночи? Выспишься наконец»
109075
+ - ТАК (простата): «Простата беспокоит? Быстрое облегчение»
109076
+ - ТАК (похудение): «Лишний вес? Без жёстких диет»
108510
109077
  ❗ Если заголовок > 12 слов, похож на длинное предложение или звучит как лозунг без ключевого слова проблемы — ОШИБКА → пересоздай вариант.
108511
109078
 
108512
109079
  BULLETS (жёсткое правило, ровно 3):
@@ -108516,14 +109083,14 @@ BULLETS (жёсткое правило, ровно 3):
108516
109083
  - ВИЗУАЛ БУЛЛЕТОВ: крупные, с иконками/галочками (✓), на контрастных подложках. Буллеты ВНЕ упаковки/банки — не на продукте.
108517
109084
  - Буллиты должны быть расположены ВЕРТИКАЛЬНО (столбиком), не горизонтально в одну строку. Минимальный размер шрифта буллитов — чтобы читались на экране телефона без зума
108518
109085
 
108519
- ❗ ВЫБОР БУЛЛЕТОВ (КРИТИЧНО): Выбери СЛУЧАЙНЫЕ 3 буллета из пула ниже в ПРОИЗВОЛЬНОМ порядке. Адаптируй формулировки под язык ${generateGeo} и категорию продукта. НЕ используй один и тот же набор для разных подходовкаждый креатив должен иметь УНИКАЛЬНУЮ комбинацию из 3 буллетов.
109086
+ ❗ ВЫБОР БУЛЛЕТОВ (КРИТИЧНО): Если выше по промпту задан блок «ОБЯЗАТЕЛЬНЫЕ БУЛЛЕТЫ» используй ТОЛЬКО его (перевод на язык ${generateGeo}). Если такого блока нет выбери 3 случайных смысла из пула ниже; пул на английском только для смысла, на макете **ноль английского** короткие фразы строго на языке ${generateGeo}. Не копируй на макет язык примеров из этого промпта, кроме целевого ${generateGeo}.
108520
109087
 
108521
- ПУЛ ВАРИАНТОВ (выбери 3 случайных, порядок произвольный; адаптируй под GEO и категорию):
108522
- Действие/бенефит: Reduce disconfortul, Reduce balonarea, Reduce durerea, Ulga rapidă, Confort zilnic, Mișcare ușoară, Mai puține simptome, Fără dureri, Zile fără disconfort, Stomac liniștit, Nopți liniștite, Rezultat vizibil
108523
- Срок/скорость: Efect în 7-14 zile, Efect în 2 săptămâni, Rezultat rapid, Ulga od 1. dnia, Efekt w 7 dni, szybciej, De la prima zi, În primele zile
108524
- Соц. доказательство: 9 din 10 recomandă, 9 din 10 bărbați recomandă, 93% potwierdza, 8 din 10 mulțumiți, Mii de clienți mulțumiți
108525
- Формула/состав: Formulă naturală, Ingrediente naturale, Fără chimicale, Compoziție selectată, Testat dermatologic
108526
- Качество жизни: Confort activ, Zile fără griji, Mai multă energie, Somn odihnitor, Viață mai ușoară
109088
+ ПУЛ СМЫСЛОВ (английский не печатать; переписать на ${generateGeo}, 2–4 слова каждый):
109089
+ Action/benefit: less discomfort, less bloating, less pain, fast relief, daily comfort, easier movement, fewer symptoms, pain-free, calm stomach, calm nights, visible result
109090
+ Time/speed: effect in 714 days, effect in 2 weeks, fast result, relief from day one, 3× faster, from first day, in the first days
109091
+ Social proof: 9 of 10 recommend, 9 of 10 men recommend, 93% confirm, 8 of 10 satisfied, thousands happy customers
109092
+ Formula: natural formula, natural ingredients, no harsh chemicals, selected composition, dermatologically tested
109093
+ Quality of life: active comfort, worry-free days, more energy, restful sleep, easier life
108527
109094
 
108528
109095
  ❗ Если хоть один буллет > 4 слов или похож на предложение/обещание — ОШИБКА → пересоздай.
108529
109096
 
@@ -108531,9 +109098,9 @@ TEXT LIMIT:
108531
109098
  - кроме: HOOK, 3 буллетов, цены, скидки, кнопки — ЛЮБОЙ другой текст запрещён (ярлыки/подписи/дисклеймеры/пояснения)
108532
109099
  - ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → кроме HOOK, цены, скидки, CTA — НИКАКОГО другого текста. Буллиты запрещены. Other_text/urgency/trust‑печати запрещены
108533
109100
  - ДОПУСКАЕТСЯ (не обязательно) ОДИН бейдж срочности: только ясные формулировки («только сегодня», «последние штуки», «акция до конца дня»). ЗАПРЕЩЕНО: «24h» — непонятно что означает.
108534
- - ДОПУСКАЕТСЯ (не обязательно) 1–3 trust‑печати: печати цветные, яркие, в стиле FDA. Текст СТРОГО на языке ${generateGeo} — запрещены английские слова («NATURAL», «QUALITY» и т.д.). Примеры для RO: «naturale», «Ingrediente naturale»; для PL: «naturalna». Размер как минимум как у буллитов. Мелкие печати — ОШИБКА.
109101
+ - ДОПУСКАЕТСЯ (не обязательно) 1–3 trust‑печати: печати цветные, яркие, в стиле FDA. Текст СТРОГО на языке ${generateGeo} — запрещены английские слова («NATURAL», «QUALITY» и т.д.). По смыслу: «натуральный», «натуральный состав» оформи короткой фразой на языке ${generateGeo}, не латиницей. Размер как минимум как у буллитов. Мелкие печати — ОШИБКА.
108535
109102
  - HOOK + буллеты <= 24 слова суммарно (HOOK до 12, буллеты до 12); если больше — ОШИБКА → пересоздай
108536
- - Если хочешь добавить ощущение срочности — делай это через формулировки в HOOK/BULLETS, через реквизит/иконки, ИЛИ (не обязательно) через один короткий бейдж срочности. Только ясные формулировки («Ostatnie sztuki», «Tylko dziś», «Koniec dziś»). ЗАПРЕЩЕНО «24h» — непонятно что означает.
109103
+ - Если хочешь добавить ощущение срочности — делай это через формулировки в HOOK/BULLETS, через реквизит/иконки, ИЛИ (не обязательно) через один короткий бейдж срочности. Только ясные формулировки на языке ${generateGeo} (уровень смысла: «последние штуки», «только сегодня», «акция до конца дня»). ЗАПРЕЩЕНО «24h» — непонятно что означает.
108537
109104
 
108538
109105
  CTA > PRICE:
108539
109106
  - кнопка CTA (1–2 слова на языке ${generateGeo}) — главный якорь нижнего блока (самый контрастный элемент внизу)
@@ -108549,7 +109116,7 @@ CTA > PRICE:
108549
109116
  - Скидка: «-50%» ОБЯЗАТЕЛЬНО отдельным видимым бейджем (не только в цене!). Процент скидки должен быть явно читаем. Ярко, заметно, строго НЕ на банке/упаковке, визуально слабее CTA
108550
109117
  - Кнопка CTA (1-2 слова)
108551
109118
  - Опционально: 1 короткий бейдж срочности (ясные формулировки: «только сегодня», «последние штуки»; ЗАПРЕЩЕНО «24h»). Бейдж в углу кадра, контрастный, но меньше CTA. НЕ обязателен
108552
- - Опционально: 1–3 trust‑печати (цветные, яркие, в стиле FDA; натуральность, премиальность, безопасность). Текст СТРОГО на языке ${generateGeo} — никакого английского. Для RO: «naturale», «Ingrediente naturale», «Calitate»; для PL: «naturalna», «naturalne»; НЕ «NATURAL», «QUALITY». Размер как минимум как у буллитов. НЕ обязательны
109119
+ - Опционально: 1–3 trust‑печати (цветные, яркие, в стиле FDA; натуральность, премиальность, безопасность). Текст СТРОГО на языке ${generateGeo} — никакого английского. По смыслу: «натуральный», «натуральный состав», «качество» коротко на ${generateGeo}; НЕ «NATURAL», «QUALITY». Размер как минимум как у буллитов. НЕ обязательны
108553
109120
  - ИСКЛЮЧЕНИЕ: если 🎯 ПОДХОД = ${noBulletsCond} → показывай только: HOOK + PRICE + DISCOUNT + CTA. Буллиты/urgency/trust‑печати запрещены
108554
109121
 
108555
109122
  ВИЗУАЛ:
@@ -108595,10 +109162,10 @@ AUTO-CHECK (перед финалом):
108595
109162
  ВАЖНО: Твой ответ — это ИЗОБРАЖЕНИЕ, не текст. Не пиши план, не перечисляй элементы текстом, не рассуждай, не вызывай tools. Сразу генерируй визуальный креатив как картинку.`;
108596
109163
  }
108597
109164
  /**
108598
- * Получить подходы с учетом количества и оверрайдов.
108599
- * Каждый подход повторяется N раз (0–4), где N = imageApproachCounts[i].
109165
+ * Развёрнутый список задач крео: каждый подход повторяется N раз (0–4), N = imageApproachCounts[i].
109166
+ * poolIndex индекс строки в CREO_APPROACHES (0-based); в UI таблице это номер строки poolIndex + 1 (1–10).
108600
109167
  */
108601
- function getCreoApproaches() {
109168
+ function getCreoApproachExpandedTasks() {
108602
109169
  const counts = (0,_promptOverrides__WEBPACK_IMPORTED_MODULE_0__.getImageApproachCounts)();
108603
109170
  const result = [];
108604
109171
  for (let i = 0; i < CREO_APPROACHES.length && i < counts.length; i++) {
@@ -108618,11 +109185,15 @@ function getCreoApproaches() {
108618
109185
  _debugLog(`✅ Using CUSTOM approach: ${approach.name}`, `hasPrompt=${!!override.customPrompt}`, `hasHeadline=${!!override.customHeadlineAngle}`, `hasBullets=${!!override.customBulletsFocus}`);
108619
109186
  }
108620
109187
  for (let k = 0; k < counts[i]; k++) {
108621
- result.push(resolved);
109188
+ result.push({ approach: resolved, poolIndex: i });
108622
109189
  }
108623
109190
  }
108624
109191
  return result;
108625
109192
  }
109193
+ /** Плоский список подходов (без индекса строки) — для обратной совместимости. */
109194
+ function getCreoApproaches() {
109195
+ return getCreoApproachExpandedTasks().map(t => t.approach);
109196
+ }
108626
109197
  const CREO_APPROACHES = [
108627
109198
  {
108628
109199
  name: 'Эксперт / Авторитет',