ttp-agent-sdk 2.45.12 → 2.46.1
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/agent-widget.dev.js +1582 -237
- package/dist/agent-widget.dev.js.map +1 -1
- package/dist/agent-widget.esm.js +1 -1
- package/dist/agent-widget.esm.js.map +1 -1
- package/dist/agent-widget.js +1 -1
- package/dist/agent-widget.js.map +1 -1
- package/dist/demos/recipe-mock-cheesecake.html +311 -0
- package/dist/demos/recipe-preview.html +186 -0
- package/dist/index.html +6 -1
- package/dist/partners/README.md +34 -0
- package/dist/partners/morrisons.svg +3 -0
- package/dist/partners/ocado.svg +3 -0
- package/package.json +1 -1
package/dist/agent-widget.dev.js
CHANGED
|
@@ -11468,11 +11468,57 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
|
|
|
11468
11468
|
}
|
|
11469
11469
|
|
|
11470
11470
|
/**
|
|
11471
|
-
*
|
|
11472
|
-
*
|
|
11471
|
+
* In-call user settings on the text channel — only responseLength applies
|
|
11472
|
+
* ("detailed"|"normal"|"brief"|"very_brief"; folded into the system prompt
|
|
11473
|
+
* from the next LLM turn). Mirrors VoiceSDK.setCallSettings().
|
|
11474
|
+
* @param {{responseLength?: string}} settings
|
|
11473
11475
|
*/
|
|
11474
11476
|
_inherits(TextChatSDK, _EventEmitter);
|
|
11475
11477
|
return _createClass(TextChatSDK, [{
|
|
11478
|
+
key: "setCallSettings",
|
|
11479
|
+
value: function setCallSettings() {
|
|
11480
|
+
var settings = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
11481
|
+
this._callSettings = _objectSpread(_objectSpread({}, this._callSettings || {}), settings);
|
|
11482
|
+
if (!this.connected || !this.ws || !this._callSettings.responseLength) {
|
|
11483
|
+
return false;
|
|
11484
|
+
}
|
|
11485
|
+
this.sendRaw({
|
|
11486
|
+
t: 'call_settings',
|
|
11487
|
+
responseLength: this._callSettings.responseLength
|
|
11488
|
+
});
|
|
11489
|
+
return true;
|
|
11490
|
+
}
|
|
11491
|
+
|
|
11492
|
+
/** Flush the persisted response-length preference right after hello_ack. */
|
|
11493
|
+
}, {
|
|
11494
|
+
key: "_syncCallSettingsAfterHello",
|
|
11495
|
+
value: function _syncCallSettingsAfterHello() {
|
|
11496
|
+
try {
|
|
11497
|
+
var s = this._callSettings;
|
|
11498
|
+
if (!s && typeof this.config.callSettingsProvider === 'function') {
|
|
11499
|
+
s = this.config.callSettingsProvider();
|
|
11500
|
+
}
|
|
11501
|
+
if (!s) return;
|
|
11502
|
+
this._callSettings = _objectSpread({}, s);
|
|
11503
|
+
var length = s.responseLength || 'normal';
|
|
11504
|
+
if (length === 'normal') return;
|
|
11505
|
+
this.sendRaw({
|
|
11506
|
+
t: 'call_settings',
|
|
11507
|
+
responseLength: length
|
|
11508
|
+
});
|
|
11509
|
+
console.log('⚙️ [TextChatSDK] Synced persisted call settings:', {
|
|
11510
|
+
responseLength: length
|
|
11511
|
+
});
|
|
11512
|
+
} catch (e) {
|
|
11513
|
+
console.warn('⚙️ [TextChatSDK] Failed to sync call settings (ignored):', e);
|
|
11514
|
+
}
|
|
11515
|
+
}
|
|
11516
|
+
|
|
11517
|
+
/**
|
|
11518
|
+
* Send a raw JSON message immediately on the open WebSocket. Used by the
|
|
11519
|
+
* client-tool registry — bypasses the LLM-turn queue used by sendMessage().
|
|
11520
|
+
*/
|
|
11521
|
+
}, {
|
|
11476
11522
|
key: "sendRaw",
|
|
11477
11523
|
value: function sendRaw(message) {
|
|
11478
11524
|
if (!this.connected || !this.ws) {
|
|
@@ -11626,6 +11672,9 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
|
|
|
11626
11672
|
hash: data.disclaimersHash
|
|
11627
11673
|
});
|
|
11628
11674
|
}
|
|
11675
|
+
// Silently re-apply the user's persisted response-length preference
|
|
11676
|
+
// (voice speed is meaningless on the text channel).
|
|
11677
|
+
_this2._syncCallSettingsAfterHello();
|
|
11629
11678
|
// Tools are loaded, connection is ready — drain any queued messages
|
|
11630
11679
|
_this2.drainQueue();
|
|
11631
11680
|
return;
|
|
@@ -11944,7 +11993,7 @@ var TextChatSDK = /*#__PURE__*/function (_EventEmitter) {
|
|
|
11944
11993
|
|
|
11945
11994
|
// SDK build time for debugging
|
|
11946
11995
|
if (true) {
|
|
11947
|
-
helloMessage.lastBuildTime = "2026-
|
|
11996
|
+
helloMessage.lastBuildTime = "2026-07-13T08:30:44.984Z";
|
|
11948
11997
|
}
|
|
11949
11998
|
try {
|
|
11950
11999
|
this.ws.send(JSON.stringify(helloMessage));
|
|
@@ -13531,6 +13580,8 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
|
|
13531
13580
|
* strip.updateTimer(text)
|
|
13532
13581
|
* strip.setMuted(bool) – legacy sync (prefer syncFromVoice)
|
|
13533
13582
|
* strip.setHeld(bool) – legacy pause visual (maps to paused)
|
|
13583
|
+
* strip.updateRecipes(recipes) – refresh saved-recipes badge + popover
|
|
13584
|
+
* strip.pulseRecipeBadge() – celebrate animation after recipe modal closes
|
|
13534
13585
|
* strip.destroy()
|
|
13535
13586
|
*/
|
|
13536
13587
|
|
|
@@ -13562,7 +13613,13 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13562
13613
|
this.onToggleSpeaker = opts.onToggleSpeaker || function () {};
|
|
13563
13614
|
this.onSendText = opts.onSendText || function () {};
|
|
13564
13615
|
this.onAbout = typeof opts.onAbout === 'function' ? opts.onAbout : null;
|
|
13616
|
+
this.onSettings = typeof opts.onSettings === 'function' ? opts.onSettings : null;
|
|
13617
|
+
this.onRecipeSelect = typeof opts.onRecipeSelect === 'function' ? opts.onRecipeSelect : null;
|
|
13565
13618
|
this._kbdOpen = false;
|
|
13619
|
+
this._recipePopoverOpen = false;
|
|
13620
|
+
this._recipes = [];
|
|
13621
|
+
this._recipeUnsub = null;
|
|
13622
|
+
this._pulseTimer = null;
|
|
13566
13623
|
this._el = null;
|
|
13567
13624
|
this._build();
|
|
13568
13625
|
}
|
|
@@ -13650,7 +13707,7 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13650
13707
|
key: "_footerHtml",
|
|
13651
13708
|
value: function _footerHtml() {
|
|
13652
13709
|
var brand = this.footer ? "<span>Powered by <a href=\"".concat(this.footer.brandUrl, "\" target=\"_blank\" rel=\"noopener noreferrer\"><b>").concat(this.footer.brandName, "</b></a></span>") : '';
|
|
13653
|
-
return "\n <div id=\"ttp-ecom-footer\" class=\"ttp-ecom-footer\">\n ".concat(brand, "\n <button type=\"button\" class=\"ttp-ecom-info-btn\" id=\"ttp-ecom-btn-info\" title=\"About\" aria-label=\"About\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/>\n <circle cx=\"12\" cy=\"7.7\" r=\"1.05\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>\n </div>");
|
|
13710
|
+
return "\n <div id=\"ttp-ecom-footer\" class=\"ttp-ecom-footer\">\n ".concat(brand, "\n <div class=\"ttp-ecom-recipe-wrap\" id=\"ttp-ecom-recipe-wrap\" hidden>\n <button type=\"button\" class=\"ttp-ecom-recipe-btn\" id=\"ttp-ecom-btn-recipe\"\n title=\"Saved recipes\" aria-label=\"Saved recipes\" aria-expanded=\"false\" aria-haspopup=\"true\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.65\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\">\n <path d=\"M5.5 3V8\"/>\n <path d=\"M7.5 3V8\"/>\n <path d=\"M9.5 3V8\"/>\n <path d=\"M7.5 8V21\"/>\n <path d=\"M16.5 3V21\"/>\n <path d=\"M16.5 3C19 3 20.5 5.2 20.5 7.5V10\"/>\n </svg>\n <span class=\"ttp-ecom-recipe-count\" id=\"ttp-ecom-recipe-count\">0</span>\n </button>\n <div class=\"ttp-ecom-recipe-popover\" id=\"ttp-ecom-recipe-popover\" role=\"menu\" hidden></div>\n </div>\n <button type=\"button\" class=\"ttp-ecom-info-btn\" id=\"ttp-ecom-btn-settings\" title=\"Call settings\" aria-label=\"Call settings\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"/>\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h.01a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.01a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ecom-info-btn\" id=\"ttp-ecom-btn-info\" title=\"About\" aria-label=\"About\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/>\n <circle cx=\"12\" cy=\"7.7\" r=\"1.05\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>\n </div>");
|
|
13654
13711
|
}
|
|
13655
13712
|
}, {
|
|
13656
13713
|
key: "_wireEvents",
|
|
@@ -13685,6 +13742,13 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13685
13742
|
if (_this.onAbout) _this.onAbout();
|
|
13686
13743
|
});
|
|
13687
13744
|
}
|
|
13745
|
+
var settingsBtn = $('ttp-ecom-btn-settings');
|
|
13746
|
+
if (settingsBtn) {
|
|
13747
|
+
settingsBtn.addEventListener('click', function () {
|
|
13748
|
+
if (_this.onSettings) _this.onSettings();
|
|
13749
|
+
});
|
|
13750
|
+
}
|
|
13751
|
+
this._wireRecipeBadge();
|
|
13688
13752
|
$('ttp-ecom-btn-end').addEventListener('click', function () {
|
|
13689
13753
|
return _this.onHangup();
|
|
13690
13754
|
});
|
|
@@ -13701,10 +13765,141 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13701
13765
|
if (e.key === 'Enter') sendFn();
|
|
13702
13766
|
});
|
|
13703
13767
|
}
|
|
13768
|
+
|
|
13769
|
+
/**
|
|
13770
|
+
* Subscribe to a recipe store; hydrates badge on mount.
|
|
13771
|
+
* @param {{ subscribe: Function, getAll: Function }} store
|
|
13772
|
+
*/
|
|
13773
|
+
}, {
|
|
13774
|
+
key: "bindRecipeStore",
|
|
13775
|
+
value: function bindRecipeStore(store) {
|
|
13776
|
+
var _this2 = this;
|
|
13777
|
+
if (this._recipeUnsub) {
|
|
13778
|
+
this._recipeUnsub();
|
|
13779
|
+
this._recipeUnsub = null;
|
|
13780
|
+
}
|
|
13781
|
+
if (!store) return;
|
|
13782
|
+
this.updateRecipes(store.getAll());
|
|
13783
|
+
this._recipeUnsub = store.subscribe(function (recipes) {
|
|
13784
|
+
return _this2.updateRecipes(recipes);
|
|
13785
|
+
});
|
|
13786
|
+
}
|
|
13787
|
+
|
|
13788
|
+
/**
|
|
13789
|
+
* @param {Array<{ id: string, title: string }>} recipes
|
|
13790
|
+
*/
|
|
13791
|
+
}, {
|
|
13792
|
+
key: "updateRecipes",
|
|
13793
|
+
value: function updateRecipes(recipes) {
|
|
13794
|
+
this._recipes = Array.isArray(recipes) ? recipes : [];
|
|
13795
|
+
if (!this._el) return;
|
|
13796
|
+
var wrap = this._el.querySelector('#ttp-ecom-recipe-wrap');
|
|
13797
|
+
var countEl = this._el.querySelector('#ttp-ecom-recipe-count');
|
|
13798
|
+
var btn = this._el.querySelector('#ttp-ecom-btn-recipe');
|
|
13799
|
+
if (!wrap || !countEl || !btn) return;
|
|
13800
|
+
var n = this._recipes.length;
|
|
13801
|
+
countEl.textContent = String(n);
|
|
13802
|
+
wrap.hidden = n === 0;
|
|
13803
|
+
if (this._recipePopoverOpen) this._renderRecipePopover();
|
|
13804
|
+
}
|
|
13805
|
+
|
|
13806
|
+
/** Play a short celebrate animation to draw attention after saving a recipe. */
|
|
13807
|
+
}, {
|
|
13808
|
+
key: "pulseRecipeBadge",
|
|
13809
|
+
value: function pulseRecipeBadge() {
|
|
13810
|
+
if (!this._el || this._recipes.length === 0) return;
|
|
13811
|
+
var btn = this._el.querySelector('#ttp-ecom-btn-recipe');
|
|
13812
|
+
var countEl = this._el.querySelector('#ttp-ecom-recipe-count');
|
|
13813
|
+
if (!btn) return;
|
|
13814
|
+
if (this._pulseTimer) {
|
|
13815
|
+
clearTimeout(this._pulseTimer);
|
|
13816
|
+
this._pulseTimer = null;
|
|
13817
|
+
}
|
|
13818
|
+
btn.classList.remove('ttp-ecom-recipe-btn--celebrate');
|
|
13819
|
+
countEl === null || countEl === void 0 || countEl.classList.remove('ttp-ecom-recipe-count--pop');
|
|
13820
|
+
// Force reflow so re-adding the class retriggers the animation.
|
|
13821
|
+
void btn.offsetWidth;
|
|
13822
|
+
btn.classList.add('ttp-ecom-recipe-btn--celebrate');
|
|
13823
|
+
countEl === null || countEl === void 0 || countEl.classList.add('ttp-ecom-recipe-count--pop');
|
|
13824
|
+
var _cleanup = function cleanup() {
|
|
13825
|
+
btn.classList.remove('ttp-ecom-recipe-btn--celebrate');
|
|
13826
|
+
countEl === null || countEl === void 0 || countEl.classList.remove('ttp-ecom-recipe-count--pop');
|
|
13827
|
+
btn.removeEventListener('animationend', _cleanup);
|
|
13828
|
+
};
|
|
13829
|
+
btn.addEventListener('animationend', _cleanup);
|
|
13830
|
+
this._pulseTimer = setTimeout(_cleanup, 1600);
|
|
13831
|
+
}
|
|
13832
|
+
}, {
|
|
13833
|
+
key: "_wireRecipeBadge",
|
|
13834
|
+
value: function _wireRecipeBadge() {
|
|
13835
|
+
var _this$_el,
|
|
13836
|
+
_this$_el2,
|
|
13837
|
+
_this3 = this;
|
|
13838
|
+
var btn = (_this$_el = this._el) === null || _this$_el === void 0 ? void 0 : _this$_el.querySelector('#ttp-ecom-btn-recipe');
|
|
13839
|
+
var popover = (_this$_el2 = this._el) === null || _this$_el2 === void 0 ? void 0 : _this$_el2.querySelector('#ttp-ecom-recipe-popover');
|
|
13840
|
+
if (!btn || !popover) return;
|
|
13841
|
+
btn.addEventListener('click', function (e) {
|
|
13842
|
+
e.stopPropagation();
|
|
13843
|
+
_this3._recipePopoverOpen = !_this3._recipePopoverOpen;
|
|
13844
|
+
btn.setAttribute('aria-expanded', _this3._recipePopoverOpen ? 'true' : 'false');
|
|
13845
|
+
if (_this3._recipePopoverOpen) {
|
|
13846
|
+
_this3._renderRecipePopover();
|
|
13847
|
+
popover.hidden = false;
|
|
13848
|
+
} else {
|
|
13849
|
+
popover.hidden = true;
|
|
13850
|
+
}
|
|
13851
|
+
});
|
|
13852
|
+
this._recipeOutsideClick = function (e) {
|
|
13853
|
+
if (!_this3._recipePopoverOpen) return;
|
|
13854
|
+
if (btn.contains(e.target) || popover.contains(e.target)) return;
|
|
13855
|
+
_this3._recipePopoverOpen = false;
|
|
13856
|
+
btn.setAttribute('aria-expanded', 'false');
|
|
13857
|
+
popover.hidden = true;
|
|
13858
|
+
};
|
|
13859
|
+
document.addEventListener('click', this._recipeOutsideClick);
|
|
13860
|
+
}
|
|
13861
|
+
}, {
|
|
13862
|
+
key: "_renderRecipePopover",
|
|
13863
|
+
value: function _renderRecipePopover() {
|
|
13864
|
+
var _this$_el3,
|
|
13865
|
+
_this4 = this;
|
|
13866
|
+
var popover = (_this$_el3 = this._el) === null || _this$_el3 === void 0 ? void 0 : _this$_el3.querySelector('#ttp-ecom-recipe-popover');
|
|
13867
|
+
if (!popover) return;
|
|
13868
|
+
var items = this._recipes.slice(0, 3);
|
|
13869
|
+
var rows = items.map(function (r) {
|
|
13870
|
+
return "\n <button type=\"button\" class=\"ttp-ecom-recipe-row\" data-recipe-id=\"".concat(_this4._escapeAttr(r.id), "\" role=\"menuitem\">\n <span class=\"ttp-ecom-recipe-row-title\">").concat(_this4._escapeHtml(r.title), "</span>\n </button>");
|
|
13871
|
+
}).join('');
|
|
13872
|
+
var more = this._recipes.length > 3 ? "<div class=\"ttp-ecom-recipe-more\">".concat(this._recipes.length - 3, " more saved</div>") : '';
|
|
13873
|
+
popover.innerHTML = "\n <span class=\"ttp-ecom-recipe-popover-label\">Saved recipes</span>\n ".concat(rows, "\n ").concat(more);
|
|
13874
|
+
popover.querySelectorAll('.ttp-ecom-recipe-row').forEach(function (row) {
|
|
13875
|
+
row.addEventListener('click', function (e) {
|
|
13876
|
+
var _this4$_el;
|
|
13877
|
+
e.stopPropagation();
|
|
13878
|
+
var id = row.getAttribute('data-recipe-id');
|
|
13879
|
+
var recipe = _this4._recipes.find(function (r) {
|
|
13880
|
+
return r.id === id;
|
|
13881
|
+
});
|
|
13882
|
+
if (recipe && _this4.onRecipeSelect) _this4.onRecipeSelect(recipe);
|
|
13883
|
+
_this4._recipePopoverOpen = false;
|
|
13884
|
+
popover.hidden = true;
|
|
13885
|
+
(_this4$_el = _this4._el) === null || _this4$_el === void 0 || (_this4$_el = _this4$_el.querySelector('#ttp-ecom-btn-recipe')) === null || _this4$_el === void 0 || _this4$_el.setAttribute('aria-expanded', 'false');
|
|
13886
|
+
});
|
|
13887
|
+
});
|
|
13888
|
+
}
|
|
13889
|
+
}, {
|
|
13890
|
+
key: "_escapeHtml",
|
|
13891
|
+
value: function _escapeHtml(str) {
|
|
13892
|
+
return String(str !== null && str !== void 0 ? str : '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
13893
|
+
}
|
|
13894
|
+
}, {
|
|
13895
|
+
key: "_escapeAttr",
|
|
13896
|
+
value: function _escapeAttr(str) {
|
|
13897
|
+
return this._escapeHtml(str).replace(/'/g, ''');
|
|
13898
|
+
}
|
|
13704
13899
|
}, {
|
|
13705
13900
|
key: "show",
|
|
13706
13901
|
value: function show() {
|
|
13707
|
-
var
|
|
13902
|
+
var _this5 = this;
|
|
13708
13903
|
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
13709
13904
|
if (!this._el) return;
|
|
13710
13905
|
if (opts.reset !== false) this._reset();
|
|
@@ -13712,7 +13907,7 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13712
13907
|
this.syncFromVoice();
|
|
13713
13908
|
// Now that the strip has real dimensions, clamp any restored drag position.
|
|
13714
13909
|
if (this._dragEnabled) requestAnimationFrame(function () {
|
|
13715
|
-
return
|
|
13910
|
+
return _this5.reclampDrag();
|
|
13716
13911
|
});
|
|
13717
13912
|
}
|
|
13718
13913
|
}, {
|
|
@@ -13768,8 +13963,8 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13768
13963
|
}, {
|
|
13769
13964
|
key: "_syncMiniWave",
|
|
13770
13965
|
value: function _syncMiniWave(frozen) {
|
|
13771
|
-
var _this$
|
|
13772
|
-
(_this$
|
|
13966
|
+
var _this$_el4;
|
|
13967
|
+
(_this$_el4 = this._el) === null || _this$_el4 === void 0 || _this$_el4.querySelectorAll('.ttp-ecom-mini-wave .ttp-ecom-wb').forEach(function (b) {
|
|
13773
13968
|
b.classList.toggle('paused', frozen);
|
|
13774
13969
|
});
|
|
13775
13970
|
}
|
|
@@ -13859,7 +14054,7 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13859
14054
|
}, {
|
|
13860
14055
|
key: "enableDrag",
|
|
13861
14056
|
value: function enableDrag() {
|
|
13862
|
-
var
|
|
14057
|
+
var _this6 = this;
|
|
13863
14058
|
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
13864
14059
|
if (!this._el || this._dragEnabled) return;
|
|
13865
14060
|
var wrapper = this._el; // fixed, centered via translateX(-50%)
|
|
@@ -13888,8 +14083,8 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13888
14083
|
dy = e.clientY - startY;
|
|
13889
14084
|
if (!moved && Math.hypot(dx, dy) < THRESHOLD) return;
|
|
13890
14085
|
moved = true;
|
|
13891
|
-
|
|
13892
|
-
|
|
14086
|
+
_this6._dragOffset = _this6._clampDragOffset(baseX + dx, baseY + dy, baseRect);
|
|
14087
|
+
_this6._applyDragOffset();
|
|
13893
14088
|
};
|
|
13894
14089
|
var _onUp = function onUp(e) {
|
|
13895
14090
|
window.removeEventListener('pointermove', onMove);
|
|
@@ -13899,9 +14094,9 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13899
14094
|
handle.releasePointerCapture(e.pointerId);
|
|
13900
14095
|
} catch (err) {/* not captured */}
|
|
13901
14096
|
dragging = false;
|
|
13902
|
-
if (moved &&
|
|
14097
|
+
if (moved && _this6._dragPersist && _this6._dragKey) {
|
|
13903
14098
|
try {
|
|
13904
|
-
window.localStorage.setItem(
|
|
14099
|
+
window.localStorage.setItem(_this6._dragKey, JSON.stringify(_this6._dragOffset));
|
|
13905
14100
|
} catch (err) {/* unavailable */}
|
|
13906
14101
|
}
|
|
13907
14102
|
};
|
|
@@ -13913,9 +14108,9 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
13913
14108
|
moved = false;
|
|
13914
14109
|
startX = e.clientX;
|
|
13915
14110
|
startY = e.clientY;
|
|
13916
|
-
baseX =
|
|
13917
|
-
baseY =
|
|
13918
|
-
baseRect =
|
|
14111
|
+
baseX = _this6._dragOffset.x;
|
|
14112
|
+
baseY = _this6._dragOffset.y;
|
|
14113
|
+
baseRect = _this6._dragBaseRect();
|
|
13919
14114
|
handle.style.setProperty('cursor', 'grabbing');
|
|
13920
14115
|
try {
|
|
13921
14116
|
handle.setPointerCapture(e.pointerId);
|
|
@@ -14019,6 +14214,18 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
14019
14214
|
}, {
|
|
14020
14215
|
key: "destroy",
|
|
14021
14216
|
value: function destroy() {
|
|
14217
|
+
if (this._recipeUnsub) {
|
|
14218
|
+
this._recipeUnsub();
|
|
14219
|
+
this._recipeUnsub = null;
|
|
14220
|
+
}
|
|
14221
|
+
if (this._recipeOutsideClick) {
|
|
14222
|
+
document.removeEventListener('click', this._recipeOutsideClick);
|
|
14223
|
+
this._recipeOutsideClick = null;
|
|
14224
|
+
}
|
|
14225
|
+
if (this._pulseTimer) {
|
|
14226
|
+
clearTimeout(this._pulseTimer);
|
|
14227
|
+
this._pulseTimer = null;
|
|
14228
|
+
}
|
|
14022
14229
|
if (this._el && this._el.parentNode) this._el.parentNode.removeChild(this._el);
|
|
14023
14230
|
this._el = null;
|
|
14024
14231
|
var style = document.getElementById('ttp-ecom-strip-styles');
|
|
@@ -14027,12 +14234,12 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
14027
14234
|
}, {
|
|
14028
14235
|
key: "_reset",
|
|
14029
14236
|
value: function _reset() {
|
|
14030
|
-
var
|
|
14237
|
+
var _this7 = this,
|
|
14031
14238
|
_$,
|
|
14032
14239
|
_$2;
|
|
14033
14240
|
this._kbdOpen = false;
|
|
14034
14241
|
var $ = function $(id) {
|
|
14035
|
-
return
|
|
14242
|
+
return _this7._el.querySelector('#' + id);
|
|
14036
14243
|
};
|
|
14037
14244
|
var tx = $('ttp-ecom-transcript');
|
|
14038
14245
|
if (tx) {
|
|
@@ -14075,7 +14282,7 @@ var EcommerceVoiceStrip = /*#__PURE__*/function () {
|
|
|
14075
14282
|
}
|
|
14076
14283
|
}]);
|
|
14077
14284
|
}();
|
|
14078
|
-
EcommerceVoiceStrip._CSS = "\n#ttp-ecom-strip-wrapper {\n position: fixed;\n left: 50%;\n bottom: 0;\n transform: translateX(-50%);\n width: min(720px, calc(100vw - 40px));\n max-width: calc(100vw - 40px);\n z-index: 2147483647;\n box-sizing: border-box;\n padding: 0 14px max(14px, env(safe-area-inset-bottom, 0px));\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n font-feature-settings: \"kern\" 1, \"liga\" 1;\n pointer-events: none;\n}\n#ttp-ecom-strip-wrapper * { box-sizing: border-box; }\n\n/* Layered glass dock: rim light, soft lift, optional backdrop tint */\n#ttp-ecom-strip {\n pointer-events: auto;\n position: relative;\n isolation: isolate;\n margin: 0;\n border-radius: 26px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: var(--ecom-strip-bg, linear-gradient(145deg, #5b21b6 0%, #3730a3 42%, #1e1b4b 100%));\n background-clip: padding-box;\n color: var(--ecom-fg, #ffffff);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.18) inset,\n 0 1px 0 rgba(255, 255, 255, 0.14) inset,\n 0 -20px 40px -8px rgba(0, 0, 0, 0.22) inset,\n 0 12px 32px rgba(0, 0, 0, 0.22),\n 0 28px 56px -16px rgba(0, 0, 0, 0.45),\n 0 0 80px -20px rgba(99, 102, 241, 0.35);\n overflow: visible;\n}\n\n#ttp-ecom-strip::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 0;\n background: linear-gradient(\n 165deg,\n rgba(255, 255, 255, 0.08) 0%,\n rgba(255, 255, 255, 0) 42%,\n rgba(0, 0, 0, 0.12) 100%\n );\n}\n\n/* LIVE chip \u2014 glass capsule (backdrop blur), straddles top edge */\n#ttp-ecom-live-edge {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n z-index: 4;\n max-width: calc(100% - 52px);\n pointer-events: none;\n padding: 3px 14px 4px;\n border-radius: 999px;\n background: rgba(8, 6, 24, 0.78);\n border: 1px solid rgba(255, 255, 255, 0.28);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.35),\n 0 4px 16px rgba(0, 0, 0, 0.35),\n inset 0 1px 0 rgba(255, 255, 255, 0.12);\n}\n@supports (backdrop-filter: blur(1px)) {\n #ttp-ecom-live-edge {\n backdrop-filter: blur(14px) saturate(180%);\n -webkit-backdrop-filter: blur(14px) saturate(180%);\n }\n}\n\n#ttp-ecom-main-row {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 18px 16px 12px;\n min-height: 48px;\n}\n\n#ttp-ecom-footer {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 0 16px 10px;\n margin-top: -4px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n padding-top: 6px;\n}\n.ttp-ecom-info-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 2px;\n margin: 0;\n background: none;\n border: none;\n cursor: pointer;\n line-height: 0;\n border-radius: 50%;\n color: rgba(255, 255, 255, 0.35);\n transition: color 0.2s, background 0.2s;\n}\n.ttp-ecom-info-btn:hover {\n color: rgba(255, 255, 255, 0.7);\n background: rgba(255, 255, 255, 0.08);\n}\n.ttp-ecom-info-btn svg { display: block; }\n#ttp-ecom-footer span {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.35);\n white-space: nowrap;\n}\n#ttp-ecom-footer a {\n color: rgba(167, 139, 250, 0.95);\n text-decoration: none;\n font-weight: 600;\n}\n#ttp-ecom-footer a:hover { opacity: 0.85; }\n#ttp-ecom-footer a b { font-weight: 700; }\n\n#ttp-ecom-left-controls,\n#ttp-ecom-right-cluster {\n display: flex;\n align-items: center;\n gap: 7px;\n flex-shrink: 0;\n}\n\n/* Inset \u201Cmeter bridge\u201D for transcript \u2014 keeps one-line layout, adds depth */\n#ttp-ecom-center {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n text-align: start;\n padding: 7px 12px 7px 14px;\n border-radius: 16px;\n background: rgba(0, 0, 0, 0.16);\n border: 1px solid rgba(255, 255, 255, 0.08);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.07),\n inset 0 -1px 0 rgba(0, 0, 0, 0.12);\n}\n\n#ttp-ecom-live-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-width: 0;\n}\n\n#ttp-ecom-live-label {\n font-size: 9px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ecom-accent, #4ade80);\n opacity: 0.98;\n white-space: nowrap;\n}\n\n#ttp-ecom-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--ecom-accent, #4ade80);\n flex-shrink: 0;\n box-shadow: 0 0 14px rgba(74, 222, 128, 0.45);\n animation: ttp-ecom-blink 1.35s ease-in-out infinite;\n}\n#ttp-ecom-dot.paused {\n animation: none;\n opacity: 0.45;\n background: rgba(255,255,255,0.35);\n box-shadow: none;\n}\n@keyframes ttp-ecom-blink {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.25; transform: scale(0.92); }\n}\n\n#ttp-ecom-transcript {\n font-size: 12px;\n line-height: 1.42;\n letter-spacing: 0.015em;\n color: rgba(255, 255, 255, 0.94);\n width: 100%;\n max-width: 100%;\n overflow: hidden;\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n}\n\n#ttp-ecom-transcript.ttp-ecom-transcript--user {\n color: rgba(255, 244, 214, 0.98);\n font-weight: 600;\n letter-spacing: 0.02em;\n text-shadow: 0 0 28px rgba(251, 191, 36, 0.22);\n}\n\n/* Squircle glass controls */\n#ttp-ecom-strip .ttp-ecom-ctrl {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.16);\n background: linear-gradient(165deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.05) 100%);\n color: rgba(255, 255, 255, 0.92);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n position: relative;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.18),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.14s ease;\n outline: none;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.08) 100%);\n border-color: rgba(255, 255, 255, 0.32);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.22),\n 0 4px 14px rgba(0, 0, 0, 0.2);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:active { transform: scale(0.94); }\n#ttp-ecom-strip .ttp-ecom-ctrl:focus-visible {\n outline: 2px solid rgba(165, 180, 252, 0.95);\n outline-offset: 2px;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-active {\n background: linear-gradient(165deg, rgba(129, 140, 248, 0.45) 0%, rgba(99, 102, 241, 0.28) 100%) !important;\n border-color: rgba(196, 181, 253, 0.65) !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 0 1px rgba(99, 102, 241, 0.35),\n 0 6px 18px rgba(79, 70, 229, 0.35) !important;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-warn {\n background: linear-gradient(165deg, rgba(252, 165, 165, 0.22) 0%, rgba(239, 68, 68, 0.2) 100%) !important;\n border-color: rgba(252, 165, 165, 0.55) !important;\n}\n\n#ttp-ecom-strip .ttp-ecom-ctrl-end {\n width: 40px;\n height: 40px;\n border-radius: 14px;\n background: linear-gradient(165deg, #fb7185 0%, var(--ecom-end, #ef4444) 52%, #991b1b 100%) !important;\n border: none !important;\n color: #fff !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.25),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 6px 22px rgba(239, 68, 68, 0.48);\n transform: rotate(135deg);\n transition: filter 0.18s ease, transform 0.14s ease, box-shadow 0.2s ease;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:hover {\n filter: brightness(1.06);\n transform: rotate(135deg) scale(1.05);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.28),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 10px 28px rgba(239, 68, 68, 0.52);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:active {\n transform: rotate(135deg) scale(0.94);\n}\n\n/* Mini waveform */\n#ttp-ecom-strip .ttp-ecom-mini-wave {\n display: flex;\n align-items: center;\n gap: 3px;\n height: 24px;\n padding: 0 4px;\n opacity: 0.9;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb {\n width: 3px;\n border-radius: 3px;\n background: linear-gradient(180deg, #ddd6fe 0%, var(--ecom-accent, #a78bfa) 100%);\n animation: ttp-ecom-wa 0.78s ease-in-out infinite;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(1) { height: 6px; animation-delay: 0s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(2) { height: 11px; animation-delay: 0.1s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(3) { height: 16px; animation-delay: 0.2s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(4) { height: 9px; animation-delay: 0.15s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(5) { height: 12px; animation-delay: 0.05s; }\n@keyframes ttp-ecom-wa {\n 0%, 100% { transform: scaleY(0.38); opacity: 0.5; }\n 50% { transform: scaleY(1); opacity: 1; }\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb.paused {\n animation-play-state: paused;\n transform: scaleY(0.32);\n opacity: 0.28;\n}\n\n/* Input row */\n#ttp-ecom-input-row {\n display: none;\n position: relative;\n z-index: 1;\n align-items: center;\n gap: 10px;\n padding: 0 14px 12px;\n margin-top: -2px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n#ttp-ecom-input-row.open {\n display: flex;\n}\n#ttp-ecom-input {\n flex: 1;\n height: 40px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: rgba(0, 0, 0, 0.22);\n color: #fff;\n font-size: 14px;\n padding: 0 14px;\n outline: none;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);\n transition: border-color 0.18s ease, box-shadow 0.18s ease;\n}\n#ttp-ecom-input::placeholder { color: rgba(255, 255, 255, 0.42); }\n#ttp-ecom-input:focus {\n border-color: rgba(165, 180, 252, 0.65);\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.2),\n 0 0 0 3px rgba(99, 102, 241, 0.25);\n}\n\n#ttp-ecom-strip .ttp-ecom-send {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: none;\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.1) 100%);\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);\n transition: background 0.18s ease, transform 0.12s ease;\n}\n#ttp-ecom-strip .ttp-ecom-send:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.14) 100%);\n}\n#ttp-ecom-strip .ttp-ecom-send:active { transform: scale(0.94); }\n\n@media (max-width: 520px) {\n #ttp-ecom-strip .ttp-ecom-mini-wave { display: none; }\n #ttp-ecom-main-row { gap: 7px; padding: 16px 12px 10px; }\n #ttp-ecom-strip .ttp-ecom-ctrl { width: 36px; height: 36px; }\n #ttp-ecom-strip .ttp-ecom-ctrl-end { width: 40px; height: 40px; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n #ttp-ecom-dot { animation: none; opacity: 0.9; }\n #ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb { animation: none; opacity: 0.65; }\n}\n";
|
|
14285
|
+
EcommerceVoiceStrip._CSS = "\n#ttp-ecom-strip-wrapper {\n position: fixed;\n left: 50%;\n bottom: 0;\n transform: translateX(-50%);\n width: min(720px, calc(100vw - 40px));\n max-width: calc(100vw - 40px);\n z-index: 2147483647;\n box-sizing: border-box;\n padding: 0 14px max(14px, env(safe-area-inset-bottom, 0px));\n font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, sans-serif;\n -webkit-font-smoothing: antialiased;\n font-feature-settings: \"kern\" 1, \"liga\" 1;\n pointer-events: none;\n}\n#ttp-ecom-strip-wrapper * { box-sizing: border-box; }\n\n/* Layered glass dock: rim light, soft lift, optional backdrop tint */\n#ttp-ecom-strip {\n pointer-events: auto;\n position: relative;\n isolation: isolate;\n margin: 0;\n border-radius: 26px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: var(--ecom-strip-bg, linear-gradient(145deg, #5b21b6 0%, #3730a3 42%, #1e1b4b 100%));\n background-clip: padding-box;\n color: var(--ecom-fg, #ffffff);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.18) inset,\n 0 1px 0 rgba(255, 255, 255, 0.14) inset,\n 0 -20px 40px -8px rgba(0, 0, 0, 0.22) inset,\n 0 12px 32px rgba(0, 0, 0, 0.22),\n 0 28px 56px -16px rgba(0, 0, 0, 0.45),\n 0 0 80px -20px rgba(99, 102, 241, 0.35);\n overflow: visible;\n}\n\n#ttp-ecom-strip::before {\n content: \"\";\n position: absolute;\n inset: 0;\n border-radius: inherit;\n pointer-events: none;\n z-index: 0;\n background: linear-gradient(\n 165deg,\n rgba(255, 255, 255, 0.08) 0%,\n rgba(255, 255, 255, 0) 42%,\n rgba(0, 0, 0, 0.12) 100%\n );\n}\n\n/* LIVE chip \u2014 glass capsule (backdrop blur), straddles top edge */\n#ttp-ecom-live-edge {\n position: absolute;\n left: 50%;\n top: 0;\n transform: translate(-50%, -50%);\n z-index: 4;\n max-width: calc(100% - 52px);\n pointer-events: none;\n padding: 3px 14px 4px;\n border-radius: 999px;\n background: rgba(8, 6, 24, 0.78);\n border: 1px solid rgba(255, 255, 255, 0.28);\n box-shadow:\n 0 0 0 1px rgba(0, 0, 0, 0.35),\n 0 4px 16px rgba(0, 0, 0, 0.35),\n inset 0 1px 0 rgba(255, 255, 255, 0.12);\n}\n@supports (backdrop-filter: blur(1px)) {\n #ttp-ecom-live-edge {\n backdrop-filter: blur(14px) saturate(180%);\n -webkit-backdrop-filter: blur(14px) saturate(180%);\n }\n}\n\n#ttp-ecom-main-row {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 18px 16px 12px;\n min-height: 48px;\n}\n\n#ttp-ecom-footer {\n position: relative;\n z-index: 1;\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n padding: 0 16px 10px;\n margin-top: -4px;\n border-top: 1px solid rgba(255, 255, 255, 0.06);\n padding-top: 6px;\n}\n.ttp-ecom-info-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 2px;\n margin: 0;\n background: none;\n border: none;\n cursor: pointer;\n line-height: 0;\n border-radius: 50%;\n color: rgba(255, 255, 255, 0.35);\n transition: color 0.2s, background 0.2s;\n}\n.ttp-ecom-info-btn:hover {\n color: rgba(255, 255, 255, 0.7);\n background: rgba(255, 255, 255, 0.08);\n}\n.ttp-ecom-info-btn svg { display: block; }\n#ttp-ecom-footer span {\n font-size: 10px;\n color: rgba(255, 255, 255, 0.35);\n white-space: nowrap;\n}\n#ttp-ecom-footer a {\n color: rgba(167, 139, 250, 0.95);\n text-decoration: none;\n font-weight: 600;\n}\n#ttp-ecom-footer a:hover { opacity: 0.85; }\n#ttp-ecom-footer a b { font-weight: 700; }\n\n.ttp-ecom-recipe-wrap {\n position: relative;\n display: inline-flex;\n align-items: center;\n}\n.ttp-ecom-recipe-btn {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 3px 7px 3px 5px;\n margin: 0;\n background: rgba(255, 255, 255, 0.06);\n border: 1px solid rgba(167, 139, 250, 0.42);\n border-radius: 999px;\n cursor: pointer;\n line-height: 1;\n color: rgba(255, 255, 255, 0.92);\n transition: color 0.2s, background 0.2s, border-color 0.2s, box-shadow 0.2s;\n}\n.ttp-ecom-recipe-btn:hover {\n color: #fff;\n background: rgba(255, 255, 255, 0.1);\n border-color: rgba(196, 181, 253, 0.65);\n}\n.ttp-ecom-recipe-btn svg { display: block; flex-shrink: 0; }\n.ttp-ecom-recipe-count {\n font-size: 10px;\n font-weight: 800;\n min-width: 12px;\n text-align: center;\n letter-spacing: 0.02em;\n}\n.ttp-ecom-recipe-btn--celebrate {\n animation: ttp-ecom-recipe-celebrate 1.35s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\n}\n.ttp-ecom-recipe-btn--celebrate::after {\n content: \"\";\n position: absolute;\n inset: -3px;\n border-radius: 999px;\n border: 2px solid rgba(74, 222, 128, 0.75);\n animation: ttp-ecom-recipe-ring 1.35s ease-out forwards;\n pointer-events: none;\n}\n.ttp-ecom-recipe-count--pop {\n animation: ttp-ecom-recipe-count-pop 1.35s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;\n}\n@keyframes ttp-ecom-recipe-celebrate {\n 0% {\n transform: scale(1);\n color: rgba(167, 139, 250, 0.92);\n background: rgba(255, 255, 255, 0.06);\n box-shadow: none;\n }\n 18% {\n transform: scale(1.22);\n color: #86efac;\n background: rgba(74, 222, 128, 0.24);\n border-color: rgba(74, 222, 128, 0.55);\n box-shadow: 0 0 22px rgba(74, 222, 128, 0.5), 0 0 40px rgba(74, 222, 128, 0.2);\n }\n 36% {\n transform: scale(1.06);\n color: #bbf7d0;\n box-shadow: 0 0 14px rgba(74, 222, 128, 0.35);\n }\n 54% {\n transform: scale(1.16);\n color: #4ade80;\n background: rgba(74, 222, 128, 0.3);\n box-shadow: 0 0 28px rgba(74, 222, 128, 0.55);\n }\n 72% {\n transform: scale(1.08);\n color: #86efac;\n }\n 100% {\n transform: scale(1);\n color: rgba(167, 139, 250, 0.95);\n background: rgba(74, 222, 128, 0.1);\n border-color: rgba(74, 222, 128, 0.28);\n box-shadow: 0 0 12px rgba(74, 222, 128, 0.15);\n }\n}\n@keyframes ttp-ecom-recipe-ring {\n 0% { transform: scale(0.9); opacity: 0.85; }\n 100% { transform: scale(2.1); opacity: 0; }\n}\n@keyframes ttp-ecom-recipe-count-pop {\n 0%, 100% { transform: scale(1); }\n 20% { transform: scale(1.45); color: #fff; }\n 45% { transform: scale(1.15); }\n 60% { transform: scale(1.35); color: #dcfce7; }\n}\n.ttp-ecom-recipe-popover {\n position: absolute;\n bottom: calc(100% + 8px);\n left: 50%;\n transform: translateX(-50%);\n min-width: 180px;\n max-width: 240px;\n padding: 8px 0 6px;\n border-radius: 14px;\n background: rgba(12, 10, 28, 0.94);\n border: 1px solid rgba(255, 255, 255, 0.14);\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(0, 0, 0, 0.2);\n z-index: 6;\n pointer-events: auto;\n}\n@supports (backdrop-filter: blur(1px)) {\n .ttp-ecom-recipe-popover {\n backdrop-filter: blur(16px) saturate(160%);\n -webkit-backdrop-filter: blur(16px) saturate(160%);\n }\n}\n.ttp-ecom-recipe-popover-label {\n display: block;\n padding: 2px 12px 6px;\n font-size: 9px;\n font-weight: 800;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: rgba(255, 255, 255, 0.4);\n}\n.ttp-ecom-recipe-row {\n display: block;\n width: 100%;\n padding: 8px 12px;\n margin: 0;\n border: none;\n background: transparent;\n color: rgba(255, 255, 255, 0.92);\n font: 500 12px/1.35 ui-sans-serif, system-ui, sans-serif;\n text-align: start;\n cursor: pointer;\n transition: background 0.15s;\n}\n.ttp-ecom-recipe-row:hover {\n background: rgba(255, 255, 255, 0.08);\n}\n.ttp-ecom-recipe-row-title {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ttp-ecom-recipe-more {\n padding: 4px 12px 2px;\n font-size: 10px;\n color: rgba(167, 139, 250, 0.85);\n text-align: center;\n}\n\n#ttp-ecom-left-controls,\n#ttp-ecom-right-cluster {\n display: flex;\n align-items: center;\n gap: 7px;\n flex-shrink: 0;\n}\n\n/* Inset \u201Cmeter bridge\u201D for transcript \u2014 keeps one-line layout, adds depth */\n#ttp-ecom-center {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n align-items: stretch;\n justify-content: center;\n text-align: start;\n padding: 7px 12px 7px 14px;\n border-radius: 16px;\n background: rgba(0, 0, 0, 0.16);\n border: 1px solid rgba(255, 255, 255, 0.08);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.07),\n inset 0 -1px 0 rgba(0, 0, 0, 0.12);\n}\n\n#ttp-ecom-live-row {\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 6px;\n min-width: 0;\n}\n\n#ttp-ecom-live-label {\n font-size: 9px;\n font-weight: 800;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n color: var(--ecom-accent, #4ade80);\n opacity: 0.98;\n white-space: nowrap;\n}\n\n#ttp-ecom-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--ecom-accent, #4ade80);\n flex-shrink: 0;\n box-shadow: 0 0 14px rgba(74, 222, 128, 0.45);\n animation: ttp-ecom-blink 1.35s ease-in-out infinite;\n}\n#ttp-ecom-dot.paused {\n animation: none;\n opacity: 0.45;\n background: rgba(255,255,255,0.35);\n box-shadow: none;\n}\n@keyframes ttp-ecom-blink {\n 0%, 100% { opacity: 1; transform: scale(1); }\n 50% { opacity: 0.25; transform: scale(0.92); }\n}\n\n#ttp-ecom-transcript {\n font-size: 12px;\n line-height: 1.42;\n letter-spacing: 0.015em;\n color: rgba(255, 255, 255, 0.94);\n width: 100%;\n max-width: 100%;\n overflow: hidden;\n word-break: break-word;\n overflow-wrap: anywhere;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n}\n\n#ttp-ecom-transcript.ttp-ecom-transcript--user {\n color: rgba(255, 244, 214, 0.98);\n font-weight: 600;\n letter-spacing: 0.02em;\n text-shadow: 0 0 28px rgba(251, 191, 36, 0.22);\n}\n\n/* Squircle glass controls */\n#ttp-ecom-strip .ttp-ecom-ctrl {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.16);\n background: linear-gradient(165deg, rgba(255,255,255,0.14) 0%, rgba(255,255,255,0.05) 100%);\n color: rgba(255, 255, 255, 0.92);\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n position: relative;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.18),\n 0 2px 8px rgba(0, 0, 0, 0.15);\n transition: background 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.14s ease;\n outline: none;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.08) 100%);\n border-color: rgba(255, 255, 255, 0.32);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.22),\n 0 4px 14px rgba(0, 0, 0, 0.2);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl:active { transform: scale(0.94); }\n#ttp-ecom-strip .ttp-ecom-ctrl:focus-visible {\n outline: 2px solid rgba(165, 180, 252, 0.95);\n outline-offset: 2px;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-active {\n background: linear-gradient(165deg, rgba(129, 140, 248, 0.45) 0%, rgba(99, 102, 241, 0.28) 100%) !important;\n border-color: rgba(196, 181, 253, 0.65) !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.2),\n 0 0 0 1px rgba(99, 102, 241, 0.35),\n 0 6px 18px rgba(79, 70, 229, 0.35) !important;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-warn {\n background: linear-gradient(165deg, rgba(252, 165, 165, 0.22) 0%, rgba(239, 68, 68, 0.2) 100%) !important;\n border-color: rgba(252, 165, 165, 0.55) !important;\n}\n\n#ttp-ecom-strip .ttp-ecom-ctrl-end {\n width: 40px;\n height: 40px;\n border-radius: 14px;\n background: linear-gradient(165deg, #fb7185 0%, var(--ecom-end, #ef4444) 52%, #991b1b 100%) !important;\n border: none !important;\n color: #fff !important;\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.25),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 6px 22px rgba(239, 68, 68, 0.48);\n transform: rotate(135deg);\n transition: filter 0.18s ease, transform 0.14s ease, box-shadow 0.2s ease;\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:hover {\n filter: brightness(1.06);\n transform: rotate(135deg) scale(1.05);\n box-shadow:\n inset 0 1px 0 rgba(255, 255, 255, 0.28),\n 0 0 0 2px rgba(0, 0, 0, 0.12),\n 0 10px 28px rgba(239, 68, 68, 0.52);\n}\n#ttp-ecom-strip .ttp-ecom-ctrl-end:active {\n transform: rotate(135deg) scale(0.94);\n}\n\n/* Mini waveform */\n#ttp-ecom-strip .ttp-ecom-mini-wave {\n display: flex;\n align-items: center;\n gap: 3px;\n height: 24px;\n padding: 0 4px;\n opacity: 0.9;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb {\n width: 3px;\n border-radius: 3px;\n background: linear-gradient(180deg, #ddd6fe 0%, var(--ecom-accent, #a78bfa) 100%);\n animation: ttp-ecom-wa 0.78s ease-in-out infinite;\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(1) { height: 6px; animation-delay: 0s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(2) { height: 11px; animation-delay: 0.1s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(3) { height: 16px; animation-delay: 0.2s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(4) { height: 9px; animation-delay: 0.15s; }\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb:nth-child(5) { height: 12px; animation-delay: 0.05s; }\n@keyframes ttp-ecom-wa {\n 0%, 100% { transform: scaleY(0.38); opacity: 0.5; }\n 50% { transform: scaleY(1); opacity: 1; }\n}\n#ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb.paused {\n animation-play-state: paused;\n transform: scaleY(0.32);\n opacity: 0.28;\n}\n\n/* Input row */\n#ttp-ecom-input-row {\n display: none;\n position: relative;\n z-index: 1;\n align-items: center;\n gap: 10px;\n padding: 0 14px 12px;\n margin-top: -2px;\n border-top: 1px solid rgba(255, 255, 255, 0.1);\n}\n#ttp-ecom-input-row.open {\n display: flex;\n}\n#ttp-ecom-input {\n flex: 1;\n height: 40px;\n border-radius: 12px;\n border: 1px solid rgba(255, 255, 255, 0.18);\n background: rgba(0, 0, 0, 0.22);\n color: #fff;\n font-size: 14px;\n padding: 0 14px;\n outline: none;\n box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.2);\n transition: border-color 0.18s ease, box-shadow 0.18s ease;\n}\n#ttp-ecom-input::placeholder { color: rgba(255, 255, 255, 0.42); }\n#ttp-ecom-input:focus {\n border-color: rgba(165, 180, 252, 0.65);\n box-shadow:\n inset 0 1px 2px rgba(0, 0, 0, 0.2),\n 0 0 0 3px rgba(99, 102, 241, 0.25);\n}\n\n#ttp-ecom-strip .ttp-ecom-send {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n border: none;\n background: linear-gradient(165deg, rgba(255,255,255,0.22) 0%, rgba(255,255,255,0.1) 100%);\n color: #fff;\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2);\n transition: background 0.18s ease, transform 0.12s ease;\n}\n#ttp-ecom-strip .ttp-ecom-send:hover {\n background: linear-gradient(165deg, rgba(255,255,255,0.3) 0%, rgba(255,255,255,0.14) 100%);\n}\n#ttp-ecom-strip .ttp-ecom-send:active { transform: scale(0.94); }\n\n@media (max-width: 520px) {\n #ttp-ecom-strip .ttp-ecom-mini-wave { display: none; }\n #ttp-ecom-main-row { gap: 7px; padding: 16px 12px 10px; }\n #ttp-ecom-strip .ttp-ecom-ctrl { width: 36px; height: 36px; }\n #ttp-ecom-strip .ttp-ecom-ctrl-end { width: 40px; height: 40px; }\n}\n\n@media (prefers-reduced-motion: reduce) {\n #ttp-ecom-dot { animation: none; opacity: 0.9; }\n #ttp-ecom-strip .ttp-ecom-mini-wave .ttp-ecom-wb { animation: none; opacity: 0.65; }\n .ttp-ecom-recipe-btn--celebrate,\n .ttp-ecom-recipe-count--pop {\n animation: none !important;\n }\n .ttp-ecom-recipe-btn--celebrate::after { display: none; }\n}\n";
|
|
14079
14286
|
|
|
14080
14287
|
/***/ }),
|
|
14081
14288
|
|
|
@@ -16015,6 +16222,529 @@ var ProductPicker = /*#__PURE__*/function () {
|
|
|
16015
16222
|
|
|
16016
16223
|
/***/ }),
|
|
16017
16224
|
|
|
16225
|
+
/***/ "./src/ecommerce/RecipeHandler.js":
|
|
16226
|
+
/*!****************************************!*\
|
|
16227
|
+
!*** ./src/ecommerce/RecipeHandler.js ***!
|
|
16228
|
+
\****************************************/
|
|
16229
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
16230
|
+
|
|
16231
|
+
"use strict";
|
|
16232
|
+
__webpack_require__.r(__webpack_exports__);
|
|
16233
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
16234
|
+
/* harmony export */ buildRecipeHtml: () => (/* binding */ buildRecipeHtml),
|
|
16235
|
+
/* harmony export */ createRecipeHandler: () => (/* binding */ createRecipeHandler)
|
|
16236
|
+
/* harmony export */ });
|
|
16237
|
+
/* harmony import */ var _partnerLogo_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./partnerLogo.js */ "./src/ecommerce/partnerLogo.js");
|
|
16238
|
+
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
16239
|
+
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
|
|
16240
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
16241
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
16242
|
+
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
16243
|
+
/**
|
|
16244
|
+
* Recipe Handler — centered modal + self-contained HTML download.
|
|
16245
|
+
*
|
|
16246
|
+
* Backend wire: { t: 'show_recipe', recipe: { title, ingredients[], steps[], servings?, notes? } }
|
|
16247
|
+
* Triggered sync-to-speech when the agent calls send_recipe.
|
|
16248
|
+
*/
|
|
16249
|
+
|
|
16250
|
+
|
|
16251
|
+
var STYLES_ID = 'ttp-recipe-handler-styles';
|
|
16252
|
+
function escapeHtml(str) {
|
|
16253
|
+
return String(str !== null && str !== void 0 ? str : '').replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
16254
|
+
}
|
|
16255
|
+
function slugify(title) {
|
|
16256
|
+
var slug = String(title !== null && title !== void 0 ? title : 'recipe').trim().toLowerCase().replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '');
|
|
16257
|
+
return slug || 'recipe';
|
|
16258
|
+
}
|
|
16259
|
+
function normalizeRecipe(input) {
|
|
16260
|
+
var _recipe$title;
|
|
16261
|
+
if (!input || _typeof(input) !== 'object') return null;
|
|
16262
|
+
var recipe = input.recipe && _typeof(input.recipe) === 'object' ? input.recipe : input;
|
|
16263
|
+
var title = String((_recipe$title = recipe.title) !== null && _recipe$title !== void 0 ? _recipe$title : '').trim();
|
|
16264
|
+
var ingredients = Array.isArray(recipe.ingredients) ? recipe.ingredients.map(function (x) {
|
|
16265
|
+
return String(x).trim();
|
|
16266
|
+
}).filter(Boolean) : [];
|
|
16267
|
+
var steps = Array.isArray(recipe.steps) ? recipe.steps.map(function (x) {
|
|
16268
|
+
return String(x).trim();
|
|
16269
|
+
}).filter(Boolean) : [];
|
|
16270
|
+
if (!title || ingredients.length === 0 && steps.length === 0) {
|
|
16271
|
+
console.warn('[RecipeHandler] Invalid recipe payload — need title plus ingredients or steps', input);
|
|
16272
|
+
return null;
|
|
16273
|
+
}
|
|
16274
|
+
return {
|
|
16275
|
+
title: title,
|
|
16276
|
+
ingredients: ingredients,
|
|
16277
|
+
steps: steps,
|
|
16278
|
+
servings: recipe.servings ? String(recipe.servings).trim() : '',
|
|
16279
|
+
notes: recipe.notes ? String(recipe.notes).trim() : ''
|
|
16280
|
+
};
|
|
16281
|
+
}
|
|
16282
|
+
|
|
16283
|
+
/** Shared download-page CSS (self-contained, no external assets). */
|
|
16284
|
+
var RECIPE_PAGE_CSS = "\n :root {\n --bg: #f6f3ee;\n --paper: #fffcf8;\n --ink: #1c1917;\n --muted: #78716c;\n --accent: #2f6b52;\n --accent-soft: #e8f2ec;\n --accent-deep: #1e4d3a;\n --warm: #c4713a;\n --warm-soft: #fdf3eb;\n --line: rgba(28, 25, 23, 0.08);\n --shadow: 0 24px 60px rgba(28, 25, 23, 0.12);\n --radius: 20px;\n }\n * { box-sizing: border-box; }\n body {\n margin: 0;\n min-height: 100vh;\n font-family: \"Segoe UI\", system-ui, -apple-system, sans-serif;\n color: var(--ink);\n background:\n radial-gradient(circle at top right, rgba(47, 107, 82, 0.08), transparent 28rem),\n radial-gradient(circle at bottom left, rgba(196, 113, 58, 0.08), transparent 24rem),\n var(--bg);\n line-height: 1.55;\n padding: 32px 16px 48px;\n }\n .sheet {\n max-width: 760px;\n margin: 0 auto;\n background: var(--paper);\n border-radius: calc(var(--radius) + 4px);\n box-shadow: var(--shadow);\n overflow: hidden;\n border: 1px solid rgba(255, 255, 255, 0.7);\n }\n .hero {\n position: relative;\n padding: 36px 32px 28px;\n background:\n linear-gradient(135deg, var(--accent-deep) 0%, var(--accent) 55%, #3d8b67 100%);\n color: #fff;\n overflow: hidden;\n }\n .hero::before {\n content: \"\";\n position: absolute;\n inset: 0;\n background:\n radial-gradient(circle at 85% 15%, rgba(255,255,255,0.16), transparent 42%),\n radial-gradient(circle at 10% 100%, rgba(255,255,255,0.08), transparent 35%);\n pointer-events: none;\n }\n .hero-inner { position: relative; z-index: 1; }\n .hero-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 16px;\n margin-bottom: 12px;\n }\n .hero-head .eyebrow { margin-bottom: 0; }\n .partner-logo-wrap {\n flex-shrink: 0;\n background: rgba(255, 255, 255, 0.95);\n border-radius: 12px;\n padding: 8px 12px;\n max-width: 140px;\n display: flex;\n align-items: center;\n justify-content: center;\n }\n .partner-logo {\n height: 28px;\n width: auto;\n max-width: 120px;\n object-fit: contain;\n display: block;\n }\n .eyebrow {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n opacity: 0.88;\n margin-bottom: 12px;\n }\n .eyebrow-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #ffd166;\n box-shadow: 0 0 0 4px rgba(255, 209, 102, 0.22);\n }\n h1 {\n margin: 0;\n font-family: \"Iowan Old Style\", \"Palatino Linotype\", \"Book Antiqua\", Georgia, serif;\n font-size: clamp(2rem, 5vw, 2.75rem);\n line-height: 1.08;\n font-weight: 600;\n letter-spacing: -0.02em;\n }\n .servings {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-top: 16px;\n padding: 8px 14px;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.14);\n border: 1px solid rgba(255, 255, 255, 0.18);\n backdrop-filter: blur(8px);\n font-size: 14px;\n font-weight: 500;\n }\n .content { padding: 28px 28px 32px; }\n .grid {\n display: grid;\n grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);\n gap: 24px;\n }\n .section { min-width: 0; }\n .section-title {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0 0 14px;\n font-size: 12px;\n font-weight: 800;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: var(--accent-deep);\n }\n .section-title::after {\n content: \"\";\n flex: 1;\n height: 1px;\n background: linear-gradient(to right, var(--line), transparent);\n }\n .ingredients-box {\n margin: 0;\n padding: 0;\n list-style: none;\n background: var(--accent-soft);\n border: 1px solid rgba(47, 107, 82, 0.12);\n border-radius: 16px;\n overflow: hidden;\n }\n .ingredients-box li {\n display: flex;\n align-items: flex-start;\n gap: 12px;\n padding: 12px 16px;\n border-bottom: 1px solid rgba(47, 107, 82, 0.08);\n font-size: 15px;\n }\n .ingredients-box li:last-child { border-bottom: 0; }\n .ingredients-box li::before {\n content: \"\";\n flex-shrink: 0;\n width: 8px;\n height: 8px;\n margin-top: 0.45em;\n border-radius: 50%;\n background: var(--accent);\n box-shadow: 0 0 0 3px rgba(47, 107, 82, 0.14);\n }\n .steps { margin: 0; padding: 0; list-style: none; display: grid; gap: 12px; }\n .step {\n display: grid;\n grid-template-columns: 36px minmax(0, 1fr);\n gap: 14px;\n padding: 14px 16px;\n background: #fff;\n border: 1px solid var(--line);\n border-radius: 16px;\n box-shadow: 0 8px 24px rgba(28, 25, 23, 0.04);\n }\n .step-num {\n width: 36px;\n height: 36px;\n border-radius: 12px;\n display: grid;\n place-items: center;\n background: linear-gradient(180deg, var(--warm-soft), #fff);\n border: 1px solid rgba(196, 113, 58, 0.18);\n color: var(--warm);\n font-size: 14px;\n font-weight: 800;\n }\n .step-text { font-size: 15px; color: #292524; padding-top: 6px; }\n .notes {\n margin-top: 24px;\n padding: 16px 18px 16px 20px;\n border-radius: 16px;\n background: var(--warm-soft);\n border: 1px solid rgba(196, 113, 58, 0.16);\n color: #57534e;\n font-size: 14px;\n }\n .notes strong {\n display: block;\n margin-bottom: 6px;\n color: #9a3412;\n font-size: 12px;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n }\n .footer {\n margin-top: 28px;\n padding-top: 18px;\n border-top: 1px solid var(--line);\n text-align: center;\n font-size: 12px;\n color: var(--muted);\n letter-spacing: 0.04em;\n }\n @media (max-width: 720px) {\n .hero { padding: 28px 22px 22px; }\n .content { padding: 22px 18px 26px; }\n .grid { grid-template-columns: 1fr; gap: 22px; }\n }\n @media print {\n body { background: #fff; padding: 0; }\n .sheet { box-shadow: none; border: none; max-width: none; }\n }\n";
|
|
16285
|
+
function buildIngredientsHtml(ingredients) {
|
|
16286
|
+
if (!ingredients.length) return '';
|
|
16287
|
+
var items = ingredients.map(function (item) {
|
|
16288
|
+
return "<li>".concat(escapeHtml(item), "</li>");
|
|
16289
|
+
}).join('');
|
|
16290
|
+
return "\n <section class=\"section\">\n <h2 class=\"section-title\">Ingredients</h2>\n <ul class=\"ingredients-box\">".concat(items, "</ul>\n </section>");
|
|
16291
|
+
}
|
|
16292
|
+
function buildStepsHtml(steps) {
|
|
16293
|
+
if (!steps.length) return '';
|
|
16294
|
+
var items = steps.map(function (step, i) {
|
|
16295
|
+
return "\n <li class=\"step\">\n <div class=\"step-num\">".concat(i + 1, "</div>\n <div class=\"step-text\">").concat(escapeHtml(step), "</div>\n </li>");
|
|
16296
|
+
}).join('');
|
|
16297
|
+
return "\n <section class=\"section\">\n <h2 class=\"section-title\">Method</h2>\n <ol class=\"steps\">".concat(items, "</ol>\n </section>");
|
|
16298
|
+
}
|
|
16299
|
+
function buildNotesHtml(notes) {
|
|
16300
|
+
if (!notes) return '';
|
|
16301
|
+
return "<div class=\"notes\"><strong>Chef's tip</strong>".concat(escapeHtml(notes), "</div>");
|
|
16302
|
+
}
|
|
16303
|
+
function buildPartnerLogoHtml(logoUrl) {
|
|
16304
|
+
if (!logoUrl) return '';
|
|
16305
|
+
return "<div class=\"partner-logo-wrap\"><img class=\"partner-logo\" src=\"".concat(escapeHtml(logoUrl), "\" alt=\"\"></div>");
|
|
16306
|
+
}
|
|
16307
|
+
function buildHeroHeadHtml(logoUrl) {
|
|
16308
|
+
var logo = buildPartnerLogoHtml(logoUrl);
|
|
16309
|
+
var eyebrow = '<div class="eyebrow"><span class="eyebrow-dot"></span> Recipe card</div>';
|
|
16310
|
+
if (!logo) return eyebrow;
|
|
16311
|
+
return "<div class=\"hero-head\">".concat(eyebrow).concat(logo, "</div>");
|
|
16312
|
+
}
|
|
16313
|
+
function buildRecipeHtml(recipe) {
|
|
16314
|
+
var logoUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
16315
|
+
var servings = recipe.servings ? "<div class=\"servings\"><span aria-hidden=\"true\">\uD83C\uDF7D</span> ".concat(escapeHtml(recipe.servings), "</div>") : '';
|
|
16316
|
+
return "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <title>".concat(escapeHtml(recipe.title), "</title>\n <style>").concat(RECIPE_PAGE_CSS, "</style>\n</head>\n<body>\n <article class=\"sheet\">\n <header class=\"hero\">\n <div class=\"hero-inner\">\n ").concat(buildHeroHeadHtml(logoUrl), "\n <h1>").concat(escapeHtml(recipe.title), "</h1>\n ").concat(servings, "\n </div>\n </header>\n <div class=\"content\">\n <div class=\"grid\">\n ").concat(buildIngredientsHtml(recipe.ingredients), "\n ").concat(buildStepsHtml(recipe.steps), "\n </div>\n ").concat(buildNotesHtml(recipe.notes), "\n <p class=\"footer\">Saved from TalkToPC \xB7 Your voice shopping assistant</p>\n </div>\n </article>\n</body>\n</html>");
|
|
16317
|
+
}
|
|
16318
|
+
function downloadRecipeHtml(recipe) {
|
|
16319
|
+
var logoUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
16320
|
+
try {
|
|
16321
|
+
var html = buildRecipeHtml(recipe, logoUrl);
|
|
16322
|
+
var blob = new Blob([html], {
|
|
16323
|
+
type: 'text/html;charset=utf-8'
|
|
16324
|
+
});
|
|
16325
|
+
var url = URL.createObjectURL(blob);
|
|
16326
|
+
var a = document.createElement('a');
|
|
16327
|
+
a.href = url;
|
|
16328
|
+
a.download = "".concat(slugify(recipe.title), ".html");
|
|
16329
|
+
a.rel = 'noopener';
|
|
16330
|
+
document.body.appendChild(a);
|
|
16331
|
+
a.click();
|
|
16332
|
+
a.remove();
|
|
16333
|
+
setTimeout(function () {
|
|
16334
|
+
return URL.revokeObjectURL(url);
|
|
16335
|
+
}, 1000);
|
|
16336
|
+
console.log('[RecipeHandler] Downloaded recipe HTML:', a.download);
|
|
16337
|
+
} catch (e) {
|
|
16338
|
+
console.warn('[RecipeHandler] HTML download failed:', e);
|
|
16339
|
+
}
|
|
16340
|
+
}
|
|
16341
|
+
function injectStyles() {
|
|
16342
|
+
if (document.getElementById(STYLES_ID)) return;
|
|
16343
|
+
var s = document.createElement('style');
|
|
16344
|
+
s.id = STYLES_ID;
|
|
16345
|
+
s.textContent = "\n.ttp-rh-backdrop {\n position: fixed;\n inset: 0;\n z-index: 2147483640;\n background: rgba(15, 23, 20, 0);\n backdrop-filter: blur(0px);\n -webkit-backdrop-filter: blur(0px);\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 16px;\n box-sizing: border-box;\n transition: background 0.32s ease, backdrop-filter 0.32s ease;\n pointer-events: none;\n}\n.ttp-rh-backdrop.ttp-rh-visible {\n background: rgba(15, 23, 20, 0.52);\n backdrop-filter: blur(10px);\n -webkit-backdrop-filter: blur(10px);\n pointer-events: all;\n}\n.ttp-rh-card {\n position: relative;\n width: min(94vw, 680px);\n max-height: calc(100vh - 32px);\n background: #fffcf8;\n border-radius: 24px;\n box-shadow: 0 28px 80px rgba(15, 23, 20, 0.22), 0 8px 24px rgba(15, 23, 20, 0.08);\n display: flex;\n flex-direction: column;\n opacity: 0;\n transform: scale(0.94) translateY(12px);\n transition: opacity 0.32s cubic-bezier(0.23, 1, 0.32, 1),\n transform 0.32s cubic-bezier(0.23, 1, 0.32, 1);\n overflow: hidden;\n border: 1px solid rgba(255, 255, 255, 0.65);\n}\n.ttp-rh-backdrop.ttp-rh-visible .ttp-rh-card {\n opacity: 1;\n transform: scale(1) translateY(0);\n}\n.ttp-rh-hero {\n position: relative;\n padding: 28px 56px 22px 24px;\n background: linear-gradient(135deg, #1e4d3a 0%, #2f6b52 55%, #3d8b67 100%);\n color: #fff;\n flex-shrink: 0;\n}\n.ttp-rh-hero::before {\n content: \"\";\n position: absolute;\n inset: 0;\n background:\n radial-gradient(circle at 85% 15%, rgba(255,255,255,0.16), transparent 42%),\n radial-gradient(circle at 10% 100%, rgba(255,255,255,0.08), transparent 35%);\n pointer-events: none;\n}\n.ttp-rh-hero-inner { position: relative; z-index: 1; }\n.ttp-rh-hero-head {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 12px;\n margin-bottom: 10px;\n padding-right: 36px;\n}\n.ttp-rh-hero-head .ttp-rh-eyebrow { margin-bottom: 0; }\n.ttp-rh-partner-logo-wrap {\n flex-shrink: 0;\n background: rgba(255, 255, 255, 0.95);\n border-radius: 10px;\n padding: 6px 10px;\n max-width: 120px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n.ttp-rh-partner-logo {\n height: 26px;\n width: auto;\n max-width: 100px;\n object-fit: contain;\n display: block;\n}\n.ttp-rh-eyebrow {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n font: 700 11px/1 \"Segoe UI\", system-ui, sans-serif;\n letter-spacing: 0.14em;\n text-transform: uppercase;\n opacity: 0.88;\n margin-bottom: 10px;\n}\n.ttp-rh-eyebrow-dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: #ffd166;\n box-shadow: 0 0 0 4px rgba(255, 209, 102, 0.22);\n}\n.ttp-rh-title {\n font-family: \"Iowan Old Style\", \"Palatino Linotype\", \"Book Antiqua\", Georgia, serif;\n font-size: clamp(1.45rem, 4vw, 1.95rem);\n font-weight: 600;\n line-height: 1.1;\n letter-spacing: -0.02em;\n}\n.ttp-rh-servings {\n display: inline-flex;\n align-items: center;\n gap: 8px;\n margin-top: 14px;\n padding: 7px 13px;\n border-radius: 999px;\n background: rgba(255, 255, 255, 0.14);\n border: 1px solid rgba(255, 255, 255, 0.18);\n font: 500 13px/1.2 \"Segoe UI\", system-ui, sans-serif;\n}\n.ttp-rh-hero-actions {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n margin-top: 18px;\n}\n.ttp-rh-hero-actions .ttp-rh-btn {\n flex: 0 1 auto;\n padding: 10px 16px;\n border: none;\n border-radius: 12px;\n font: 600 13px/1 \"Segoe UI\", system-ui, sans-serif;\n cursor: pointer;\n transition: transform 0.12s ease, background 0.15s ease, box-shadow 0.15s ease;\n}\n.ttp-rh-hero-actions .ttp-rh-btn:active { transform: scale(0.98); }\n.ttp-rh-hero-actions .ttp-rh-btn-secondary {\n background: rgba(255, 255, 255, 0.14);\n color: #fff;\n border: 1px solid rgba(255, 255, 255, 0.28);\n}\n.ttp-rh-hero-actions .ttp-rh-btn-secondary:hover { background: rgba(255, 255, 255, 0.22); }\n.ttp-rh-hero-actions .ttp-rh-btn-primary {\n background: #fff;\n color: #1e4d3a;\n box-shadow: 0 8px 20px rgba(15, 23, 20, 0.18);\n}\n.ttp-rh-hero-actions .ttp-rh-btn-primary:hover { background: #f4faf7; }\n.ttp-rh-close {\n position: absolute;\n top: 16px;\n right: 16px;\n z-index: 2;\n width: 36px;\n height: 36px;\n padding: 0;\n border: 1px solid rgba(255, 255, 255, 0.22);\n border-radius: 50%;\n background: rgba(255, 255, 255, 0.12);\n color: #fff;\n cursor: pointer;\n font-size: 22px;\n line-height: 1;\n backdrop-filter: blur(8px);\n}\n.ttp-rh-close:hover { background: rgba(255, 255, 255, 0.2); }\n.ttp-rh-body {\n padding: 20px 22px 8px;\n overflow-y: auto;\n flex: 1;\n background: linear-gradient(180deg, #fffcf8 0%, #f8f5f0 100%);\n}\n.ttp-rh-grid {\n display: grid;\n grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);\n gap: 18px;\n}\n.ttp-rh-section { min-width: 0; margin-bottom: 0; }\n.ttp-rh-section-title {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 0 0 12px;\n font: 800 11px/1 \"Segoe UI\", system-ui, sans-serif;\n letter-spacing: 0.12em;\n text-transform: uppercase;\n color: #1e4d3a;\n}\n.ttp-rh-section-title::after {\n content: \"\";\n flex: 1;\n height: 1px;\n background: linear-gradient(to right, rgba(28,25,23,0.08), transparent);\n}\n.ttp-rh-ingredients {\n margin: 0;\n padding: 0;\n list-style: none;\n background: #e8f2ec;\n border: 1px solid rgba(47, 107, 82, 0.12);\n border-radius: 14px;\n overflow: hidden;\n}\n.ttp-rh-ingredients li {\n display: flex;\n align-items: flex-start;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid rgba(47, 107, 82, 0.08);\n font: 14px/1.45 \"Segoe UI\", system-ui, sans-serif;\n color: #292524;\n}\n.ttp-rh-ingredients li:last-child { border-bottom: 0; }\n.ttp-rh-ingredients li::before {\n content: \"\";\n flex-shrink: 0;\n width: 7px;\n height: 7px;\n margin-top: 0.45em;\n border-radius: 50%;\n background: #2f6b52;\n box-shadow: 0 0 0 3px rgba(47, 107, 82, 0.14);\n}\n.ttp-rh-steps {\n margin: 0;\n padding: 0;\n list-style: none;\n display: grid;\n gap: 10px;\n}\n.ttp-rh-step {\n display: grid;\n grid-template-columns: 32px minmax(0, 1fr);\n gap: 12px;\n padding: 12px 14px;\n background: #fff;\n border: 1px solid rgba(28, 25, 23, 0.08);\n border-radius: 14px;\n box-shadow: 0 6px 18px rgba(28, 25, 23, 0.04);\n}\n.ttp-rh-step-num {\n width: 32px;\n height: 32px;\n border-radius: 10px;\n display: grid;\n place-items: center;\n background: linear-gradient(180deg, #fdf3eb, #fff);\n border: 1px solid rgba(196, 113, 58, 0.18);\n color: #c4713a;\n font: 800 13px/1 \"Segoe UI\", system-ui, sans-serif;\n}\n.ttp-rh-step-text {\n font: 14px/1.45 \"Segoe UI\", system-ui, sans-serif;\n color: #292524;\n padding-top: 5px;\n}\n.ttp-rh-notes-wrap { margin-top: 16px; }\n.ttp-rh-notes {\n padding: 14px 16px;\n border-radius: 14px;\n background: #fdf3eb;\n border: 1px solid rgba(196, 113, 58, 0.16);\n font: 13px/1.5 \"Segoe UI\", system-ui, sans-serif;\n color: #57534e;\n}\n.ttp-rh-notes-label {\n display: block;\n margin-bottom: 6px;\n font: 800 11px/1 \"Segoe UI\", system-ui, sans-serif;\n letter-spacing: 0.08em;\n text-transform: uppercase;\n color: #9a3412;\n}\n@media (max-width: 640px) {\n .ttp-rh-backdrop { padding: 10px; }\n .ttp-rh-card { width: calc(100vw - 20px); border-radius: 20px; }\n .ttp-rh-grid { grid-template-columns: 1fr; }\n .ttp-rh-hero { padding: 24px 52px 22px 20px; }\n .ttp-rh-hero-actions { margin-top: 14px; }\n .ttp-rh-hero-actions .ttp-rh-btn { flex: 1 1 calc(50% - 5px); min-width: 120px; }\n}\n";
|
|
16346
|
+
document.head.appendChild(s);
|
|
16347
|
+
}
|
|
16348
|
+
function _appendSectionTitle(parent, label) {
|
|
16349
|
+
var title = document.createElement('h3');
|
|
16350
|
+
title.className = 'ttp-rh-section-title';
|
|
16351
|
+
title.textContent = label;
|
|
16352
|
+
parent.appendChild(title);
|
|
16353
|
+
}
|
|
16354
|
+
function createRecipeHandler(widget) {
|
|
16355
|
+
var backdrop = null;
|
|
16356
|
+
var _dismissed = false;
|
|
16357
|
+
var _savedHostZIndex = null;
|
|
16358
|
+
var _printFrame = null;
|
|
16359
|
+
var _lastLogoUrl = null;
|
|
16360
|
+
var _openedAsReshow = false;
|
|
16361
|
+
function _minimizeWidget() {
|
|
16362
|
+
try {
|
|
16363
|
+
var _widget$shadowRoot;
|
|
16364
|
+
var host = widget === null || widget === void 0 || (_widget$shadowRoot = widget.shadowRoot) === null || _widget$shadowRoot === void 0 ? void 0 : _widget$shadowRoot.host;
|
|
16365
|
+
if (host) {
|
|
16366
|
+
_savedHostZIndex = host.style.zIndex || null;
|
|
16367
|
+
host.style.zIndex = String(2147483641);
|
|
16368
|
+
}
|
|
16369
|
+
} catch (e) {/* best-effort */}
|
|
16370
|
+
}
|
|
16371
|
+
function _restoreWidget() {
|
|
16372
|
+
try {
|
|
16373
|
+
var _widget$shadowRoot2;
|
|
16374
|
+
var host = widget === null || widget === void 0 || (_widget$shadowRoot2 = widget.shadowRoot) === null || _widget$shadowRoot2 === void 0 ? void 0 : _widget$shadowRoot2.host;
|
|
16375
|
+
if (host) {
|
|
16376
|
+
host.style.zIndex = _savedHostZIndex || '';
|
|
16377
|
+
_savedHostZIndex = null;
|
|
16378
|
+
}
|
|
16379
|
+
} catch (e) {/* best-effort */}
|
|
16380
|
+
}
|
|
16381
|
+
function _teardownFrame() {
|
|
16382
|
+
var _printFrame2;
|
|
16383
|
+
if ((_printFrame2 = _printFrame) !== null && _printFrame2 !== void 0 && _printFrame2.parentNode) {
|
|
16384
|
+
_printFrame.parentNode.removeChild(_printFrame);
|
|
16385
|
+
}
|
|
16386
|
+
_printFrame = null;
|
|
16387
|
+
}
|
|
16388
|
+
function _appendHeroHead(heroInner, logoUrl) {
|
|
16389
|
+
var eyebrow = document.createElement('div');
|
|
16390
|
+
eyebrow.className = 'ttp-rh-eyebrow';
|
|
16391
|
+
eyebrow.innerHTML = '<span class="ttp-rh-eyebrow-dot"></span> Recipe card';
|
|
16392
|
+
if (!logoUrl) {
|
|
16393
|
+
heroInner.appendChild(eyebrow);
|
|
16394
|
+
return;
|
|
16395
|
+
}
|
|
16396
|
+
var head = document.createElement('div');
|
|
16397
|
+
head.className = 'ttp-rh-hero-head';
|
|
16398
|
+
head.appendChild(eyebrow);
|
|
16399
|
+
var logoWrap = document.createElement('div');
|
|
16400
|
+
logoWrap.className = 'ttp-rh-partner-logo-wrap';
|
|
16401
|
+
var logoImg = document.createElement('img');
|
|
16402
|
+
logoImg.className = 'ttp-rh-partner-logo';
|
|
16403
|
+
logoImg.src = logoUrl;
|
|
16404
|
+
logoImg.alt = '';
|
|
16405
|
+
logoWrap.appendChild(logoImg);
|
|
16406
|
+
head.appendChild(logoWrap);
|
|
16407
|
+
heroInner.appendChild(head);
|
|
16408
|
+
}
|
|
16409
|
+
function _buildCard(recipe) {
|
|
16410
|
+
var logoUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
16411
|
+
var card = document.createElement('div');
|
|
16412
|
+
card.className = 'ttp-rh-card';
|
|
16413
|
+
card.addEventListener('click', function (e) {
|
|
16414
|
+
return e.stopPropagation();
|
|
16415
|
+
});
|
|
16416
|
+
var closeBtn = document.createElement('button');
|
|
16417
|
+
closeBtn.className = 'ttp-rh-close';
|
|
16418
|
+
closeBtn.setAttribute('aria-label', 'Close recipe');
|
|
16419
|
+
closeBtn.textContent = "\xD7";
|
|
16420
|
+
closeBtn.addEventListener('click', dismissRecipe);
|
|
16421
|
+
var hero = document.createElement('header');
|
|
16422
|
+
hero.className = 'ttp-rh-hero';
|
|
16423
|
+
var heroInner = document.createElement('div');
|
|
16424
|
+
heroInner.className = 'ttp-rh-hero-inner';
|
|
16425
|
+
_appendHeroHead(heroInner, logoUrl);
|
|
16426
|
+
var titleEl = document.createElement('div');
|
|
16427
|
+
titleEl.className = 'ttp-rh-title';
|
|
16428
|
+
titleEl.textContent = recipe.title;
|
|
16429
|
+
heroInner.appendChild(titleEl);
|
|
16430
|
+
if (recipe.servings) {
|
|
16431
|
+
var servEl = document.createElement('div');
|
|
16432
|
+
servEl.className = 'ttp-rh-servings';
|
|
16433
|
+
servEl.innerHTML = "<span aria-hidden=\"true\">\uD83C\uDF7D</span> ".concat(recipe.servings);
|
|
16434
|
+
heroInner.appendChild(servEl);
|
|
16435
|
+
}
|
|
16436
|
+
var actions = document.createElement('div');
|
|
16437
|
+
actions.className = 'ttp-rh-hero-actions';
|
|
16438
|
+
var saveBtn = document.createElement('button');
|
|
16439
|
+
saveBtn.className = 'ttp-rh-btn ttp-rh-btn-secondary';
|
|
16440
|
+
saveBtn.textContent = 'Save again';
|
|
16441
|
+
saveBtn.addEventListener('click', function () {
|
|
16442
|
+
return downloadRecipeHtml(recipe, logoUrl);
|
|
16443
|
+
});
|
|
16444
|
+
var printBtn = document.createElement('button');
|
|
16445
|
+
printBtn.className = 'ttp-rh-btn ttp-rh-btn-primary';
|
|
16446
|
+
printBtn.textContent = 'Print recipe';
|
|
16447
|
+
printBtn.addEventListener('click', function () {
|
|
16448
|
+
return printRecipe(recipe, logoUrl);
|
|
16449
|
+
});
|
|
16450
|
+
actions.appendChild(saveBtn);
|
|
16451
|
+
actions.appendChild(printBtn);
|
|
16452
|
+
heroInner.appendChild(actions);
|
|
16453
|
+
hero.appendChild(heroInner);
|
|
16454
|
+
hero.appendChild(closeBtn);
|
|
16455
|
+
card.appendChild(hero);
|
|
16456
|
+
var body = document.createElement('div');
|
|
16457
|
+
body.className = 'ttp-rh-body';
|
|
16458
|
+
var grid = document.createElement('div');
|
|
16459
|
+
grid.className = 'ttp-rh-grid';
|
|
16460
|
+
if (recipe.ingredients.length) {
|
|
16461
|
+
var sec = document.createElement('section');
|
|
16462
|
+
sec.className = 'ttp-rh-section';
|
|
16463
|
+
_appendSectionTitle(sec, 'Ingredients');
|
|
16464
|
+
var ul = document.createElement('ul');
|
|
16465
|
+
ul.className = 'ttp-rh-ingredients';
|
|
16466
|
+
recipe.ingredients.forEach(function (item) {
|
|
16467
|
+
var li = document.createElement('li');
|
|
16468
|
+
li.textContent = item;
|
|
16469
|
+
ul.appendChild(li);
|
|
16470
|
+
});
|
|
16471
|
+
sec.appendChild(ul);
|
|
16472
|
+
grid.appendChild(sec);
|
|
16473
|
+
}
|
|
16474
|
+
if (recipe.steps.length) {
|
|
16475
|
+
var _sec = document.createElement('section');
|
|
16476
|
+
_sec.className = 'ttp-rh-section';
|
|
16477
|
+
_appendSectionTitle(_sec, 'Method');
|
|
16478
|
+
var ol = document.createElement('ol');
|
|
16479
|
+
ol.className = 'ttp-rh-steps';
|
|
16480
|
+
recipe.steps.forEach(function (step, index) {
|
|
16481
|
+
var li = document.createElement('li');
|
|
16482
|
+
li.className = 'ttp-rh-step';
|
|
16483
|
+
var num = document.createElement('div');
|
|
16484
|
+
num.className = 'ttp-rh-step-num';
|
|
16485
|
+
num.textContent = String(index + 1);
|
|
16486
|
+
var text = document.createElement('div');
|
|
16487
|
+
text.className = 'ttp-rh-step-text';
|
|
16488
|
+
text.textContent = step;
|
|
16489
|
+
li.appendChild(num);
|
|
16490
|
+
li.appendChild(text);
|
|
16491
|
+
ol.appendChild(li);
|
|
16492
|
+
});
|
|
16493
|
+
_sec.appendChild(ol);
|
|
16494
|
+
grid.appendChild(_sec);
|
|
16495
|
+
}
|
|
16496
|
+
body.appendChild(grid);
|
|
16497
|
+
if (recipe.notes) {
|
|
16498
|
+
var notesWrap = document.createElement('div');
|
|
16499
|
+
notesWrap.className = 'ttp-rh-notes-wrap';
|
|
16500
|
+
var notes = document.createElement('div');
|
|
16501
|
+
notes.className = 'ttp-rh-notes';
|
|
16502
|
+
var label = document.createElement('span');
|
|
16503
|
+
label.className = 'ttp-rh-notes-label';
|
|
16504
|
+
label.textContent = "Chef's tip";
|
|
16505
|
+
notes.appendChild(label);
|
|
16506
|
+
notes.appendChild(document.createTextNode(recipe.notes));
|
|
16507
|
+
notesWrap.appendChild(notes);
|
|
16508
|
+
body.appendChild(notesWrap);
|
|
16509
|
+
}
|
|
16510
|
+
card.appendChild(body);
|
|
16511
|
+
return card;
|
|
16512
|
+
}
|
|
16513
|
+
function printRecipe(recipe) {
|
|
16514
|
+
var _frame$contentWindow, _frame$contentWindow2, _frame$contentWindow3;
|
|
16515
|
+
var logoUrl = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
|
|
16516
|
+
_teardownFrame();
|
|
16517
|
+
var frame = document.createElement('iframe');
|
|
16518
|
+
frame.style.cssText = 'position:fixed;right:0;bottom:0;width:0;height:0;border:0;';
|
|
16519
|
+
document.body.appendChild(frame);
|
|
16520
|
+
_printFrame = frame;
|
|
16521
|
+
var doc = frame.contentDocument || ((_frame$contentWindow = frame.contentWindow) === null || _frame$contentWindow === void 0 ? void 0 : _frame$contentWindow.document);
|
|
16522
|
+
if (!doc) return;
|
|
16523
|
+
doc.open();
|
|
16524
|
+
doc.write(buildRecipeHtml(recipe, logoUrl !== null && logoUrl !== void 0 ? logoUrl : _lastLogoUrl));
|
|
16525
|
+
doc.close();
|
|
16526
|
+
(_frame$contentWindow2 = frame.contentWindow) === null || _frame$contentWindow2 === void 0 || _frame$contentWindow2.focus();
|
|
16527
|
+
(_frame$contentWindow3 = frame.contentWindow) === null || _frame$contentWindow3 === void 0 || _frame$contentWindow3.print();
|
|
16528
|
+
}
|
|
16529
|
+
function handleShowRecipe(_x) {
|
|
16530
|
+
return _handleShowRecipe.apply(this, arguments);
|
|
16531
|
+
}
|
|
16532
|
+
function _handleShowRecipe() {
|
|
16533
|
+
_handleShowRecipe = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(msg) {
|
|
16534
|
+
var recipe, partnerId, _t;
|
|
16535
|
+
return _regenerator().w(function (_context) {
|
|
16536
|
+
while (1) switch (_context.n) {
|
|
16537
|
+
case 0:
|
|
16538
|
+
recipe = normalizeRecipe(msg);
|
|
16539
|
+
if (recipe) {
|
|
16540
|
+
_context.n = 1;
|
|
16541
|
+
break;
|
|
16542
|
+
}
|
|
16543
|
+
return _context.a(2);
|
|
16544
|
+
case 1:
|
|
16545
|
+
console.log('[RecipeHandler] show_recipe:', recipe.title);
|
|
16546
|
+
if (backdrop) _teardownImmediate();
|
|
16547
|
+
_dismissed = false;
|
|
16548
|
+
_openedAsReshow = !!(msg !== null && msg !== void 0 && msg.reshow);
|
|
16549
|
+
injectStyles();
|
|
16550
|
+
partnerId = (0,_partnerLogo_js__WEBPACK_IMPORTED_MODULE_0__.resolvePartnerId)(widget, msg);
|
|
16551
|
+
if (!partnerId) {
|
|
16552
|
+
_context.n = 3;
|
|
16553
|
+
break;
|
|
16554
|
+
}
|
|
16555
|
+
_context.n = 2;
|
|
16556
|
+
return (0,_partnerLogo_js__WEBPACK_IMPORTED_MODULE_0__.resolvePartnerLogoUrl)(partnerId);
|
|
16557
|
+
case 2:
|
|
16558
|
+
_t = _context.v;
|
|
16559
|
+
_context.n = 4;
|
|
16560
|
+
break;
|
|
16561
|
+
case 3:
|
|
16562
|
+
_t = null;
|
|
16563
|
+
case 4:
|
|
16564
|
+
_lastLogoUrl = _t;
|
|
16565
|
+
if (!_openedAsReshow) downloadRecipeHtml(recipe, _lastLogoUrl);
|
|
16566
|
+
backdrop = document.createElement('div');
|
|
16567
|
+
backdrop.className = 'ttp-rh-backdrop';
|
|
16568
|
+
backdrop.addEventListener('click', dismissRecipe);
|
|
16569
|
+
backdrop.appendChild(_buildCard(recipe, _lastLogoUrl));
|
|
16570
|
+
document.body.appendChild(backdrop);
|
|
16571
|
+
requestAnimationFrame(function () {
|
|
16572
|
+
requestAnimationFrame(function () {
|
|
16573
|
+
var _backdrop;
|
|
16574
|
+
return (_backdrop = backdrop) === null || _backdrop === void 0 ? void 0 : _backdrop.classList.add('ttp-rh-visible');
|
|
16575
|
+
});
|
|
16576
|
+
});
|
|
16577
|
+
backdrop._escHandler = function (e) {
|
|
16578
|
+
if (e.key === 'Escape') dismissRecipe();
|
|
16579
|
+
};
|
|
16580
|
+
document.addEventListener('keydown', backdrop._escHandler);
|
|
16581
|
+
_minimizeWidget();
|
|
16582
|
+
if (!_openedAsReshow) _saveRecipe(recipe);
|
|
16583
|
+
case 5:
|
|
16584
|
+
return _context.a(2);
|
|
16585
|
+
}
|
|
16586
|
+
}, _callee);
|
|
16587
|
+
}));
|
|
16588
|
+
return _handleShowRecipe.apply(this, arguments);
|
|
16589
|
+
}
|
|
16590
|
+
function _saveRecipe(recipe) {
|
|
16591
|
+
try {
|
|
16592
|
+
var store = typeof (widget === null || widget === void 0 ? void 0 : widget.getRecipeStore) === 'function' ? widget.getRecipeStore() : null;
|
|
16593
|
+
if (store) store.add(recipe);
|
|
16594
|
+
} catch (e) {
|
|
16595
|
+
console.warn('[RecipeHandler] Could not save recipe:', e);
|
|
16596
|
+
}
|
|
16597
|
+
}
|
|
16598
|
+
function _pulseStripBadge() {
|
|
16599
|
+
try {
|
|
16600
|
+
var _widget$_ecommerceVoi, _widget$_ecommerceVoi2;
|
|
16601
|
+
widget === null || widget === void 0 || (_widget$_ecommerceVoi = widget._ecommerceVoiceStrip) === null || _widget$_ecommerceVoi === void 0 || (_widget$_ecommerceVoi2 = _widget$_ecommerceVoi.pulseRecipeBadge) === null || _widget$_ecommerceVoi2 === void 0 || _widget$_ecommerceVoi2.call(_widget$_ecommerceVoi);
|
|
16602
|
+
} catch (e) {/* best-effort */}
|
|
16603
|
+
}
|
|
16604
|
+
function dismissRecipe() {
|
|
16605
|
+
var opts = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
16606
|
+
var _opts$animate = opts.animate,
|
|
16607
|
+
animate = _opts$animate === void 0 ? true : _opts$animate;
|
|
16608
|
+
if (_dismissed || !backdrop) return;
|
|
16609
|
+
_dismissed = true;
|
|
16610
|
+
backdrop.classList.remove('ttp-rh-visible');
|
|
16611
|
+
var el = backdrop;
|
|
16612
|
+
setTimeout(function () {
|
|
16613
|
+
if (el.parentNode) el.parentNode.removeChild(el);
|
|
16614
|
+
if (el._escHandler) document.removeEventListener('keydown', el._escHandler);
|
|
16615
|
+
}, 320);
|
|
16616
|
+
backdrop = null;
|
|
16617
|
+
_restoreWidget();
|
|
16618
|
+
if (animate && !_openedAsReshow) {
|
|
16619
|
+
// Slight delay so the modal fade finishes before the strip badge celebrates.
|
|
16620
|
+
setTimeout(function () {
|
|
16621
|
+
return _pulseStripBadge();
|
|
16622
|
+
}, 180);
|
|
16623
|
+
}
|
|
16624
|
+
_openedAsReshow = false;
|
|
16625
|
+
}
|
|
16626
|
+
function _teardownImmediate() {
|
|
16627
|
+
if (backdrop) {
|
|
16628
|
+
if (backdrop._escHandler) document.removeEventListener('keydown', backdrop._escHandler);
|
|
16629
|
+
if (backdrop.parentNode) backdrop.parentNode.removeChild(backdrop);
|
|
16630
|
+
backdrop = null;
|
|
16631
|
+
}
|
|
16632
|
+
_restoreWidget();
|
|
16633
|
+
}
|
|
16634
|
+
return {
|
|
16635
|
+
handleShowRecipe: handleShowRecipe,
|
|
16636
|
+
dismissRecipe: dismissRecipe,
|
|
16637
|
+
buildRecipeHtml: buildRecipeHtml,
|
|
16638
|
+
downloadRecipeHtml: downloadRecipeHtml
|
|
16639
|
+
};
|
|
16640
|
+
}
|
|
16641
|
+
|
|
16642
|
+
/***/ }),
|
|
16643
|
+
|
|
16644
|
+
/***/ "./src/ecommerce/RecipeStore.js":
|
|
16645
|
+
/*!**************************************!*\
|
|
16646
|
+
!*** ./src/ecommerce/RecipeStore.js ***!
|
|
16647
|
+
\**************************************/
|
|
16648
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
16649
|
+
|
|
16650
|
+
"use strict";
|
|
16651
|
+
__webpack_require__.r(__webpack_exports__);
|
|
16652
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
16653
|
+
/* harmony export */ createRecipeStore: () => (/* binding */ createRecipeStore),
|
|
16654
|
+
/* harmony export */ recipeStorageKey: () => (/* binding */ recipeStorageKey)
|
|
16655
|
+
/* harmony export */ });
|
|
16656
|
+
/**
|
|
16657
|
+
* Persist saved recipes in localStorage (scoped by storage key).
|
|
16658
|
+
* In-memory list is the source of truth; subscribers get notified on change.
|
|
16659
|
+
*/
|
|
16660
|
+
|
|
16661
|
+
var MAX_RECIPES = 50;
|
|
16662
|
+
function slugify(title) {
|
|
16663
|
+
var slug = String(title !== null && title !== void 0 ? title : 'recipe').trim().toLowerCase().replace(/[^a-z0-9]+/gi, '-').replace(/^-+|-+$/g, '');
|
|
16664
|
+
return slug || 'recipe';
|
|
16665
|
+
}
|
|
16666
|
+
|
|
16667
|
+
/**
|
|
16668
|
+
* @param {string} storageKey – e.g. origin + partner id
|
|
16669
|
+
*/
|
|
16670
|
+
function createRecipeStore(storageKey) {
|
|
16671
|
+
var recipes = [];
|
|
16672
|
+
var listeners = new Set();
|
|
16673
|
+
function _notify() {
|
|
16674
|
+
var snapshot = recipes.slice();
|
|
16675
|
+
listeners.forEach(function (fn) {
|
|
16676
|
+
try {
|
|
16677
|
+
fn(snapshot);
|
|
16678
|
+
} catch (e) {/* subscriber */}
|
|
16679
|
+
});
|
|
16680
|
+
}
|
|
16681
|
+
function _load() {
|
|
16682
|
+
try {
|
|
16683
|
+
var raw = window.localStorage.getItem(storageKey);
|
|
16684
|
+
if (!raw) return;
|
|
16685
|
+
var parsed = JSON.parse(raw);
|
|
16686
|
+
if (Array.isArray(parsed)) recipes = parsed;
|
|
16687
|
+
} catch (e) {
|
|
16688
|
+
console.warn('[RecipeStore] Could not load recipes:', e);
|
|
16689
|
+
}
|
|
16690
|
+
}
|
|
16691
|
+
function _persist() {
|
|
16692
|
+
try {
|
|
16693
|
+
window.localStorage.setItem(storageKey, JSON.stringify(recipes));
|
|
16694
|
+
} catch (e) {
|
|
16695
|
+
console.warn('[RecipeStore] Could not persist recipes:', e);
|
|
16696
|
+
}
|
|
16697
|
+
}
|
|
16698
|
+
function getAll() {
|
|
16699
|
+
return recipes.slice();
|
|
16700
|
+
}
|
|
16701
|
+
function add(recipe) {
|
|
16702
|
+
if (!recipe || !recipe.title) return null;
|
|
16703
|
+
var entry = {
|
|
16704
|
+
id: "".concat(slugify(recipe.title), "-").concat(Date.now()),
|
|
16705
|
+
title: recipe.title,
|
|
16706
|
+
ingredients: Array.isArray(recipe.ingredients) ? recipe.ingredients.slice() : [],
|
|
16707
|
+
steps: Array.isArray(recipe.steps) ? recipe.steps.slice() : [],
|
|
16708
|
+
servings: recipe.servings || '',
|
|
16709
|
+
notes: recipe.notes || '',
|
|
16710
|
+
savedAt: Date.now()
|
|
16711
|
+
};
|
|
16712
|
+
recipes.unshift(entry);
|
|
16713
|
+
if (recipes.length > MAX_RECIPES) recipes.length = MAX_RECIPES;
|
|
16714
|
+
_persist();
|
|
16715
|
+
_notify();
|
|
16716
|
+
return entry;
|
|
16717
|
+
}
|
|
16718
|
+
function subscribe(fn) {
|
|
16719
|
+
listeners.add(fn);
|
|
16720
|
+
return function () {
|
|
16721
|
+
return listeners.delete(fn);
|
|
16722
|
+
};
|
|
16723
|
+
}
|
|
16724
|
+
_load();
|
|
16725
|
+
return {
|
|
16726
|
+
getAll: getAll,
|
|
16727
|
+
add: add,
|
|
16728
|
+
subscribe: subscribe,
|
|
16729
|
+
count: function count() {
|
|
16730
|
+
return recipes.length;
|
|
16731
|
+
}
|
|
16732
|
+
};
|
|
16733
|
+
}
|
|
16734
|
+
|
|
16735
|
+
/**
|
|
16736
|
+
* Build a scoped storage key for the current page + partner.
|
|
16737
|
+
* @param {string} [partnerId]
|
|
16738
|
+
*/
|
|
16739
|
+
function recipeStorageKey() {
|
|
16740
|
+
var partnerId = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'default';
|
|
16741
|
+
var origin = typeof window !== 'undefined' ? window.location.origin : '';
|
|
16742
|
+
var path = typeof window !== 'undefined' ? window.location.pathname : '';
|
|
16743
|
+
return "".concat(origin).concat(path, "_ttp_recipes_").concat(partnerId);
|
|
16744
|
+
}
|
|
16745
|
+
|
|
16746
|
+
/***/ }),
|
|
16747
|
+
|
|
16018
16748
|
/***/ "./src/ecommerce/TTPEcommerceWidget.js":
|
|
16019
16749
|
/*!*********************************************!*\
|
|
16020
16750
|
!*** ./src/ecommerce/TTPEcommerceWidget.js ***!
|
|
@@ -16644,18 +17374,165 @@ var VariationDesktopPicker = /*#__PURE__*/function () {
|
|
|
16644
17374
|
\******************************************/
|
|
16645
17375
|
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
16646
17376
|
|
|
16647
|
-
"use strict";
|
|
16648
|
-
__webpack_require__.r(__webpack_exports__);
|
|
16649
|
-
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
16650
|
-
/* harmony export */ generateEcommerceCSS: () => (/* binding */ generateEcommerceCSS)
|
|
16651
|
-
/* harmony export */ });
|
|
16652
|
-
/**
|
|
16653
|
-
* ecommerceStyles - CSS for e-commerce components.
|
|
16654
|
-
* Returns a CSS string to be merged into the shadow root <style> tag.
|
|
16655
|
-
* Follows the same pattern as Styles.generateCSS().
|
|
16656
|
-
*/
|
|
16657
|
-
function generateEcommerceCSS() {
|
|
16658
|
-
return "\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ECOMMERCE AREA\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n\n/*\n * When products are visible, expand the panel dynamically.\n * Actual height is set via inline style by EcommerceManager._expandPanelToFit().\n * When the class is removed, the panel returns to its CSS-defined default.\n */\n#text-chat-panel.ttp-panel-expanded {\n transition: height 0.25s ease;\n}\n\n/*\n * Layout overrides ONLY when ecommerce/hotels overlay is active.\n * Scoped under .ttp-products-visible / .ttp-rooms-visible so the\n * normal voice CSS takes effect when products/rooms are hidden.\n *\n * voiceActiveState is a flex column: [voice-controls] [ecommerce] [conversation].\n * Ecommerce area fills the middle and scrolls; conversation panel stays at bottom.\n */\n#voiceActiveState.ttp-products-visible,\n#voiceActiveState.ttp-rooms-visible {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow: hidden !important;\n}\n\n.ttp-products-visible > .desktop-voice-section,\n.ttp-rooms-visible > .desktop-voice-section {\n flex-shrink: 1 !important;\n}\n\n/* Conversation + input always stick to bottom; ecommerce area above grows to fill. */\n.ttp-products-visible > .desktop-conversation-panel,\n.ttp-rooms-visible > .desktop-conversation-panel {\n flex: 0 0 auto !important;\n margin-top: auto !important;\n display: flex !important;\n flex-direction: column !important;\n}\n\n.ttp-products-visible .desktop-conversation-panel .live-transcript-collapsed,\n.ttp-rooms-visible .desktop-conversation-panel .live-transcript-collapsed {\n flex: 0 0 auto !important;\n min-height: 40px !important;\n overflow: hidden !important;\n}\n\n.ttp-products-visible .desktop-conversation-panel .voice-text-input-area,\n.ttp-rooms-visible .desktop-conversation-panel .voice-text-input-area {\n margin-top: auto !important;\n padding: 3px 16px !important;\n}\n\n.ttp-products-visible .desktop-conversation-panel .voice-input-hint,\n.ttp-rooms-visible .desktop-conversation-panel .voice-input-hint {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-voice-section {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .compact-voice-section {\n display: flex !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-conversation-panel {\n flex: 0 0 auto !important;\n}\n\n#voiceActiveState.ttp-products-visible .conversation-history {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .live-transcript-collapsed {\n flex: 0 0 auto !important;\n}\n\n.voice-text-input-area {\n flex-shrink: 0 !important;\n}\n\n.ttp-products-visible .conversation-history,\n.ttp-rooms-visible .conversation-history {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow-y: auto !important;\n}\n\n.ttp-ecommerce-area {\n display: flex !important;\n flex-direction: column !important;\n width: 100%;\n flex: 1 1 0 !important;\n min-height: 0 !important;\n position: relative !important;\n overflow-x: hidden !important;\n overflow-y: hidden !important;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT PICKER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-picker {\n background: rgba(255,255,255,0.04);\n border-radius: 14px;\n border: 1px solid rgba(255,255,255,0.08);\n box-shadow: none;\n margin: 8px 10px;\n overflow-x: hidden !important;\n overflow-y: auto !important;\n animation: ttpSlideUp 0.25s ease;\n display: flex !important;\n flex-direction: column;\n flex: 1;\n min-height: 0 !important;\n}\n\n@keyframes ttpSlideUp {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.ttp-picker-header {\n display: flex !important;\n justify-content: space-between;\n align-items: center;\n padding: 10px 14px;\n border-bottom: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n}\n\n.ttp-picker-title {\n font-size: 12px;\n font-weight: 600;\n color: rgba(255,255,255,0.5);\n}\n\n.ttp-picker-close {\n background: none;\n border: none;\n cursor: pointer;\n color: rgba(255,255,255,0.4);\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n}\n.ttp-picker-close:hover {\n background: rgba(255,255,255,0.08);\n color: rgba(255,255,255,0.7);\n}\n\n/* Horizontal card layout */\n.ttp-products-horizontal {\n display: flex !important;\n align-items: flex-start;\n flex-shrink: 0;\n gap: 10px;\n padding: 12px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: thin;\n}\n.ttp-products-horizontal::-webkit-scrollbar { height: 4px; }\n.ttp-products-horizontal::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 2px; }\n.ttp-products-horizontal::-webkit-scrollbar-track { background: transparent; }\n\n/* Vertical list layout */\n.ttp-products-vertical {\n padding: 8px 12px;\n overflow-y: auto !important;\n display: flex !important;\n flex-direction: column;\n gap: 6px;\n flex: 1;\n min-height: 0 !important;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT CARD (horizontal)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-card {\n width: 170px !important;\n flex-shrink: 0 !important;\n background: rgba(255,255,255,0.04);\n border-radius: 12px;\n border: 1px solid rgba(255,255,255,0.08);\n overflow: hidden;\n transition: border-color 0.15s;\n}\n.ttp-product-card:hover { border-color: rgba(109,86,245,0.5); }\n\n.ttp-product-image {\n height: 110px !important;\n background: rgba(0,0,0,0.2);\n display: flex !important;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n}\n.ttp-product-image img {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n object-fit: contain !important;\n display: block !important;\n}\n\n.ttp-stock-badge {\n position: absolute;\n top: 6px; right: 6px;\n background: rgba(239,68,68,0.15);\n color: #ef4444;\n font-size: 9px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.ttp-product-details {\n padding: 10px 12px 14px;\n}\n\n.ttp-product-name {\n font-size: 13px;\n font-weight: 600;\n color: #e8e4f0;\n line-height: 1.3;\n min-height: 30px;\n}\n\n.ttp-product-page-link {\n display: inline-flex;\n align-items: center;\n margin-left: 5px;\n font-size: 10px;\n color: #a78bfa;\n text-decoration: none;\n opacity: 0.7;\n vertical-align: middle;\n}\n.ttp-product-page-link:hover { opacity: 1; text-decoration: underline; }\n\n.ttp-product-meta {\n font-size: 10px;\n color: rgba(255,255,255,0.35);\n margin-top: 2px;\n}\n\n.ttp-product-footer {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n margin-top: 6px;\n}\n\n.ttp-product-price {\n font-size: 14px;\n font-weight: 700;\n color: #e8e4f0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT COMPACT (list view)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-compact {\n display: flex !important;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n background: rgba(255,255,255,0.04);\n border-radius: 10px;\n border: 1px solid rgba(255,255,255,0.08);\n transition: border-color 0.15s;\n}\n.ttp-product-compact:hover { border-color: rgba(109,86,245,0.5); }\n\n.ttp-product-image-sm {\n width: 72px !important; height: 72px !important;\n border-radius: 10px;\n background: rgba(0,0,0,0.2);\n display: flex !important;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n}\n.ttp-product-image-sm img {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n object-fit: contain !important;\n display: block !important;\n}\n\n.ttp-product-compact .ttp-product-info {\n flex: 1;\n min-width: 0;\n}\n.ttp-product-compact .ttp-product-name {\n min-height: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: #e8e4f0;\n}\n.ttp-product-compact .ttp-product-action {\n text-align: right;\n flex-shrink: 0 !important;\n}\n.ttp-product-compact .ttp-product-price {\n font-size: 13px;\n}\n\n.ttp-out-of-stock {\n font-size: 10px;\n color: #f87171;\n font-weight: 500;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ADD BUTTON\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-add-btn {\n padding: 6px 14px;\n border-radius: 8px;\n border: 1.5px solid rgba(109,86,245,0.6);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n background: transparent;\n color: #a78bfa;\n transition: all 0.15s;\n}\n.ttp-add-btn:hover { background: rgba(109,86,245,0.15); border-color: #a78bfa; }\n.ttp-add-btn:active { transform: scale(0.95); }\n.ttp-add-btn.ttp-added { background: rgba(109,86,245,0.6) !important; border-color: #7c3aed !important; color: #fff !important; }\n.ttp-add-btn:disabled { cursor: default; opacity: 0.5; }\n.ttp-add-btn.ttp-update-btn { background: rgba(245,158,11,0.15); border-color: rgba(245,158,11,0.5); color: #fbbf24; }\n.ttp-add-btn.ttp-update-btn:hover { background: rgba(245,158,11,0.25); border-color: #fbbf24; }\n\n.ttp-products-animating .ttp-add-btn {\n opacity: 0.4;\n pointer-events: none;\n cursor: not-allowed;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CART TOAST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* Toast replaces waveform in desktop voice section */\n.ttp-cart-toast {\n display: flex !important;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n margin: 8px 12px;\n background: rgba(16,185,129,0.1);\n border-radius: 12px;\n border: 1px solid rgba(16,185,129,0.2);\n animation: ttpToastIn 0.25s ease;\n flex-shrink: 0;\n box-shadow: none;\n}\n\n@keyframes ttpToastIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ttp-cart-toast.ttp-toast-hiding {\n animation: ttpSlideDown 0.3s ease forwards;\n}\n\n@keyframes ttpSlideDown {\n to { opacity: 0; transform: translateY(-8px); height: 0; padding: 0; margin: 0; overflow: hidden; }\n}\n\n.ttp-toast-icon {\n width: 24px !important; height: 24px !important;\n border-radius: 50%;\n background: #10b981;\n color: #fff;\n display: flex !important;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n flex-shrink: 0;\n}\n\n.ttp-toast-content { flex: 1; min-width: 0; }\n.ttp-toast-title { font-size: 12px; font-weight: 600; color: #34d399; }\n.ttp-toast-product {\n font-size: 11px;\n color: rgba(52,211,153,0.7);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ttp-toast-undo {\n background: none;\n border: 1px solid rgba(52,211,153,0.3);\n border-radius: 6px;\n padding: 3px 8px;\n font-size: 10px;\n color: #34d399;\n cursor: pointer;\n font-weight: 600;\n flex-shrink: 0;\n}\n.ttp-toast-undo:hover { background: rgba(52,211,153,0.1); }\n\n/* Fly-to-cart desktop target (when cart summary is hidden) */\n.ttp-desktop-fly-target {\n position: absolute;\n bottom: 12px;\n right: 80px;\n width: 24px;\n height: 24px;\n pointer-events: none;\n}\n\n/* Fly-to-cart ripple effect */\n.ttp-fly-ripple {\n position: absolute;\n left: 10px;\n top: 50%;\n width: 30px;\n height: 30px;\n margin-top: -15px;\n border-radius: 50%;\n border: 2px solid rgba(74,222,128,0.7);\n animation: ttp-ripple-expand 0.6s ease-out forwards;\n pointer-events: none;\n}\n\n@keyframes ttp-ripple-expand {\n 0% { transform: scale(0.5); opacity: 0.8; }\n 100% { transform: scale(3); opacity: 0; }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n QUANTITY/WEIGHT STEPPER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-stepper {\n display: flex !important;\n align-items: center;\n gap: 2px;\n margin: 4px 0;\n}\n\n.ttp-stepper-btn {\n width: 24px !important;\n height: 24px !important;\n border-radius: 6px;\n border: 1px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.06);\n color: rgba(255,255,255,0.6);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n display: flex !important;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.ttp-stepper-btn:hover:not(:disabled) {\n background: rgba(255,255,255,0.12);\n border-color: rgba(255,255,255,0.25);\n}\n\n.ttp-stepper-btn:active:not(:disabled) {\n transform: scale(0.9);\n}\n\n.ttp-stepper-btn:disabled,\n.ttp-stepper-disabled {\n opacity: 0.35;\n cursor: default;\n}\n\n.ttp-stepper-value {\n font-size: 12px;\n font-weight: 600;\n color: #e8e4f0;\n min-width: 36px;\n text-align: center;\n user-select: none;\n}\n\n.ttp-product-compact .ttp-stepper {\n justify-content: flex-end;\n}\n\n.ttp-product-compact .ttp-product-action {\n display: flex !important;\n flex-direction: column;\n align-items: flex-end;\n gap: 2px;\n}\n\n.ttp-product-card .ttp-stepper {\n justify-content: center;\n margin: 4px 0;\n}\n\n.ttp-product-card .ttp-product-footer {\n display: flex !important;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIATION DESKTOP PICKER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.picker-relative {\n position: relative !important;\n flex: 1 1 0 !important;\n min-height: 0 !important;\n display: flex !important;\n flex-direction: column !important;\n overflow: hidden;\n}\n\n/* When variant picker is shown, center it horizontally and vertically */\n.picker-relative.ttp-var-picker-active {\n justify-content: center !important;\n align-items: center !important;\n}\n\n.ttp-var-picker {\n background: rgba(255,255,255,0.04);\n border-radius: 14px;\n border: 1px solid rgba(255,255,255,0.08);\n display: flex !important;\n flex-direction: column;\n animation: ttpVarFadeIn 0.2s ease;\n overflow: hidden;\n width: 100%;\n flex-shrink: 0 !important;\n}\n\n@keyframes ttpVarFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.ttp-var-header {\n display: flex !important;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n}\n\n.ttp-var-back-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: rgba(255,255,255,0.5);\n font-size: 16px;\n padding: 0;\n display: flex;\n align-items: center;\n line-height: 1;\n font-family: inherit;\n}\n.ttp-var-back-btn:hover { color: #e8e4f0; }\n\n.ttp-var-title {\n font-size: 13px;\n font-weight: 700;\n color: #e8e4f0;\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ttp-var-page-link {\n font-size: 11px;\n color: #a78bfa;\n text-decoration: none;\n font-weight: 500;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.ttp-var-page-link:hover { text-decoration: underline; }\n\n.ttp-var-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px 14px;\n display: flex !important;\n flex-direction: column;\n gap: 14px;\n}\n\n.ttp-var-preview {\n display: flex !important;\n gap: 12px;\n align-items: flex-start;\n}\n\n.ttp-var-preview-img {\n width: 72px !important;\n height: 72px !important;\n border-radius: 12px;\n background: rgba(0,0,0,0.2);\n border: 1px solid rgba(255,255,255,0.08);\n display: flex !important;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n transition: all 0.2s ease;\n}\n\n.ttp-var-preview-img img {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n object-fit: contain !important;\n display: block !important;\n padding: 6px;\n}\n\n.ttp-var-preview-info { flex: 1; min-width: 0; }\n\n.ttp-var-preview-brand {\n font-size: 10px;\n color: rgba(255,255,255,0.4);\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.ttp-var-preview-name {\n font-size: 14px;\n font-weight: 700;\n color: #e8e4f0;\n margin: 2px 0 4px;\n line-height: 1.2;\n}\n\n.ttp-var-preview-price {\n font-size: 18px;\n font-weight: 700;\n color: #7c3aed;\n}\n\n.ttp-var-preview-selected {\n font-size: 11px;\n color: rgba(255,255,255,0.4);\n margin-top: 3px;\n}\n\n.ttp-var-section { display: flex !important; flex-direction: column; gap: 8px; }\n\n.ttp-var-section-label {\n font-size: 11px;\n font-weight: 700;\n color: rgba(255,255,255,0.5);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.ttp-var-swatches { display: flex !important; flex-wrap: wrap; gap: 8px; }\n\n.ttp-var-swatch {\n display: block !important;\n width: 28px !important;\n height: 28px !important;\n border-radius: 50%;\n cursor: pointer;\n border: 3px solid transparent;\n transition: all 0.15s;\n position: relative;\n flex-shrink: 0;\n}\n.ttp-var-swatch:hover { transform: scale(1.1); }\n.ttp-var-swatch.selected {\n border-color: #7c3aed;\n box-shadow: 0 0 0 2px #fff, 0 0 0 4px #7c3aed;\n}\n.ttp-var-swatch.oos {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.ttp-var-pills { display: flex !important; flex-wrap: wrap; gap: 6px; }\n\n.ttp-var-pill {\n padding: 5px 12px;\n border-radius: 8px;\n border: 1.5px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n font-size: 12px;\n font-weight: 600;\n color: rgba(255,255,255,0.6);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n}\n.ttp-var-pill:hover:not(:disabled) { border-color: #7c3aed; color: #a78bfa; }\n.ttp-var-pill.selected { border-color: #7c3aed; background: #7c3aed; color: #fff; }\n.ttp-var-pill.oos { opacity: 0.35; cursor: not-allowed; text-decoration: line-through; }\n\n.ttp-var-footer {\n padding: 10px 14px 12px;\n border-top: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n}\n\n.ttp-var-add-btn {\n width: 100%;\n padding: 10px;\n background: linear-gradient(135deg, #7c3aed, #6d28d9);\n color: #fff;\n border: none;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n font-family: inherit;\n box-shadow: 0 3px 10px rgba(124,58,237,0.3);\n transition: all 0.15s;\n}\n.ttp-var-add-btn:hover:not(:disabled) { transform: scale(0.99); }\n.ttp-var-add-btn:disabled {\n background: rgba(255,255,255,0.1);\n box-shadow: none;\n cursor: not-allowed;\n color: rgba(255,255,255,0.3);\n}\n\n.ttp-var-spinner {\n width: 24px;\n height: 24px;\n border: 3px solid rgba(255,255,255,0.1);\n border-top-color: #7c3aed;\n border-radius: 50%;\n animation: ttpVarSpin 0.7s linear infinite;\n}\n@keyframes ttpVarSpin {\n to { transform: rotate(360deg); }\n}\n\n/* Amber \"Choose\" button for variant products */\n.ttp-add-btn.ttp-choose-btn {\n background: linear-gradient(135deg, #f59e0b, #d97706);\n box-shadow: 0 2px 8px rgba(245,158,11,0.3);\n color: #fff;\n}\n\n ";
|
|
17377
|
+
"use strict";
|
|
17378
|
+
__webpack_require__.r(__webpack_exports__);
|
|
17379
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
17380
|
+
/* harmony export */ generateEcommerceCSS: () => (/* binding */ generateEcommerceCSS)
|
|
17381
|
+
/* harmony export */ });
|
|
17382
|
+
/**
|
|
17383
|
+
* ecommerceStyles - CSS for e-commerce components.
|
|
17384
|
+
* Returns a CSS string to be merged into the shadow root <style> tag.
|
|
17385
|
+
* Follows the same pattern as Styles.generateCSS().
|
|
17386
|
+
*/
|
|
17387
|
+
function generateEcommerceCSS() {
|
|
17388
|
+
return "\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ECOMMERCE AREA\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n\n/*\n * When products are visible, expand the panel dynamically.\n * Actual height is set via inline style by EcommerceManager._expandPanelToFit().\n * When the class is removed, the panel returns to its CSS-defined default.\n */\n#text-chat-panel.ttp-panel-expanded {\n transition: height 0.25s ease;\n}\n\n/*\n * Layout overrides ONLY when ecommerce/hotels overlay is active.\n * Scoped under .ttp-products-visible / .ttp-rooms-visible so the\n * normal voice CSS takes effect when products/rooms are hidden.\n *\n * voiceActiveState is a flex column: [voice-controls] [ecommerce] [conversation].\n * Ecommerce area fills the middle and scrolls; conversation panel stays at bottom.\n */\n#voiceActiveState.ttp-products-visible,\n#voiceActiveState.ttp-rooms-visible {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow: hidden !important;\n}\n\n.ttp-products-visible > .desktop-voice-section,\n.ttp-rooms-visible > .desktop-voice-section {\n flex-shrink: 1 !important;\n}\n\n/* Conversation + input always stick to bottom; ecommerce area above grows to fill. */\n.ttp-products-visible > .desktop-conversation-panel,\n.ttp-rooms-visible > .desktop-conversation-panel {\n flex: 0 0 auto !important;\n margin-top: auto !important;\n display: flex !important;\n flex-direction: column !important;\n}\n\n.ttp-products-visible .desktop-conversation-panel .live-transcript-collapsed,\n.ttp-rooms-visible .desktop-conversation-panel .live-transcript-collapsed {\n flex: 0 0 auto !important;\n min-height: 40px !important;\n overflow: hidden !important;\n}\n\n.ttp-products-visible .desktop-conversation-panel .voice-text-input-area,\n.ttp-rooms-visible .desktop-conversation-panel .voice-text-input-area {\n margin-top: auto !important;\n padding: 3px 16px !important;\n}\n\n.ttp-products-visible .desktop-conversation-panel .voice-input-hint,\n.ttp-rooms-visible .desktop-conversation-panel .voice-input-hint {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-voice-section {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .compact-voice-section {\n display: flex !important;\n}\n\n#voiceActiveState.ttp-products-visible .desktop-conversation-panel {\n flex: 0 0 auto !important;\n}\n\n#voiceActiveState.ttp-products-visible .conversation-history {\n display: none !important;\n}\n\n#voiceActiveState.ttp-products-visible .live-transcript-collapsed {\n flex: 0 0 auto !important;\n}\n\n.voice-text-input-area {\n flex-shrink: 0 !important;\n}\n\n.ttp-products-visible .conversation-history,\n.ttp-rooms-visible .conversation-history {\n flex: 1 1 0 !important;\n min-height: 0 !important;\n overflow-y: auto !important;\n}\n\n.ttp-ecommerce-area {\n display: flex !important;\n flex-direction: column !important;\n width: 100%;\n flex: 1 1 0 !important;\n min-height: 0 !important;\n position: relative !important;\n overflow-x: hidden !important;\n overflow-y: hidden !important;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT PICKER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-picker {\n background: rgba(255,255,255,0.04);\n border-radius: 14px;\n border: 1px solid rgba(255,255,255,0.08);\n box-shadow: none;\n margin: 8px 10px;\n overflow-x: hidden !important;\n overflow-y: auto !important;\n animation: ttpSlideUp 0.25s ease;\n display: flex !important;\n flex-direction: column;\n flex: 1;\n min-height: 0 !important;\n}\n\n@keyframes ttpSlideUp {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n\n.ttp-picker-header {\n display: flex !important;\n justify-content: space-between;\n align-items: center;\n padding: 10px 14px;\n border-bottom: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n}\n\n.ttp-picker-title {\n font-size: 12px;\n font-weight: 600;\n color: rgba(255,255,255,0.5);\n}\n\n.ttp-picker-close {\n background: none;\n border: none;\n cursor: pointer;\n color: rgba(255,255,255,0.4);\n font-size: 14px;\n padding: 2px 6px;\n border-radius: 4px;\n}\n.ttp-picker-close:hover {\n background: rgba(255,255,255,0.08);\n color: rgba(255,255,255,0.7);\n}\n\n/* Horizontal card layout */\n.ttp-products-horizontal {\n display: flex !important;\n align-items: flex-start;\n flex-shrink: 0;\n gap: 10px;\n padding: 12px;\n overflow-x: auto;\n -webkit-overflow-scrolling: touch;\n scrollbar-width: thin;\n}\n.ttp-products-horizontal::-webkit-scrollbar { height: 4px; }\n.ttp-products-horizontal::-webkit-scrollbar-thumb { background: rgba(255,255,255,0.15); border-radius: 2px; }\n.ttp-products-horizontal::-webkit-scrollbar-track { background: transparent; }\n\n/* Vertical list layout */\n.ttp-products-vertical {\n padding: 8px 12px;\n overflow-y: auto !important;\n display: flex !important;\n flex-direction: column;\n gap: 6px;\n flex: 1;\n min-height: 0 !important;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT CARD (horizontal)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-card {\n width: 170px !important;\n flex-shrink: 0 !important;\n background: rgba(255,255,255,0.04);\n border-radius: 12px;\n border: 1px solid rgba(255,255,255,0.08);\n overflow: hidden;\n transition: border-color 0.15s;\n}\n.ttp-product-card:hover { border-color: rgba(109,86,245,0.5); }\n\n.ttp-product-image {\n height: 110px !important;\n background: rgba(0,0,0,0.2);\n display: flex !important;\n align-items: center;\n justify-content: center;\n position: relative;\n overflow: hidden;\n}\n.ttp-product-image img {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n object-fit: contain !important;\n display: block !important;\n}\n\n.ttp-stock-badge {\n position: absolute;\n top: 6px; right: 6px;\n background: rgba(239,68,68,0.15);\n color: #ef4444;\n font-size: 9px;\n font-weight: 600;\n padding: 2px 6px;\n border-radius: 4px;\n}\n\n.ttp-product-details {\n padding: 10px 12px 14px;\n}\n\n.ttp-product-name {\n font-size: 13px;\n font-weight: 600;\n color: #e8e4f0;\n line-height: 1.3;\n min-height: 30px;\n}\n\n.ttp-product-page-link {\n display: inline-flex;\n align-items: center;\n margin-left: 5px;\n font-size: 10px;\n color: #a78bfa;\n text-decoration: none;\n opacity: 0.7;\n vertical-align: middle;\n}\n.ttp-product-page-link:hover { opacity: 1; text-decoration: underline; }\n\n.ttp-product-meta {\n font-size: 10px;\n color: rgba(255,255,255,0.35);\n margin-top: 2px;\n}\n\n.ttp-product-footer {\n display: flex !important;\n align-items: center;\n justify-content: space-between;\n margin-top: 6px;\n}\n\n.ttp-product-price {\n font-size: 14px;\n font-weight: 700;\n color: #e8e4f0;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n PRODUCT COMPACT (list view)\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-product-compact {\n display: flex !important;\n align-items: center;\n gap: 10px;\n padding: 8px 10px;\n background: rgba(255,255,255,0.04);\n border-radius: 10px;\n border: 1px solid rgba(255,255,255,0.08);\n transition: border-color 0.15s;\n}\n.ttp-product-compact:hover { border-color: rgba(109,86,245,0.5); }\n\n.ttp-product-image-sm {\n width: 72px !important; height: 72px !important;\n border-radius: 10px;\n background: rgba(0,0,0,0.2);\n display: flex !important;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n}\n.ttp-product-image-sm img {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n object-fit: contain !important;\n display: block !important;\n}\n\n.ttp-product-compact .ttp-product-info {\n flex: 1;\n min-width: 0;\n}\n.ttp-product-compact .ttp-product-name {\n min-height: auto;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n color: #e8e4f0;\n}\n.ttp-product-compact .ttp-product-action {\n text-align: right;\n flex-shrink: 0 !important;\n}\n.ttp-product-compact .ttp-product-price {\n font-size: 13px;\n}\n\n.ttp-out-of-stock {\n font-size: 10px;\n color: #f87171;\n font-weight: 500;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n ADD BUTTON\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-add-btn {\n padding: 6px 14px;\n border-radius: 8px;\n border: 1.5px solid rgba(109,86,245,0.6);\n font-size: 12px;\n font-weight: 600;\n cursor: pointer;\n background: transparent;\n color: #a78bfa;\n transition: all 0.15s;\n}\n.ttp-add-btn:hover { background: rgba(109,86,245,0.15); border-color: #a78bfa; }\n.ttp-add-btn:active { transform: scale(0.95); }\n.ttp-add-btn.ttp-added { background: rgba(109,86,245,0.6) !important; border-color: #7c3aed !important; color: #fff !important; }\n.ttp-add-btn:disabled { cursor: default; opacity: 0.5; }\n.ttp-add-btn.ttp-update-btn { background: rgba(245,158,11,0.15); border-color: rgba(245,158,11,0.5); color: #fbbf24; }\n.ttp-add-btn.ttp-update-btn:hover { background: rgba(245,158,11,0.25); border-color: #fbbf24; }\n\n.ttp-products-animating .ttp-add-btn {\n opacity: 0.4;\n pointer-events: none;\n cursor: not-allowed;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n CART TOAST\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n/* Toast replaces waveform in desktop voice section */\n.ttp-cart-toast {\n display: flex !important;\n align-items: center;\n gap: 10px;\n padding: 12px 16px;\n margin: 8px 12px;\n background: rgba(16,185,129,0.1);\n border-radius: 12px;\n border: 1px solid rgba(16,185,129,0.2);\n animation: ttpToastIn 0.25s ease;\n flex-shrink: 0;\n box-shadow: none;\n}\n\n@keyframes ttpToastIn {\n from { opacity: 0; transform: translateY(8px); }\n to { opacity: 1; transform: translateY(0); }\n}\n.ttp-cart-toast.ttp-toast-hiding {\n animation: ttpSlideDown 0.3s ease forwards;\n}\n\n@keyframes ttpSlideDown {\n to { opacity: 0; transform: translateY(-8px); height: 0; padding: 0; margin: 0; overflow: hidden; }\n}\n\n.ttp-toast-icon {\n width: 24px !important; height: 24px !important;\n border-radius: 50%;\n background: #10b981;\n color: #fff;\n display: flex !important;\n align-items: center;\n justify-content: center;\n font-size: 12px;\n font-weight: 700;\n flex-shrink: 0;\n}\n\n.ttp-toast-content { flex: 1; min-width: 0; }\n.ttp-toast-title { font-size: 12px; font-weight: 600; color: #34d399; }\n.ttp-toast-product {\n font-size: 11px;\n color: rgba(52,211,153,0.7);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ttp-toast-undo {\n background: none;\n border: 1px solid rgba(52,211,153,0.3);\n border-radius: 6px;\n padding: 3px 8px;\n font-size: 10px;\n color: #34d399;\n cursor: pointer;\n font-weight: 600;\n flex-shrink: 0;\n}\n.ttp-toast-undo:hover { background: rgba(52,211,153,0.1); }\n\n/* Fly-to-cart desktop target (when cart summary is hidden) */\n.ttp-desktop-fly-target {\n position: absolute;\n bottom: 12px;\n right: 80px;\n width: 24px;\n height: 24px;\n pointer-events: none;\n}\n\n/* Fly-to-cart ripple effect */\n.ttp-fly-ripple {\n position: absolute;\n left: 10px;\n top: 50%;\n width: 30px;\n height: 30px;\n margin-top: -15px;\n border-radius: 50%;\n border: 2px solid rgba(74,222,128,0.7);\n animation: ttp-ripple-expand 0.6s ease-out forwards;\n pointer-events: none;\n}\n\n@keyframes ttp-ripple-expand {\n 0% { transform: scale(0.5); opacity: 0.8; }\n 100% { transform: scale(3); opacity: 0; }\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n QUANTITY/WEIGHT STEPPER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.ttp-stepper {\n display: flex !important;\n align-items: center;\n gap: 2px;\n margin: 4px 0;\n}\n\n.ttp-stepper-btn {\n width: 24px !important;\n height: 24px !important;\n border-radius: 6px;\n border: 1px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.06);\n color: rgba(255,255,255,0.6);\n font-size: 14px;\n font-weight: 600;\n cursor: pointer;\n display: flex !important;\n align-items: center;\n justify-content: center;\n padding: 0;\n line-height: 1;\n transition: all 0.15s;\n flex-shrink: 0;\n}\n\n.ttp-stepper-btn:hover:not(:disabled) {\n background: rgba(255,255,255,0.12);\n border-color: rgba(255,255,255,0.25);\n}\n\n.ttp-stepper-btn:active:not(:disabled) {\n transform: scale(0.9);\n}\n\n.ttp-stepper-btn:disabled,\n.ttp-stepper-disabled {\n opacity: 0.35;\n cursor: default;\n}\n\n.ttp-stepper-value {\n font-size: 12px;\n font-weight: 600;\n color: #e8e4f0;\n min-width: 36px;\n text-align: center;\n user-select: none;\n}\n\n.ttp-product-compact .ttp-stepper {\n justify-content: flex-end;\n}\n\n.ttp-product-compact .ttp-product-action {\n display: flex !important;\n flex-direction: column;\n align-items: flex-end;\n gap: 2px;\n}\n\n.ttp-product-card .ttp-stepper {\n justify-content: center;\n margin: 4px 0;\n}\n\n.ttp-product-card .ttp-product-footer {\n display: flex !important;\n flex-direction: column;\n align-items: center;\n gap: 4px;\n}\n\n/* \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n VARIATION DESKTOP PICKER\n \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 */\n\n.picker-relative {\n position: relative !important;\n flex: 1 1 0 !important;\n min-height: 0 !important;\n display: flex !important;\n flex-direction: column !important;\n overflow: hidden;\n}\n\n/* When variant picker is shown, center it horizontally and vertically */\n.picker-relative.ttp-var-picker-active {\n justify-content: center !important;\n align-items: center !important;\n}\n\n.ttp-var-picker {\n background: rgba(255,255,255,0.04);\n border-radius: 14px;\n border: 1px solid rgba(255,255,255,0.08);\n display: flex !important;\n flex-direction: column;\n animation: ttpVarFadeIn 0.2s ease;\n overflow: hidden;\n width: 100%;\n flex-shrink: 0 !important;\n}\n\n@keyframes ttpVarFadeIn {\n from { opacity: 0; }\n to { opacity: 1; }\n}\n\n.ttp-var-header {\n display: flex !important;\n align-items: center;\n gap: 10px;\n padding: 10px 14px;\n border-bottom: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n}\n\n.ttp-var-back-btn {\n background: none;\n border: none;\n cursor: pointer;\n color: rgba(255,255,255,0.5);\n font-size: 16px;\n padding: 0;\n display: flex;\n align-items: center;\n line-height: 1;\n font-family: inherit;\n}\n.ttp-var-back-btn:hover { color: #e8e4f0; }\n\n.ttp-var-title {\n font-size: 13px;\n font-weight: 700;\n color: #e8e4f0;\n flex: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.ttp-var-page-link {\n font-size: 11px;\n color: #a78bfa;\n text-decoration: none;\n font-weight: 500;\n white-space: nowrap;\n flex-shrink: 0;\n}\n.ttp-var-page-link:hover { text-decoration: underline; }\n\n.ttp-var-body {\n flex: 1;\n overflow-y: auto;\n padding: 12px 14px;\n display: flex !important;\n flex-direction: column;\n gap: 14px;\n}\n\n.ttp-var-preview {\n display: flex !important;\n gap: 12px;\n align-items: flex-start;\n}\n\n.ttp-var-preview-img {\n width: 72px !important;\n height: 72px !important;\n border-radius: 12px;\n background: rgba(0,0,0,0.2);\n border: 1px solid rgba(255,255,255,0.08);\n display: flex !important;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n overflow: hidden;\n transition: all 0.2s ease;\n}\n\n.ttp-var-preview-img img {\n width: 100% !important;\n height: 100% !important;\n max-width: none !important;\n object-fit: contain !important;\n display: block !important;\n padding: 6px;\n}\n\n.ttp-var-preview-info { flex: 1; min-width: 0; }\n\n.ttp-var-preview-brand {\n font-size: 10px;\n color: rgba(255,255,255,0.4);\n font-weight: 500;\n text-transform: uppercase;\n letter-spacing: 0.3px;\n}\n\n.ttp-var-preview-name {\n font-size: 14px;\n font-weight: 700;\n color: #e8e4f0;\n margin: 2px 0 4px;\n line-height: 1.2;\n}\n\n.ttp-var-preview-price {\n font-size: 18px;\n font-weight: 700;\n color: #7c3aed;\n}\n\n.ttp-var-preview-selected {\n font-size: 11px;\n color: rgba(255,255,255,0.4);\n margin-top: 3px;\n}\n\n.ttp-var-section { display: flex !important; flex-direction: column; gap: 8px; }\n\n.ttp-var-section-label {\n font-size: 11px;\n font-weight: 700;\n color: rgba(255,255,255,0.5);\n text-transform: uppercase;\n letter-spacing: 0.4px;\n}\n\n.ttp-var-swatches { display: flex !important; flex-wrap: wrap; gap: 8px; }\n\n.ttp-var-swatch {\n display: block !important;\n width: 28px !important;\n height: 28px !important;\n border-radius: 50%;\n cursor: pointer;\n border: 3px solid transparent;\n transition: all 0.15s;\n position: relative;\n flex-shrink: 0;\n}\n.ttp-var-swatch:hover { transform: scale(1.1); }\n.ttp-var-swatch.selected {\n border-color: #7c3aed;\n box-shadow: 0 0 0 2px #fff, 0 0 0 4px #7c3aed;\n}\n.ttp-var-swatch.oos {\n opacity: 0.35;\n cursor: not-allowed;\n}\n\n.ttp-var-pills { display: flex !important; flex-wrap: wrap; gap: 6px; }\n\n.ttp-var-pill {\n padding: 5px 12px;\n border-radius: 8px;\n border: 1.5px solid rgba(255,255,255,0.15);\n background: rgba(255,255,255,0.04);\n font-size: 12px;\n font-weight: 600;\n color: rgba(255,255,255,0.6);\n cursor: pointer;\n transition: all 0.15s;\n font-family: inherit;\n}\n.ttp-var-pill:hover:not(:disabled) { border-color: #7c3aed; color: #a78bfa; }\n.ttp-var-pill.selected { border-color: #7c3aed; background: #7c3aed; color: #fff; }\n.ttp-var-pill.oos { opacity: 0.35; cursor: not-allowed; text-decoration: line-through; }\n\n.ttp-var-footer {\n padding: 10px 14px 12px;\n border-top: 1px solid rgba(255,255,255,0.06);\n flex-shrink: 0;\n}\n\n.ttp-var-add-btn {\n width: 100%;\n padding: 10px;\n background: linear-gradient(135deg, #7c3aed, #6d28d9);\n color: #fff;\n border: none;\n border-radius: 10px;\n font-size: 13px;\n font-weight: 600;\n cursor: pointer;\n font-family: inherit;\n box-shadow: 0 3px 10px rgba(124,58,237,0.3);\n transition: all 0.15s;\n}\n.ttp-var-add-btn:hover:not(:disabled) { transform: scale(0.99); }\n.ttp-var-add-btn:disabled {\n background: rgba(255,255,255,0.1);\n box-shadow: none;\n cursor: not-allowed;\n color: rgba(255,255,255,0.3);\n}\n\n.ttp-var-spinner {\n width: 24px;\n height: 24px;\n border: 3px solid rgba(255,255,255,0.1);\n border-top-color: #7c3aed;\n border-radius: 50%;\n animation: ttpVarSpin 0.7s linear infinite;\n}\n@keyframes ttpVarSpin {\n to { transform: rotate(360deg); }\n}\n\n/* Amber \"Choose\" button for variant products */\n.ttp-add-btn.ttp-choose-btn {\n background: linear-gradient(135deg, #f59e0b, #d97706);\n box-shadow: 0 2px 8px rgba(245,158,11,0.3);\n color: #fff;\n}\n\n ";
|
|
17389
|
+
}
|
|
17390
|
+
|
|
17391
|
+
/***/ }),
|
|
17392
|
+
|
|
17393
|
+
/***/ "./src/ecommerce/partnerLogo.js":
|
|
17394
|
+
/*!**************************************!*\
|
|
17395
|
+
!*** ./src/ecommerce/partnerLogo.js ***!
|
|
17396
|
+
\**************************************/
|
|
17397
|
+
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
|
|
17398
|
+
|
|
17399
|
+
"use strict";
|
|
17400
|
+
__webpack_require__.r(__webpack_exports__);
|
|
17401
|
+
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
|
|
17402
|
+
/* harmony export */ resolvePartnerId: () => (/* binding */ resolvePartnerId),
|
|
17403
|
+
/* harmony export */ resolvePartnerLogoUrl: () => (/* binding */ resolvePartnerLogoUrl),
|
|
17404
|
+
/* harmony export */ resolveSdkBaseUrl: () => (/* binding */ resolveSdkBaseUrl)
|
|
17405
|
+
/* harmony export */ });
|
|
17406
|
+
function _regenerator() { /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/babel/babel/blob/main/packages/babel-helpers/LICENSE */ var e, t, r = "function" == typeof Symbol ? Symbol : {}, n = r.iterator || "@@iterator", o = r.toStringTag || "@@toStringTag"; function i(r, n, o, i) { var c = n && n.prototype instanceof Generator ? n : Generator, u = Object.create(c.prototype); return _regeneratorDefine2(u, "_invoke", function (r, n, o) { var i, c, u, f = 0, p = o || [], y = !1, G = { p: 0, n: 0, v: e, a: d, f: d.bind(e, 4), d: function d(t, r) { return i = t, c = 0, u = e, G.n = r, a; } }; function d(r, n) { for (c = r, u = n, t = 0; !y && f && !o && t < p.length; t++) { var o, i = p[t], d = G.p, l = i[2]; r > 3 ? (o = l === n) && (u = i[(c = i[4]) ? 5 : (c = 3, 3)], i[4] = i[5] = e) : i[0] <= d && ((o = r < 2 && d < i[1]) ? (c = 0, G.v = n, G.n = i[1]) : d < l && (o = r < 3 || i[0] > n || n > l) && (i[4] = r, i[5] = n, G.n = l, c = 0)); } if (o || r > 1) return a; throw y = !0, n; } return function (o, p, l) { if (f > 1) throw TypeError("Generator is already running"); for (y && 1 === p && d(p, l), c = p, u = l; (t = c < 2 ? e : u) || !y;) { i || (c ? c < 3 ? (c > 1 && (G.n = -1), d(c, u)) : G.n = u : G.v = u); try { if (f = 2, i) { if (c || (o = "next"), t = i[o]) { if (!(t = t.call(i, u))) throw TypeError("iterator result is not an object"); if (!t.done) return t; u = t.value, c < 2 && (c = 0); } else 1 === c && (t = i.return) && t.call(i), c < 2 && (u = TypeError("The iterator does not provide a '" + o + "' method"), c = 1); i = e; } else if ((t = (y = G.n < 0) ? u : r.call(n, G)) !== a) break; } catch (t) { i = e, c = 1, u = t; } finally { f = 1; } } return { value: t, done: y }; }; }(r, o, i), !0), u; } var a = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} t = Object.getPrototypeOf; var c = [][n] ? t(t([][n]())) : (_regeneratorDefine2(t = {}, n, function () { return this; }), t), u = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(c); function f(e) { return Object.setPrototypeOf ? Object.setPrototypeOf(e, GeneratorFunctionPrototype) : (e.__proto__ = GeneratorFunctionPrototype, _regeneratorDefine2(e, o, "GeneratorFunction")), e.prototype = Object.create(u), e; } return GeneratorFunction.prototype = GeneratorFunctionPrototype, _regeneratorDefine2(u, "constructor", GeneratorFunctionPrototype), _regeneratorDefine2(GeneratorFunctionPrototype, "constructor", GeneratorFunction), GeneratorFunction.displayName = "GeneratorFunction", _regeneratorDefine2(GeneratorFunctionPrototype, o, "GeneratorFunction"), _regeneratorDefine2(u), _regeneratorDefine2(u, o, "Generator"), _regeneratorDefine2(u, n, function () { return this; }), _regeneratorDefine2(u, "toString", function () { return "[object Generator]"; }), (_regenerator = function _regenerator() { return { w: i, m: f }; })(); }
|
|
17407
|
+
function _regeneratorDefine2(e, r, n, t) { var i = Object.defineProperty; try { i({}, "", {}); } catch (e) { i = 0; } _regeneratorDefine2 = function _regeneratorDefine(e, r, n, t) { function o(r, n) { _regeneratorDefine2(e, r, function (e) { return this._invoke(r, n, e); }); } r ? i ? i(e, r, { value: n, enumerable: !t, configurable: !t, writable: !t }) : e[r] = n : (o("next", 0), o("throw", 1), o("return", 2)); }, _regeneratorDefine2(e, r, n, t); }
|
|
17408
|
+
function asyncGeneratorStep(n, t, e, r, o, a, c) { try { var i = n[a](c), u = i.value; } catch (n) { return void e(n); } i.done ? t(u) : Promise.resolve(u).then(r, o); }
|
|
17409
|
+
function _asyncToGenerator(n) { return function () { var t = this, e = arguments; return new Promise(function (r, o) { var a = n.apply(t, e); function _next(n) { asyncGeneratorStep(a, r, o, _next, _throw, "next", n); } function _throw(n) { asyncGeneratorStep(a, r, o, _next, _throw, "throw", n); } _next(void 0); }); }; }
|
|
17410
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
17411
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
17412
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
17413
|
+
/**
|
|
17414
|
+
* Partner logos on the SDK CDN:
|
|
17415
|
+
* {sdkBaseUrl}/partners/{partnerId}.svg (preferred — you provide)
|
|
17416
|
+
* {sdkBaseUrl}/partners/{partnerId}.png (optional fallback)
|
|
17417
|
+
*
|
|
17418
|
+
* Missing partnerId or missing file → no logo rendered.
|
|
17419
|
+
*/
|
|
17420
|
+
|
|
17421
|
+
var LOGO_EXTENSIONS = ['svg', 'png'];
|
|
17422
|
+
function resolveSdkBaseUrl() {
|
|
17423
|
+
if (typeof document !== 'undefined') {
|
|
17424
|
+
var scripts = document.querySelectorAll('script[src]');
|
|
17425
|
+
var _iterator = _createForOfIteratorHelper(scripts),
|
|
17426
|
+
_step;
|
|
17427
|
+
try {
|
|
17428
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
17429
|
+
var script = _step.value;
|
|
17430
|
+
var src = script.getAttribute('src') || '';
|
|
17431
|
+
if (!src.includes('agent-widget') && !src.includes('ttp-agent-sdk')) continue;
|
|
17432
|
+
try {
|
|
17433
|
+
var url = new URL(src, window.location.href);
|
|
17434
|
+
return url.origin + url.pathname.replace(/\/[^/]*$/, '');
|
|
17435
|
+
} catch (e) {/* continue */}
|
|
17436
|
+
}
|
|
17437
|
+
} catch (err) {
|
|
17438
|
+
_iterator.e(err);
|
|
17439
|
+
} finally {
|
|
17440
|
+
_iterator.f();
|
|
17441
|
+
}
|
|
17442
|
+
}
|
|
17443
|
+
if (typeof window !== 'undefined') {
|
|
17444
|
+
var host = window.location.hostname || '';
|
|
17445
|
+
if (host.includes('cdn.talktopc.com') || host.includes('talktopc.com')) {
|
|
17446
|
+
return "".concat(window.location.origin, "/ttp-agent-sdk");
|
|
17447
|
+
}
|
|
17448
|
+
}
|
|
17449
|
+
return 'https://cdn.talktopc.com/ttp-agent-sdk';
|
|
17450
|
+
}
|
|
17451
|
+
|
|
17452
|
+
/** partnerId from wire message, else widget flavor.partnerId. */
|
|
17453
|
+
function resolvePartnerId(widget, message) {
|
|
17454
|
+
var _ref, _ref2, _message$partnerId, _message$recipe, _message$recipe2, _widget$config$flavor, _widget$config;
|
|
17455
|
+
var fromMsg = (_ref = (_ref2 = (_message$partnerId = message === null || message === void 0 ? void 0 : message.partnerId) !== null && _message$partnerId !== void 0 ? _message$partnerId : message === null || message === void 0 ? void 0 : message.partner_id) !== null && _ref2 !== void 0 ? _ref2 : message === null || message === void 0 || (_message$recipe = message.recipe) === null || _message$recipe === void 0 ? void 0 : _message$recipe.partnerId) !== null && _ref !== void 0 ? _ref : message === null || message === void 0 || (_message$recipe2 = message.recipe) === null || _message$recipe2 === void 0 ? void 0 : _message$recipe2.partner_id;
|
|
17456
|
+
if (fromMsg && String(fromMsg).trim()) {
|
|
17457
|
+
return String(fromMsg).trim();
|
|
17458
|
+
}
|
|
17459
|
+
var flavor = (_widget$config$flavor = widget === null || widget === void 0 || (_widget$config = widget.config) === null || _widget$config === void 0 ? void 0 : _widget$config.flavor) !== null && _widget$config$flavor !== void 0 ? _widget$config$flavor : widget === null || widget === void 0 ? void 0 : widget._flavorObj;
|
|
17460
|
+
var fromFlavor = flavor === null || flavor === void 0 ? void 0 : flavor.partnerId;
|
|
17461
|
+
if (fromFlavor && String(fromFlavor).trim()) {
|
|
17462
|
+
return String(fromFlavor).trim();
|
|
17463
|
+
}
|
|
17464
|
+
return null;
|
|
17465
|
+
}
|
|
17466
|
+
function probeImage(url) {
|
|
17467
|
+
return new Promise(function (resolve) {
|
|
17468
|
+
var img = new Image();
|
|
17469
|
+
img.onload = function () {
|
|
17470
|
+
return resolve(true);
|
|
17471
|
+
};
|
|
17472
|
+
img.onerror = function () {
|
|
17473
|
+
return resolve(false);
|
|
17474
|
+
};
|
|
17475
|
+
img.src = url;
|
|
17476
|
+
});
|
|
17477
|
+
}
|
|
17478
|
+
|
|
17479
|
+
/** @returns {Promise<string|null>} First logo URL that loads, or null. */
|
|
17480
|
+
function resolvePartnerLogoUrl(_x, _x2) {
|
|
17481
|
+
return _resolvePartnerLogoUrl.apply(this, arguments);
|
|
17482
|
+
}
|
|
17483
|
+
function _resolvePartnerLogoUrl() {
|
|
17484
|
+
_resolvePartnerLogoUrl = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee(partnerId, sdkBaseUrl) {
|
|
17485
|
+
var id, base, safeId, _iterator2, _step2, ext, url, _t;
|
|
17486
|
+
return _regenerator().w(function (_context) {
|
|
17487
|
+
while (1) switch (_context.p = _context.n) {
|
|
17488
|
+
case 0:
|
|
17489
|
+
id = partnerId === null || partnerId === void 0 ? void 0 : partnerId.trim();
|
|
17490
|
+
if (id) {
|
|
17491
|
+
_context.n = 1;
|
|
17492
|
+
break;
|
|
17493
|
+
}
|
|
17494
|
+
return _context.a(2, null);
|
|
17495
|
+
case 1:
|
|
17496
|
+
base = (sdkBaseUrl || resolveSdkBaseUrl()).replace(/\/$/, '');
|
|
17497
|
+
safeId = encodeURIComponent(id);
|
|
17498
|
+
_iterator2 = _createForOfIteratorHelper(LOGO_EXTENSIONS);
|
|
17499
|
+
_context.p = 2;
|
|
17500
|
+
_iterator2.s();
|
|
17501
|
+
case 3:
|
|
17502
|
+
if ((_step2 = _iterator2.n()).done) {
|
|
17503
|
+
_context.n = 6;
|
|
17504
|
+
break;
|
|
17505
|
+
}
|
|
17506
|
+
ext = _step2.value;
|
|
17507
|
+
url = "".concat(base, "/partners/").concat(safeId, ".").concat(ext); // eslint-disable-next-line no-await-in-loop
|
|
17508
|
+
_context.n = 4;
|
|
17509
|
+
return probeImage(url);
|
|
17510
|
+
case 4:
|
|
17511
|
+
if (!_context.v) {
|
|
17512
|
+
_context.n = 5;
|
|
17513
|
+
break;
|
|
17514
|
+
}
|
|
17515
|
+
return _context.a(2, url);
|
|
17516
|
+
case 5:
|
|
17517
|
+
_context.n = 3;
|
|
17518
|
+
break;
|
|
17519
|
+
case 6:
|
|
17520
|
+
_context.n = 8;
|
|
17521
|
+
break;
|
|
17522
|
+
case 7:
|
|
17523
|
+
_context.p = 7;
|
|
17524
|
+
_t = _context.v;
|
|
17525
|
+
_iterator2.e(_t);
|
|
17526
|
+
case 8:
|
|
17527
|
+
_context.p = 8;
|
|
17528
|
+
_iterator2.f();
|
|
17529
|
+
return _context.f(8);
|
|
17530
|
+
case 9:
|
|
17531
|
+
return _context.a(2, null);
|
|
17532
|
+
}
|
|
17533
|
+
}, _callee, null, [[2, 7, 8, 9]]);
|
|
17534
|
+
}));
|
|
17535
|
+
return _resolvePartnerLogoUrl.apply(this, arguments);
|
|
16659
17536
|
}
|
|
16660
17537
|
|
|
16661
17538
|
/***/ }),
|
|
@@ -16929,6 +17806,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
16929
17806
|
/* harmony export */ MESSAGE_TYPES: () => (/* binding */ MESSAGE_TYPES)
|
|
16930
17807
|
/* harmony export */ });
|
|
16931
17808
|
/* harmony import */ var _widget_galleryHandler_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../widget/galleryHandler.js */ "./src/widget/galleryHandler.js");
|
|
17809
|
+
/* harmony import */ var _ecommerce_RecipeHandler_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../ecommerce/RecipeHandler.js */ "./src/ecommerce/RecipeHandler.js");
|
|
16932
17810
|
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
|
16933
17811
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
16934
17812
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -16972,6 +17850,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
|
|
16972
17850
|
*/
|
|
16973
17851
|
|
|
16974
17852
|
|
|
17853
|
+
|
|
16975
17854
|
/**
|
|
16976
17855
|
* The universal message types that form the contract between widget and backend.
|
|
16977
17856
|
* Flavors receive these incoming types and send these outgoing types.
|
|
@@ -16983,6 +17862,8 @@ var MESSAGE_TYPES = Object.freeze({
|
|
|
16983
17862
|
CART_UPDATED: 'cart_updated',
|
|
16984
17863
|
SHOW_MEDIA: 'show_media',
|
|
16985
17864
|
DISMISS_MEDIA: 'dismiss_media',
|
|
17865
|
+
SHOW_RECIPE: 'show_recipe',
|
|
17866
|
+
DISMISS_RECIPE: 'dismiss_recipe',
|
|
16986
17867
|
// Outgoing (widget → backend)
|
|
16987
17868
|
PRODUCT_SELECTED: 'product_selected',
|
|
16988
17869
|
PRODUCT_DESELECTED: 'product_deselected'
|
|
@@ -17068,6 +17949,14 @@ var BaseFlavor = /*#__PURE__*/function () {
|
|
|
17068
17949
|
value: function buildTools() {
|
|
17069
17950
|
return [];
|
|
17070
17951
|
}
|
|
17952
|
+
}, {
|
|
17953
|
+
key: "_getRecipeHandler",
|
|
17954
|
+
value: function _getRecipeHandler() {
|
|
17955
|
+
if (!this._recipeHandler) {
|
|
17956
|
+
this._recipeHandler = (0,_ecommerce_RecipeHandler_js__WEBPACK_IMPORTED_MODULE_1__.createRecipeHandler)(this.widget);
|
|
17957
|
+
}
|
|
17958
|
+
return this._recipeHandler;
|
|
17959
|
+
}
|
|
17071
17960
|
|
|
17072
17961
|
// ─── Shared helpers (available to subclasses) ─────────────────
|
|
17073
17962
|
|
|
@@ -17178,13 +18067,19 @@ var BaseFlavor = /*#__PURE__*/function () {
|
|
|
17178
18067
|
};
|
|
17179
18068
|
|
|
17180
18069
|
// Universal handlers — these are the contract
|
|
17181
|
-
var universal = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, MESSAGE_TYPES.SHOW_ITEMS, routeShowItems), "show_products", routeShowItems), MESSAGE_TYPES.CART_UPDATED, function (msg) {
|
|
18070
|
+
var universal = _defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty(_defineProperty({}, MESSAGE_TYPES.SHOW_ITEMS, routeShowItems), "show_products", routeShowItems), MESSAGE_TYPES.CART_UPDATED, function (msg) {
|
|
17182
18071
|
_this.manager.handleCartUpdated(msg);
|
|
17183
18072
|
}), MESSAGE_TYPES.SHOW_MEDIA, function (msg) {
|
|
17184
18073
|
_this.hideManagerUI();
|
|
17185
18074
|
_this.galleryHandler.handleShowMedia(msg);
|
|
17186
18075
|
}), MESSAGE_TYPES.DISMISS_MEDIA, function () {
|
|
17187
18076
|
_this.galleryHandler.dismissGallery();
|
|
18077
|
+
}), MESSAGE_TYPES.SHOW_RECIPE, function (msg) {
|
|
18078
|
+
_this._getRecipeHandler().handleShowRecipe(msg);
|
|
18079
|
+
}), MESSAGE_TYPES.DISMISS_RECIPE, function (msg) {
|
|
18080
|
+
_this._getRecipeHandler().dismissRecipe({
|
|
18081
|
+
animate: (msg === null || msg === void 0 ? void 0 : msg.silent) !== true && (msg === null || msg === void 0 ? void 0 : msg.animate) !== false
|
|
18082
|
+
});
|
|
17188
18083
|
});
|
|
17189
18084
|
|
|
17190
18085
|
// Extra handlers from subclass
|
|
@@ -17884,12 +18779,19 @@ var EcommerceFlavor = /*#__PURE__*/function (_BaseFlavor) {
|
|
|
17884
18779
|
runAdapter: function runAdapter(action, args) {
|
|
17885
18780
|
var _self$_partnerScriptR2;
|
|
17886
18781
|
return (_self$_partnerScriptR2 = self._partnerScriptRunner) === null || _self$_partnerScriptR2 === void 0 ? void 0 : _self$_partnerScriptR2.runAdapter(action, args);
|
|
18782
|
+
},
|
|
18783
|
+
showRecipe: function showRecipe(recipe) {
|
|
18784
|
+
return self._getRecipeHandler().handleShowRecipe({
|
|
18785
|
+
recipe: recipe
|
|
18786
|
+
});
|
|
17887
18787
|
}
|
|
17888
18788
|
};
|
|
17889
18789
|
}
|
|
17890
18790
|
}, {
|
|
17891
18791
|
key: "destroy",
|
|
17892
18792
|
value: function destroy() {
|
|
18793
|
+
var _this$_recipeHandler;
|
|
18794
|
+
(_this$_recipeHandler = this._recipeHandler) === null || _this$_recipeHandler === void 0 || _this$_recipeHandler.dismissRecipe();
|
|
17893
18795
|
delete window.__TTP_ECOMMERCE__;
|
|
17894
18796
|
_superPropGet(EcommerceFlavor, "destroy", this, 3)([]);
|
|
17895
18797
|
}
|
|
@@ -20303,8 +21205,8 @@ var VoiceSDK = _v2_VoiceSDK_js__WEBPACK_IMPORTED_MODULE_0__["default"];
|
|
|
20303
21205
|
|
|
20304
21206
|
|
|
20305
21207
|
// Version - injected at build time from package.json via webpack DefinePlugin
|
|
20306
|
-
var VERSION = "2.
|
|
20307
|
-
var BUILD_TIME = "2026-
|
|
21208
|
+
var VERSION = "2.46.1";
|
|
21209
|
+
var BUILD_TIME = "2026-07-13T08:30:44.984Z";
|
|
20308
21210
|
console.log("%c TTP Agent SDK v".concat(VERSION, " (").concat(BUILD_TIME, ") "), 'background: #4f46e5; color: white; font-size: 12px; font-weight: bold; padding: 2px 6px; border-radius: 4px;');
|
|
20309
21211
|
|
|
20310
21212
|
// Named exports
|
|
@@ -25063,6 +25965,14 @@ var AudioPlayer = /*#__PURE__*/function (_EventEmitter) {
|
|
|
25063
25965
|
});
|
|
25064
25966
|
_this4.currentSegmentId = _this4.pendingSegmentId;
|
|
25065
25967
|
console.log("\uD83D\uDCDD AudioPlayer: Sentence scheduled at ".concat(_this4.nextStartTime.toFixed(3), "s (segmentId: ").concat(_this4.pendingSegmentId, "): \"").concat((_this4.pendingSentenceText || '').substring(0, 40), "...\" (synced: ").concat(_this4.pendingSynced ? _this4.pendingSynced.length : 0, ")"));
|
|
25968
|
+
// Per-segment START signal: this segment's first frame just scheduled (≈ playback start).
|
|
25969
|
+
// Mirrors the per-segment 'segmentDone' (end) event; lets the backend fire speech-synced
|
|
25970
|
+
// actions exactly when THIS line begins playing (vs the coarse, once-per-burst playbackStarted).
|
|
25971
|
+
if (_this4.currentSegmentId != null) {
|
|
25972
|
+
_this4.emit('segmentStarted', {
|
|
25973
|
+
segmentId: _this4.currentSegmentId
|
|
25974
|
+
});
|
|
25975
|
+
}
|
|
25066
25976
|
_this4.pendingSentenceText = null;
|
|
25067
25977
|
_this4.pendingSynced = null;
|
|
25068
25978
|
_this4.pendingSegmentId = null;
|
|
@@ -27002,6 +27912,10 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27002
27912
|
websocketUrl: config.websocketUrl || 'wss://speech.talktopc.com/ws/conv',
|
|
27003
27913
|
agentId: config.agentId,
|
|
27004
27914
|
appId: config.appId,
|
|
27915
|
+
// Supervision monitor mode: listen-only to an existing call (no mic).
|
|
27916
|
+
// mode:'monitor' + a short-lived ticket authorize /ws/supervision.
|
|
27917
|
+
mode: config.mode || 'agent',
|
|
27918
|
+
ticket: config.ticket || null,
|
|
27005
27919
|
// Input format (what we send to server)
|
|
27006
27920
|
|
|
27007
27921
|
sampleRate: config.sampleRate || 16000,
|
|
@@ -27566,6 +28480,20 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27566
28480
|
});
|
|
27567
28481
|
}
|
|
27568
28482
|
});
|
|
28483
|
+
|
|
28484
|
+
// Per-segment START — fired when a sentence's first frame schedules (≈ it begins playing).
|
|
28485
|
+
// The backend uses this to fire sync_with_speech tool execution exactly as the line is heard.
|
|
28486
|
+
|
|
28487
|
+
this.audioPlayer.on('segmentStarted', function (info) {
|
|
28488
|
+
if (!info || info.segmentId == null) return;
|
|
28489
|
+
if (_this3.isConnected) {
|
|
28490
|
+
console.log('📤 VoiceSDK v2: Sending audio_segment_started (segmentId: ' + info.segmentId + ')');
|
|
28491
|
+
_this3.sendMessage({
|
|
28492
|
+
t: 'audio_segment_started',
|
|
28493
|
+
segmentId: info.segmentId
|
|
28494
|
+
});
|
|
28495
|
+
}
|
|
28496
|
+
});
|
|
27569
28497
|
this.audioPlayer.on('playbackError', function (error) {
|
|
27570
28498
|
_this3.emit('playbackError', error);
|
|
27571
28499
|
_this3.emit('error', error);
|
|
@@ -27629,12 +28557,28 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27629
28557
|
/**
|
|
27630
28558
|
* Build WebSocket URL with query parameters
|
|
27631
28559
|
*/
|
|
28560
|
+
/** True when this SDK instance is a listen-only supervision monitor (no mic). */
|
|
28561
|
+
}, {
|
|
28562
|
+
key: "isMonitor",
|
|
28563
|
+
value: function isMonitor() {
|
|
28564
|
+
return this.config.mode === 'monitor';
|
|
28565
|
+
}
|
|
27632
28566
|
}, {
|
|
27633
28567
|
key: "buildWebSocketUrl",
|
|
27634
28568
|
value: function buildWebSocketUrl() {
|
|
27635
28569
|
var baseUrl = this.config.websocketUrl;
|
|
27636
28570
|
var url = new URL(baseUrl, 'wss://placeholder.com');
|
|
27637
28571
|
var params = url.searchParams;
|
|
28572
|
+
|
|
28573
|
+
// Supervision monitor: authenticate by the single-use ticket only — no agentId/appId,
|
|
28574
|
+
// and never resume/attach a conversation of our own.
|
|
28575
|
+
if (this.isMonitor()) {
|
|
28576
|
+
if (this.config.ticket && !params.has('ticket')) {
|
|
28577
|
+
params.append('ticket', this.config.ticket);
|
|
28578
|
+
}
|
|
28579
|
+
var queryStringM = params.toString();
|
|
28580
|
+
return queryStringM ? "".concat(url.origin).concat(url.pathname, "?").concat(queryStringM) : "".concat(url.origin).concat(url.pathname);
|
|
28581
|
+
}
|
|
27638
28582
|
if (this.config.agentId && !params.has('agentId')) {
|
|
27639
28583
|
params.append('agentId', this.config.agentId);
|
|
27640
28584
|
}
|
|
@@ -27716,9 +28660,12 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27716
28660
|
});
|
|
27717
28661
|
}
|
|
27718
28662
|
|
|
27719
|
-
// Send hello message
|
|
27720
|
-
|
|
27721
|
-
|
|
28663
|
+
// Send hello message.
|
|
28664
|
+
// Supervision monitor: the server sends hello_ack unprompted (it only needs to
|
|
28665
|
+
// advertise outputAudioFormat), so we skip the agent hello entirely.
|
|
28666
|
+
if (!_this5.isMonitor()) {
|
|
28667
|
+
_this5.sendHelloMessage();
|
|
28668
|
+
}
|
|
27722
28669
|
_this5.emit('connected');
|
|
27723
28670
|
resolve(true);
|
|
27724
28671
|
};
|
|
@@ -27930,7 +28877,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27930
28877
|
|
|
27931
28878
|
// Include SDK build time for debugging
|
|
27932
28879
|
if (true) {
|
|
27933
|
-
helloMessage.lastBuildTime = "2026-
|
|
28880
|
+
helloMessage.lastBuildTime = "2026-07-13T08:30:44.984Z";
|
|
27934
28881
|
}
|
|
27935
28882
|
|
|
27936
28883
|
// Page context is intentionally NOT attached to the hello message.
|
|
@@ -28232,6 +29179,8 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28232
29179
|
break;
|
|
28233
29180
|
case 'show_items':
|
|
28234
29181
|
case 'show_products':
|
|
29182
|
+
case 'show_recipe':
|
|
29183
|
+
case 'dismiss_recipe':
|
|
28235
29184
|
case 'cart_updated':
|
|
28236
29185
|
case 'add_to_store_cart':
|
|
28237
29186
|
case 'add_to_site_cart':
|
|
@@ -28497,6 +29446,11 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28497
29446
|
// VoiceInterface waits for this flag before starting recording,
|
|
28498
29447
|
// so config.sampleRate must be finalized first.
|
|
28499
29448
|
this.helloAckReceived = true;
|
|
29449
|
+
|
|
29450
|
+
// Silently re-apply the user's persisted in-call settings (voice speed /
|
|
29451
|
+
// response length) now that the session is ready — the backend applies
|
|
29452
|
+
// them without a spoken acknowledgement (announce:false).
|
|
29453
|
+
this._syncCallSettingsAfterHello();
|
|
28500
29454
|
if (message.outputAudioFormat) {
|
|
28501
29455
|
// v2 protocol: format was negotiated
|
|
28502
29456
|
|
|
@@ -29310,6 +30264,79 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29310
30264
|
}
|
|
29311
30265
|
}
|
|
29312
30266
|
|
|
30267
|
+
/**
|
|
30268
|
+
* In-call user settings (voice speed / response length).
|
|
30269
|
+
*
|
|
30270
|
+
* Sends {t:"call_settings"} to the backend: `voiceSpeedFactor` multiplies the
|
|
30271
|
+
* agent's configured TTS speed (1.0 = agent default, clamped server-side to
|
|
30272
|
+
* 0.5–2.0) and applies from the next synthesized line; `responseLength`
|
|
30273
|
+
* ("detailed"|"normal"|"brief"|"very_brief") is folded into the system prompt
|
|
30274
|
+
* from the next LLM turn. `opts.announce` (default true) lets the agent speak
|
|
30275
|
+
* a short fixed confirmation when idle.
|
|
30276
|
+
*
|
|
30277
|
+
* Called before hello_ack, the values are kept and flushed silently by
|
|
30278
|
+
* _syncCallSettingsAfterHello() once the session is ready.
|
|
30279
|
+
*
|
|
30280
|
+
* @param {{voiceSpeedFactor?: number, responseLength?: string}} settings
|
|
30281
|
+
* @param {{announce?: boolean}} [opts]
|
|
30282
|
+
* @returns {boolean} true if the message was sent now
|
|
30283
|
+
*/
|
|
30284
|
+
}, {
|
|
30285
|
+
key: "setCallSettings",
|
|
30286
|
+
value: function setCallSettings() {
|
|
30287
|
+
var settings = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
30288
|
+
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
30289
|
+
this._callSettings = _objectSpread(_objectSpread({}, this._callSettings || {}), settings);
|
|
30290
|
+
if (!this.helloAckReceived || !this.websocket || this.websocket.readyState !== WebSocket.OPEN) {
|
|
30291
|
+
return false; // flushed after hello_ack
|
|
30292
|
+
}
|
|
30293
|
+
var msg = {
|
|
30294
|
+
t: 'call_settings',
|
|
30295
|
+
announce: opts.announce !== false
|
|
30296
|
+
};
|
|
30297
|
+
if (typeof this._callSettings.voiceSpeedFactor === 'number') {
|
|
30298
|
+
msg.voiceSpeedFactor = this._callSettings.voiceSpeedFactor;
|
|
30299
|
+
}
|
|
30300
|
+
if (this._callSettings.responseLength) {
|
|
30301
|
+
msg.responseLength = this._callSettings.responseLength;
|
|
30302
|
+
}
|
|
30303
|
+
return this.sendMessage(msg);
|
|
30304
|
+
}
|
|
30305
|
+
|
|
30306
|
+
/**
|
|
30307
|
+
* Flush persisted call settings right after hello_ack (silent — no spoken ack).
|
|
30308
|
+
* Values come from an earlier setCallSettings() call or, when none, from
|
|
30309
|
+
* config.callSettingsProvider (the widget wires this to its localStorage).
|
|
30310
|
+
* Defaults (factor 1.0 + "normal") are skipped — nothing to sync.
|
|
30311
|
+
*/
|
|
30312
|
+
}, {
|
|
30313
|
+
key: "_syncCallSettingsAfterHello",
|
|
30314
|
+
value: function _syncCallSettingsAfterHello() {
|
|
30315
|
+
try {
|
|
30316
|
+
var s = this._callSettings;
|
|
30317
|
+
if (!s && typeof this.config.callSettingsProvider === 'function') {
|
|
30318
|
+
s = this.config.callSettingsProvider();
|
|
30319
|
+
}
|
|
30320
|
+
if (!s) return;
|
|
30321
|
+
this._callSettings = _objectSpread({}, s);
|
|
30322
|
+
var factor = typeof s.voiceSpeedFactor === 'number' ? s.voiceSpeedFactor : 1.0;
|
|
30323
|
+
var length = s.responseLength || 'normal';
|
|
30324
|
+
if (Math.abs(factor - 1.0) < 0.001 && length === 'normal') return;
|
|
30325
|
+
this.sendMessage({
|
|
30326
|
+
t: 'call_settings',
|
|
30327
|
+
voiceSpeedFactor: factor,
|
|
30328
|
+
responseLength: length,
|
|
30329
|
+
announce: false
|
|
30330
|
+
});
|
|
30331
|
+
console.log('⚙️ VoiceSDK v2: Synced persisted call settings:', {
|
|
30332
|
+
voiceSpeedFactor: factor,
|
|
30333
|
+
responseLength: length
|
|
30334
|
+
});
|
|
30335
|
+
} catch (e) {
|
|
30336
|
+
console.warn('⚙️ VoiceSDK v2: Failed to sync call settings (ignored):', e);
|
|
30337
|
+
}
|
|
30338
|
+
}
|
|
30339
|
+
|
|
29313
30340
|
/**
|
|
29314
30341
|
* Pause the call. Stops sending/receiving audio.
|
|
29315
30342
|
*/
|
|
@@ -29433,64 +30460,72 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29433
30460
|
while (1) switch (_context8.p = _context8.n) {
|
|
29434
30461
|
case 0:
|
|
29435
30462
|
existingMediaStream = _args8.length > 0 && _args8[0] !== undefined ? _args8[0] : null;
|
|
29436
|
-
if (this.
|
|
30463
|
+
if (!this.isMonitor()) {
|
|
29437
30464
|
_context8.n = 1;
|
|
29438
30465
|
break;
|
|
29439
30466
|
}
|
|
30467
|
+
// Listen-only supervision: never open the mic / never uplink audio.
|
|
30468
|
+
console.warn('VoiceSDK v2: startRecording ignored in monitor (listen-only) mode');
|
|
30469
|
+
return _context8.a(2, false);
|
|
30470
|
+
case 1:
|
|
30471
|
+
if (this.isConnected) {
|
|
30472
|
+
_context8.n = 2;
|
|
30473
|
+
break;
|
|
30474
|
+
}
|
|
29440
30475
|
error = new Error('Not connected to voice server');
|
|
29441
30476
|
this.emit('error', error);
|
|
29442
30477
|
throw error;
|
|
29443
|
-
case
|
|
30478
|
+
case 2:
|
|
29444
30479
|
if (!this.isRecording) {
|
|
29445
|
-
_context8.n =
|
|
30480
|
+
_context8.n = 3;
|
|
29446
30481
|
break;
|
|
29447
30482
|
}
|
|
29448
30483
|
console.warn('VoiceSDK v2: Already recording');
|
|
29449
30484
|
return _context8.a(2, true);
|
|
29450
|
-
case
|
|
30485
|
+
case 3:
|
|
29451
30486
|
if (!this.disclaimersPending) {
|
|
29452
|
-
_context8.n =
|
|
30487
|
+
_context8.n = 4;
|
|
29453
30488
|
break;
|
|
29454
30489
|
}
|
|
29455
30490
|
_error4 = new Error('Server disclaimers must be accepted before recording. Call sendDisclaimerAck(true) first.');
|
|
29456
30491
|
_error4.code = 'DISCLAIMER_PENDING';
|
|
29457
30492
|
this.emit('error', _error4);
|
|
29458
30493
|
throw _error4;
|
|
29459
|
-
case
|
|
30494
|
+
case 4:
|
|
29460
30495
|
console.log('🎤 VoiceSDK v2: Starting recording...');
|
|
29461
|
-
_context8.p =
|
|
30496
|
+
_context8.p = 5;
|
|
29462
30497
|
// CRITICAL for mobile browsers: Request microphone permission FIRST
|
|
29463
30498
|
// iOS: Pass existingMediaStream to avoid second getUserMedia (can fail on iOS)
|
|
29464
30499
|
console.log('🎤 VoiceSDK v2: Requesting microphone permission (mobile-friendly)...');
|
|
29465
|
-
_context8.n =
|
|
30500
|
+
_context8.n = 6;
|
|
29466
30501
|
return this.audioRecorder.start(existingMediaStream ? {
|
|
29467
30502
|
existingMediaStream: existingMediaStream
|
|
29468
30503
|
} : {});
|
|
29469
|
-
case
|
|
30504
|
+
case 6:
|
|
29470
30505
|
if (!(!this.isConnected || !this.websocket || this.websocket.readyState !== WebSocket.OPEN)) {
|
|
29471
|
-
_context8.n =
|
|
30506
|
+
_context8.n = 11;
|
|
29472
30507
|
break;
|
|
29473
30508
|
}
|
|
29474
|
-
_context8.p =
|
|
29475
|
-
_context8.n =
|
|
30509
|
+
_context8.p = 7;
|
|
30510
|
+
_context8.n = 8;
|
|
29476
30511
|
return this.audioRecorder.stop();
|
|
29477
|
-
case 7:
|
|
29478
|
-
_context8.n = 9;
|
|
29479
|
-
break;
|
|
29480
30512
|
case 8:
|
|
29481
|
-
_context8.
|
|
29482
|
-
|
|
30513
|
+
_context8.n = 10;
|
|
30514
|
+
break;
|
|
29483
30515
|
case 9:
|
|
30516
|
+
_context8.p = 9;
|
|
30517
|
+
_t6 = _context8.v;
|
|
30518
|
+
case 10:
|
|
29484
30519
|
_error5 = new Error('Connection lost - server may have rejected the call');
|
|
29485
30520
|
_error5.name = 'ServerRejected';
|
|
29486
30521
|
_error5.isServerRejection = true;
|
|
29487
30522
|
// Don't emit error event - this is expected when server rejects
|
|
29488
30523
|
// The error handler in VoiceInterface will handle it appropriately
|
|
29489
30524
|
throw _error5;
|
|
29490
|
-
case 10:
|
|
29491
|
-
_context8.n = 11;
|
|
29492
|
-
return this.audioPlayer.resumeAudioContext();
|
|
29493
30525
|
case 11:
|
|
30526
|
+
_context8.n = 12;
|
|
30527
|
+
return this.audioPlayer.resumeAudioContext();
|
|
30528
|
+
case 12:
|
|
29494
30529
|
// After permission is granted, send start_continuous_mode message to server
|
|
29495
30530
|
this.sendMessage({
|
|
29496
30531
|
t: 'start_continuous_mode',
|
|
@@ -29500,29 +30535,29 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29500
30535
|
// Request screen wake lock to keep screen on during voice call (mobile)
|
|
29501
30536
|
this._requestWakeLock();
|
|
29502
30537
|
return _context8.a(2, true);
|
|
29503
|
-
case
|
|
29504
|
-
_context8.p =
|
|
30538
|
+
case 13:
|
|
30539
|
+
_context8.p = 13;
|
|
29505
30540
|
_t7 = _context8.v;
|
|
29506
30541
|
if (!(this.audioRecorder && this.audioRecorder.isRecording)) {
|
|
29507
|
-
_context8.n =
|
|
30542
|
+
_context8.n = 17;
|
|
29508
30543
|
break;
|
|
29509
30544
|
}
|
|
29510
|
-
_context8.p =
|
|
29511
|
-
_context8.n =
|
|
30545
|
+
_context8.p = 14;
|
|
30546
|
+
_context8.n = 15;
|
|
29512
30547
|
return this.audioRecorder.stop();
|
|
29513
|
-
case 14:
|
|
29514
|
-
_context8.n = 16;
|
|
29515
|
-
break;
|
|
29516
30548
|
case 15:
|
|
29517
|
-
_context8.
|
|
29518
|
-
|
|
30549
|
+
_context8.n = 17;
|
|
30550
|
+
break;
|
|
29519
30551
|
case 16:
|
|
30552
|
+
_context8.p = 16;
|
|
30553
|
+
_t8 = _context8.v;
|
|
30554
|
+
case 17:
|
|
29520
30555
|
if (!(_t7.isServerRejection || _t7.name === 'ServerRejected')) {
|
|
29521
|
-
_context8.n =
|
|
30556
|
+
_context8.n = 18;
|
|
29522
30557
|
break;
|
|
29523
30558
|
}
|
|
29524
30559
|
return _context8.a(2, false);
|
|
29525
|
-
case
|
|
30560
|
+
case 18:
|
|
29526
30561
|
// Log and emit other errors (permission denied, etc.)
|
|
29527
30562
|
console.error('❌ VoiceSDK v2: Failed to start recording:', _t7);
|
|
29528
30563
|
|
|
@@ -29537,7 +30572,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29537
30572
|
}
|
|
29538
30573
|
return _context8.a(2, false);
|
|
29539
30574
|
}
|
|
29540
|
-
}, _callee8, this, [[
|
|
30575
|
+
}, _callee8, this, [[14, 16], [7, 9], [5, 13]]);
|
|
29541
30576
|
}));
|
|
29542
30577
|
function startRecording() {
|
|
29543
30578
|
return _startRecording.apply(this, arguments);
|
|
@@ -31369,7 +32404,10 @@ var AgentSDK = /*#__PURE__*/function () {
|
|
|
31369
32404
|
flavor: this.config.flavor || null,
|
|
31370
32405
|
// Shared client-tool handler map (set by TTPChatWidget so voice + text SDKs
|
|
31371
32406
|
// both look up handlers in the same registration site).
|
|
31372
|
-
sharedToolHandlers: this.config.sharedToolHandlers || null
|
|
32407
|
+
sharedToolHandlers: this.config.sharedToolHandlers || null,
|
|
32408
|
+
// Persisted in-call settings provider (voice speed / response length) —
|
|
32409
|
+
// read fresh at hello_ack so localStorage changes survive reconnects.
|
|
32410
|
+
callSettingsProvider: this.config.callSettingsProvider || null
|
|
31373
32411
|
}));
|
|
31374
32412
|
|
|
31375
32413
|
// If we have stored resume info from checkResumeBeforeConnect(), use it
|
|
@@ -32365,6 +33403,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
32365
33403
|
/* harmony import */ var _widget_translations_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./widget-translations.js */ "./src/widget/widget-translations.js");
|
|
32366
33404
|
/* harmony import */ var _flavors_index_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../flavors/index.js */ "./src/flavors/index.js");
|
|
32367
33405
|
/* harmony import */ var _ecommerce_EcommerceVoiceStrip_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../ecommerce/EcommerceVoiceStrip.js */ "./src/ecommerce/EcommerceVoiceStrip.js");
|
|
33406
|
+
/* harmony import */ var _ecommerce_RecipeStore_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../ecommerce/RecipeStore.js */ "./src/ecommerce/RecipeStore.js");
|
|
32368
33407
|
var _excluded = ["agentName"];
|
|
32369
33408
|
function _objectWithoutProperties(e, t) { if (null == e) return {}; var o, r, i = _objectWithoutPropertiesLoose(e, t); if (Object.getOwnPropertySymbols) { var n = Object.getOwnPropertySymbols(e); for (r = 0; r < n.length; r++) o = n[r], -1 === t.indexOf(o) && {}.propertyIsEnumerable.call(e, o) && (i[o] = e[o]); } return i; }
|
|
32370
33409
|
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
@@ -32393,6 +33432,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
|
|
|
32393
33432
|
|
|
32394
33433
|
|
|
32395
33434
|
|
|
33435
|
+
|
|
32396
33436
|
/** Fallback for `buildWebSocketUrl()` when no optional `websocketUrl` override is set (VoiceSDK v2 uses the same default). */
|
|
32397
33437
|
var DEFAULT_VOICE_WEBSOCKET_URL = 'wss://speech.talktopc.com/ws/conv';
|
|
32398
33438
|
function isNonEmptyConfigString(v) {
|
|
@@ -32485,7 +33525,8 @@ function talkToPcLinkColorForPanel(isLightPanel, mergedVoice, rawConfig, voiceUi
|
|
|
32485
33525
|
}
|
|
32486
33526
|
var TTPChatWidget = /*#__PURE__*/function () {
|
|
32487
33527
|
function TTPChatWidget() {
|
|
32488
|
-
var _this
|
|
33528
|
+
var _this = this,
|
|
33529
|
+
_this$config$behavior,
|
|
32489
33530
|
_this$config$panel,
|
|
32490
33531
|
_this$config$flavor,
|
|
32491
33532
|
_this$config$text,
|
|
@@ -32495,8 +33536,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
32495
33536
|
_this$config$voice3,
|
|
32496
33537
|
_this$config$voice4,
|
|
32497
33538
|
_this$config$voice5,
|
|
32498
|
-
_this$config$voice6
|
|
32499
|
-
_this = this;
|
|
33539
|
+
_this$config$voice6;
|
|
32500
33540
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
32501
33541
|
_classCallCheck(this, TTPChatWidget);
|
|
32502
33542
|
this._rawConfig = config;
|
|
@@ -32504,6 +33544,14 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
32504
33544
|
this.config = this.mergeWithDefaults(config);
|
|
32505
33545
|
// Silently ignore allowOverride (now server-side only)
|
|
32506
33546
|
|
|
33547
|
+
// Persisted in-call settings (voice speed / response length). The provider is
|
|
33548
|
+
// read fresh by VoiceSDK/TextChatSDK right after each hello_ack, so the saved
|
|
33549
|
+
// values re-apply silently on every (re)connect. Rides on this.config so both
|
|
33550
|
+
// voiceConfig spreads and the TextChatSDK constructor pick it up.
|
|
33551
|
+
this.config.callSettingsProvider = function () {
|
|
33552
|
+
return _this._loadCallSettings();
|
|
33553
|
+
};
|
|
33554
|
+
|
|
32507
33555
|
// Shared client-tool handler map. Both VoiceSDK and TextChatSDK look up
|
|
32508
33556
|
// handlers in this Map, so a single registerToolHandler() call works for
|
|
32509
33557
|
// whichever channel the LLM happens to be running on at tool-call time.
|
|
@@ -32825,11 +33873,21 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
32825
33873
|
if (flavor.messageHandlers['dismiss_media']) {
|
|
32826
33874
|
flavor.messageHandlers['dismiss_media']();
|
|
32827
33875
|
}
|
|
33876
|
+
if (flavor.messageHandlers['dismiss_recipe']) {
|
|
33877
|
+
flavor.messageHandlers['dismiss_recipe']({
|
|
33878
|
+
silent: true
|
|
33879
|
+
});
|
|
33880
|
+
}
|
|
32828
33881
|
});
|
|
32829
33882
|
this.voiceSDK.on('bargeIn', function () {
|
|
32830
33883
|
if (flavor.messageHandlers['dismiss_media']) {
|
|
32831
33884
|
flavor.messageHandlers['dismiss_media']();
|
|
32832
33885
|
}
|
|
33886
|
+
if (flavor.messageHandlers['dismiss_recipe']) {
|
|
33887
|
+
flavor.messageHandlers['dismiss_recipe']({
|
|
33888
|
+
silent: true
|
|
33889
|
+
});
|
|
33890
|
+
}
|
|
32833
33891
|
});
|
|
32834
33892
|
console.log("[TTPChatWidget] Flavor \"".concat(flavorName, "\" message listeners attached (voice)"));
|
|
32835
33893
|
}
|
|
@@ -33745,6 +34803,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
33745
34803
|
};
|
|
33746
34804
|
}
|
|
33747
34805
|
|
|
34806
|
+
/**
|
|
34807
|
+
* Scoped localStorage-backed store for saved recipes (strip badge + popover).
|
|
34808
|
+
*/
|
|
34809
|
+
}, {
|
|
34810
|
+
key: "getRecipeStore",
|
|
34811
|
+
value: function getRecipeStore() {
|
|
34812
|
+
if (!this._recipeStore) {
|
|
34813
|
+
var _this$_flavorObj2, _this$config$flavor2;
|
|
34814
|
+
var partnerId = ((_this$_flavorObj2 = this._flavorObj) === null || _this$_flavorObj2 === void 0 ? void 0 : _this$_flavorObj2.partnerId) || (_typeof(this.config.flavor) === 'object' ? (_this$config$flavor2 = this.config.flavor) === null || _this$config$flavor2 === void 0 ? void 0 : _this$config$flavor2.partnerId : null) || 'default';
|
|
34815
|
+
this._recipeStore = (0,_ecommerce_RecipeStore_js__WEBPACK_IMPORTED_MODULE_6__.createRecipeStore)((0,_ecommerce_RecipeStore_js__WEBPACK_IMPORTED_MODULE_6__.recipeStorageKey)(partnerId));
|
|
34816
|
+
}
|
|
34817
|
+
return this._recipeStore;
|
|
34818
|
+
}
|
|
34819
|
+
|
|
33748
34820
|
/**
|
|
33749
34821
|
* Generate footer branding HTML
|
|
33750
34822
|
*/
|
|
@@ -33832,7 +34904,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
33832
34904
|
return;
|
|
33833
34905
|
}
|
|
33834
34906
|
this._ensureAboutStyles();
|
|
33835
|
-
var version = true ? "2.
|
|
34907
|
+
var version = true ? "2.46.1" : 0;
|
|
33836
34908
|
var convId = this._getLastConversationId();
|
|
33837
34909
|
var t = function t(k, fb) {
|
|
33838
34910
|
try {
|
|
@@ -33889,6 +34961,190 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
33889
34961
|
this._aboutOverlay = null;
|
|
33890
34962
|
}
|
|
33891
34963
|
}
|
|
34964
|
+
|
|
34965
|
+
// ===================================================================================
|
|
34966
|
+
// In-call settings (voice speed / response length) — gear button + dialog
|
|
34967
|
+
// ===================================================================================
|
|
34968
|
+
|
|
34969
|
+
/** localStorage key for the persisted call settings, scoped per agent + origin. */
|
|
34970
|
+
}, {
|
|
34971
|
+
key: "_callSettingsStorageKey",
|
|
34972
|
+
value: function _callSettingsStorageKey() {
|
|
34973
|
+
var agent = this.config.agentId || this.config.appId || 'default';
|
|
34974
|
+
return "ttp_call_settings_".concat(agent);
|
|
34975
|
+
}
|
|
34976
|
+
|
|
34977
|
+
/**
|
|
34978
|
+
* Load persisted call settings. Defaults: agent-configured speed (factor 1.0)
|
|
34979
|
+
* and "normal" response length.
|
|
34980
|
+
* @returns {{voiceSpeedFactor: number, responseLength: string}}
|
|
34981
|
+
*/
|
|
34982
|
+
}, {
|
|
34983
|
+
key: "_loadCallSettings",
|
|
34984
|
+
value: function _loadCallSettings() {
|
|
34985
|
+
var defaults = {
|
|
34986
|
+
voiceSpeedFactor: 1.0,
|
|
34987
|
+
responseLength: 'normal'
|
|
34988
|
+
};
|
|
34989
|
+
try {
|
|
34990
|
+
var raw = localStorage.getItem(this._callSettingsStorageKey());
|
|
34991
|
+
if (!raw) return defaults;
|
|
34992
|
+
var s = JSON.parse(raw);
|
|
34993
|
+
var factor = typeof s.voiceSpeedFactor === 'number' ? Math.max(0.5, Math.min(2.0, s.voiceSpeedFactor)) : 1.0;
|
|
34994
|
+
var length = ['detailed', 'normal', 'brief', 'very_brief'].includes(s.responseLength) ? s.responseLength : 'normal';
|
|
34995
|
+
return {
|
|
34996
|
+
voiceSpeedFactor: factor,
|
|
34997
|
+
responseLength: length
|
|
34998
|
+
};
|
|
34999
|
+
} catch (_) {
|
|
35000
|
+
return defaults;
|
|
35001
|
+
}
|
|
35002
|
+
}
|
|
35003
|
+
}, {
|
|
35004
|
+
key: "_saveCallSettings",
|
|
35005
|
+
value: function _saveCallSettings(settings) {
|
|
35006
|
+
try {
|
|
35007
|
+
localStorage.setItem(this._callSettingsStorageKey(), JSON.stringify(settings));
|
|
35008
|
+
} catch (_) {/* storage unavailable — settings still apply for this session */}
|
|
35009
|
+
}
|
|
35010
|
+
|
|
35011
|
+
/**
|
|
35012
|
+
* Persist + push a settings change to whichever channel is live. The backend
|
|
35013
|
+
* applies voice speed from the next spoken line and response length from the
|
|
35014
|
+
* next LLM turn — no tool call involved. announce=true lets the agent speak
|
|
35015
|
+
* its short fixed confirmation (only when idle).
|
|
35016
|
+
*/
|
|
35017
|
+
}, {
|
|
35018
|
+
key: "_applyCallSettings",
|
|
35019
|
+
value: function _applyCallSettings(partial) {
|
|
35020
|
+
var _this$voiceInterface4, _this$sdk2;
|
|
35021
|
+
var announce = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
|
35022
|
+
var merged = _objectSpread(_objectSpread({}, this._loadCallSettings()), partial);
|
|
35023
|
+
this._saveCallSettings(merged);
|
|
35024
|
+
var voice = (_this$voiceInterface4 = this.voiceInterface) === null || _this$voiceInterface4 === void 0 || (_this$voiceInterface4 = _this$voiceInterface4.sdk) === null || _this$voiceInterface4 === void 0 ? void 0 : _this$voiceInterface4.voiceSDK;
|
|
35025
|
+
if (voice !== null && voice !== void 0 && voice.setCallSettings) {
|
|
35026
|
+
voice.setCallSettings({
|
|
35027
|
+
voiceSpeedFactor: merged.voiceSpeedFactor,
|
|
35028
|
+
responseLength: merged.responseLength
|
|
35029
|
+
}, {
|
|
35030
|
+
announce: announce
|
|
35031
|
+
});
|
|
35032
|
+
}
|
|
35033
|
+
if ((_this$sdk2 = this.sdk) !== null && _this$sdk2 !== void 0 && _this$sdk2.setCallSettings && this.sdk.connected) {
|
|
35034
|
+
this.sdk.setCallSettings({
|
|
35035
|
+
responseLength: merged.responseLength
|
|
35036
|
+
});
|
|
35037
|
+
}
|
|
35038
|
+
}
|
|
35039
|
+
|
|
35040
|
+
/** Inject the settings-dialog styles into document.head once (global, above the strip). */
|
|
35041
|
+
}, {
|
|
35042
|
+
key: "_ensureCallSettingsStyles",
|
|
35043
|
+
value: function _ensureCallSettingsStyles() {
|
|
35044
|
+
if (document.getElementById('ttp-callsettings-dialog-styles')) return;
|
|
35045
|
+
this._ensureAboutStyles(); // reuse the overlay/card/close/row styles
|
|
35046
|
+
var style = document.createElement('style');
|
|
35047
|
+
style.id = 'ttp-callsettings-dialog-styles';
|
|
35048
|
+
style.textContent = "\n .ttp-cs-row { text-align: start; }\n .ttp-cs-head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 6px; }\n .ttp-cs-val {\n font-size: 13px; font-weight: 700; color: #6d28d9;\n font-variant-numeric: tabular-nums;\n }\n .ttp-cs-slider {\n -webkit-appearance: none; appearance: none; width: 100%; height: 6px;\n border-radius: 3px; background: #e5e7eb; outline: none; cursor: pointer;\n accent-color: #6d28d9; margin: 4px 0 2px;\n }\n .ttp-cs-slider::-webkit-slider-thumb {\n -webkit-appearance: none; appearance: none; width: 18px; height: 18px;\n border-radius: 50%; background: #6d28d9; border: 2px solid #ffffff;\n box-shadow: 0 1px 4px rgba(0,0,0,0.3); cursor: pointer;\n }\n .ttp-cs-slider::-moz-range-thumb {\n width: 18px; height: 18px; border-radius: 50%; background: #6d28d9;\n border: 2px solid #ffffff; box-shadow: 0 1px 4px rgba(0,0,0,0.3); cursor: pointer;\n }\n .ttp-cs-ends {\n display: flex; justify-content: space-between;\n font-size: 10.5px; color: #9ca3af; letter-spacing: 0.2px;\n }\n ";
|
|
35049
|
+
document.head.appendChild(style);
|
|
35050
|
+
}
|
|
35051
|
+
|
|
35052
|
+
/**
|
|
35053
|
+
* Open the in-call settings dialog: two sliders — voice speed (higher = faster)
|
|
35054
|
+
* and response length (very brief on the left → detailed on the right). Values
|
|
35055
|
+
* persist to localStorage and apply from the next line/turn (backend `call_settings`).
|
|
35056
|
+
*/
|
|
35057
|
+
}, {
|
|
35058
|
+
key: "_openCallSettingsModal",
|
|
35059
|
+
value: function _openCallSettingsModal() {
|
|
35060
|
+
var _this9 = this,
|
|
35061
|
+
_overlay$querySelecto2;
|
|
35062
|
+
if (this._callSettingsOverlay) {
|
|
35063
|
+
this._closeCallSettingsModal();
|
|
35064
|
+
return;
|
|
35065
|
+
}
|
|
35066
|
+
this._ensureCallSettingsStyles();
|
|
35067
|
+
var t = function t(k, fb) {
|
|
35068
|
+
try {
|
|
35069
|
+
var _this9$voiceInterface, _this9$voiceInterface2, _this9$textInterface, _this9$textInterface$;
|
|
35070
|
+
return ((_this9$voiceInterface = _this9.voiceInterface) === null || _this9$voiceInterface === void 0 || (_this9$voiceInterface2 = _this9$voiceInterface.t) === null || _this9$voiceInterface2 === void 0 ? void 0 : _this9$voiceInterface2.call(_this9$voiceInterface, k)) || ((_this9$textInterface = _this9.textInterface) === null || _this9$textInterface === void 0 || (_this9$textInterface$ = _this9$textInterface.t) === null || _this9$textInterface$ === void 0 ? void 0 : _this9$textInterface$.call(_this9$textInterface, k)) || fb;
|
|
35071
|
+
} catch (_) {
|
|
35072
|
+
return fb;
|
|
35073
|
+
}
|
|
35074
|
+
};
|
|
35075
|
+
var title = t('settingsTitle', 'Call settings');
|
|
35076
|
+
var speedLabel = t('settingsVoiceSpeed', 'Voice speed');
|
|
35077
|
+
var lengthLabel = t('settingsResponseLength', 'Response length');
|
|
35078
|
+
// Slider order: very brief (left) → detailed (right); higher = more detail.
|
|
35079
|
+
var LEVELS = ['very_brief', 'brief', 'normal', 'detailed'];
|
|
35080
|
+
var levelLabels = {
|
|
35081
|
+
detailed: t('lengthDetailed', 'Detailed'),
|
|
35082
|
+
normal: t('lengthNormal', 'Normal'),
|
|
35083
|
+
brief: t('lengthBrief', 'Brief'),
|
|
35084
|
+
very_brief: t('lengthVeryBrief', 'Very brief')
|
|
35085
|
+
};
|
|
35086
|
+
var saved = this._loadCallSettings();
|
|
35087
|
+
var levelIdx = Math.max(0, LEVELS.indexOf(saved.responseLength));
|
|
35088
|
+
var overlay = document.createElement('div');
|
|
35089
|
+
overlay.className = 'ttp-about-overlay';
|
|
35090
|
+
overlay.innerHTML = "\n <div class=\"ttp-about-card\" role=\"dialog\" aria-modal=\"true\" aria-label=\"".concat(title, "\">\n <button type=\"button\" class=\"ttp-about-close\" aria-label=\"Close\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n <div class=\"ttp-about-title\">").concat(title, "</div>\n <div class=\"ttp-about-rows\">\n <div class=\"ttp-about-row ttp-cs-row\">\n <div class=\"ttp-cs-head\">\n <span class=\"ttp-about-key\">").concat(speedLabel, "</span>\n <span class=\"ttp-cs-val\" data-cs-speed-val></span>\n </div>\n <input type=\"range\" class=\"ttp-cs-slider\" data-cs-speed\n min=\"0.5\" max=\"2\" step=\"0.05\" value=\"").concat(saved.voiceSpeedFactor, "\"\n aria-label=\"").concat(speedLabel, "\">\n <div class=\"ttp-cs-ends\"><span>0.5\xD7</span><span>2\xD7</span></div>\n </div>\n <div class=\"ttp-about-row ttp-cs-row\">\n <div class=\"ttp-cs-head\">\n <span class=\"ttp-about-key\">").concat(lengthLabel, "</span>\n <span class=\"ttp-cs-val\" data-cs-length-val></span>\n </div>\n <input type=\"range\" class=\"ttp-cs-slider\" data-cs-length\n min=\"0\" max=\"3\" step=\"1\" value=\"").concat(levelIdx, "\"\n aria-label=\"").concat(lengthLabel, "\">\n <div class=\"ttp-cs-ends\"><span>").concat(levelLabels.very_brief, "</span><span>").concat(levelLabels.detailed, "</span></div>\n </div>\n </div>\n </div>");
|
|
35091
|
+
var speedSlider = overlay.querySelector('[data-cs-speed]');
|
|
35092
|
+
var speedVal = overlay.querySelector('[data-cs-speed-val]');
|
|
35093
|
+
var lengthSlider = overlay.querySelector('[data-cs-length]');
|
|
35094
|
+
var lengthVal = overlay.querySelector('[data-cs-length-val]');
|
|
35095
|
+
var fmtSpeed = function fmtSpeed(v) {
|
|
35096
|
+
return "".concat(Number(v).toFixed(2).replace(/0$/, ''), "\xD7");
|
|
35097
|
+
};
|
|
35098
|
+
var renderVals = function renderVals() {
|
|
35099
|
+
if (speedVal) speedVal.textContent = fmtSpeed(speedSlider.value);
|
|
35100
|
+
if (lengthVal) lengthVal.textContent = levelLabels[LEVELS[Number(lengthSlider.value)]] || '';
|
|
35101
|
+
};
|
|
35102
|
+
renderVals();
|
|
35103
|
+
|
|
35104
|
+
// Live label updates while dragging; persist + push on release only.
|
|
35105
|
+
speedSlider === null || speedSlider === void 0 || speedSlider.addEventListener('input', renderVals);
|
|
35106
|
+
lengthSlider === null || lengthSlider === void 0 || lengthSlider.addEventListener('input', renderVals);
|
|
35107
|
+
speedSlider === null || speedSlider === void 0 || speedSlider.addEventListener('change', function () {
|
|
35108
|
+
_this9._applyCallSettings({
|
|
35109
|
+
voiceSpeedFactor: Number(speedSlider.value)
|
|
35110
|
+
}, true);
|
|
35111
|
+
});
|
|
35112
|
+
lengthSlider === null || lengthSlider === void 0 || lengthSlider.addEventListener('change', function () {
|
|
35113
|
+
_this9._applyCallSettings({
|
|
35114
|
+
responseLength: LEVELS[Number(lengthSlider.value)]
|
|
35115
|
+
}, true);
|
|
35116
|
+
});
|
|
35117
|
+
var close = function close() {
|
|
35118
|
+
return _this9._closeCallSettingsModal();
|
|
35119
|
+
};
|
|
35120
|
+
overlay.addEventListener('click', function (e) {
|
|
35121
|
+
if (e.target === overlay) close();
|
|
35122
|
+
});
|
|
35123
|
+
(_overlay$querySelecto2 = overlay.querySelector('.ttp-about-close')) === null || _overlay$querySelecto2 === void 0 || _overlay$querySelecto2.addEventListener('click', function (e) {
|
|
35124
|
+
e.stopPropagation();
|
|
35125
|
+
close();
|
|
35126
|
+
});
|
|
35127
|
+
this._callSettingsKeyHandler = function (e) {
|
|
35128
|
+
if (e.key === 'Escape') close();
|
|
35129
|
+
};
|
|
35130
|
+
document.addEventListener('keydown', this._callSettingsKeyHandler);
|
|
35131
|
+
document.body.appendChild(overlay);
|
|
35132
|
+
this._callSettingsOverlay = overlay;
|
|
35133
|
+
}
|
|
35134
|
+
|
|
35135
|
+
/** Close the in-call settings dialog if open. */
|
|
35136
|
+
}, {
|
|
35137
|
+
key: "_closeCallSettingsModal",
|
|
35138
|
+
value: function _closeCallSettingsModal() {
|
|
35139
|
+
if (this._callSettingsKeyHandler) {
|
|
35140
|
+
document.removeEventListener('keydown', this._callSettingsKeyHandler);
|
|
35141
|
+
this._callSettingsKeyHandler = null;
|
|
35142
|
+
}
|
|
35143
|
+
if (this._callSettingsOverlay) {
|
|
35144
|
+
this._callSettingsOverlay.remove();
|
|
35145
|
+
this._callSettingsOverlay = null;
|
|
35146
|
+
}
|
|
35147
|
+
}
|
|
33892
35148
|
}, {
|
|
33893
35149
|
key: "generatePositionStyles",
|
|
33894
35150
|
value: function generatePositionStyles() {
|
|
@@ -34025,7 +35281,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34025
35281
|
}, {
|
|
34026
35282
|
key: "setupWidgetEvents",
|
|
34027
35283
|
value: function setupWidgetEvents() {
|
|
34028
|
-
var
|
|
35284
|
+
var _this0 = this,
|
|
34029
35285
|
_this$config$behavior8,
|
|
34030
35286
|
_this$config$position5;
|
|
34031
35287
|
if (!this.shadowRoot) return;
|
|
@@ -34039,17 +35295,17 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34039
35295
|
launcherBtn.onclick = function (e) {
|
|
34040
35296
|
e.stopPropagation();
|
|
34041
35297
|
// A drag just ended — don't treat the trailing click as "open panel".
|
|
34042
|
-
if (
|
|
34043
|
-
if (
|
|
34044
|
-
|
|
35298
|
+
if (_this0._suppressLauncherClick) return;
|
|
35299
|
+
if (_this0.config.promptAnimation.hideAfterClick) {
|
|
35300
|
+
_this0.hidePrompt();
|
|
34045
35301
|
}
|
|
34046
|
-
|
|
35302
|
+
_this0.togglePanel();
|
|
34047
35303
|
};
|
|
34048
35304
|
}
|
|
34049
35305
|
var closeBtn = this.shadowRoot.getElementById('closeBtn');
|
|
34050
35306
|
if (closeBtn) {
|
|
34051
35307
|
closeBtn.onclick = function () {
|
|
34052
|
-
|
|
35308
|
+
_this0._doTogglePanel();
|
|
34053
35309
|
};
|
|
34054
35310
|
}
|
|
34055
35311
|
|
|
@@ -34057,23 +35313,34 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34057
35313
|
var closeIdle = this.shadowRoot.getElementById('ttpCloseIdle');
|
|
34058
35314
|
if (closeIdle) {
|
|
34059
35315
|
closeIdle.onclick = function () {
|
|
34060
|
-
return
|
|
35316
|
+
return _this0._doTogglePanel();
|
|
34061
35317
|
};
|
|
34062
35318
|
}
|
|
34063
35319
|
var closeActive = this.shadowRoot.getElementById('ttpCloseActive');
|
|
34064
35320
|
if (closeActive) {
|
|
34065
35321
|
closeActive.onclick = function () {
|
|
34066
|
-
return
|
|
35322
|
+
return _this0._doTogglePanel();
|
|
34067
35323
|
};
|
|
34068
35324
|
}
|
|
34069
35325
|
|
|
34070
35326
|
// "About" info buttons (present in every view: idle / active / compact /
|
|
34071
35327
|
// mobile idle / mobile active / text top-bar). One shared dialog.
|
|
34072
|
-
|
|
35328
|
+
// Settings gear buttons share the .ttp-info-btn styling class — skip them here.
|
|
35329
|
+
this.shadowRoot.querySelectorAll('.ttp-info-btn:not(.ttp-settings-btn)').forEach(function (btn) {
|
|
35330
|
+
btn.onclick = function (e) {
|
|
35331
|
+
e.stopPropagation();
|
|
35332
|
+
e.preventDefault();
|
|
35333
|
+
_this0._openAboutModal();
|
|
35334
|
+
};
|
|
35335
|
+
});
|
|
35336
|
+
|
|
35337
|
+
// In-call settings gear buttons (active-call views) — one shared dialog with
|
|
35338
|
+
// the voice-speed / response-length sliders.
|
|
35339
|
+
this.shadowRoot.querySelectorAll('.ttp-settings-btn').forEach(function (btn) {
|
|
34073
35340
|
btn.onclick = function (e) {
|
|
34074
35341
|
e.stopPropagation();
|
|
34075
35342
|
e.preventDefault();
|
|
34076
|
-
|
|
35343
|
+
_this0._openCallSettingsModal();
|
|
34077
35344
|
};
|
|
34078
35345
|
});
|
|
34079
35346
|
|
|
@@ -34081,17 +35348,17 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34081
35348
|
var startTextBtn = this.shadowRoot.getElementById('startTextBtn');
|
|
34082
35349
|
if (startTextBtn) {
|
|
34083
35350
|
startTextBtn.onclick = function () {
|
|
34084
|
-
return
|
|
35351
|
+
return _this0.showText();
|
|
34085
35352
|
};
|
|
34086
35353
|
}
|
|
34087
35354
|
var textUnifiedBackBtn = this.shadowRoot.getElementById('textUnifiedBackBtn');
|
|
34088
35355
|
if (textUnifiedBackBtn) {
|
|
34089
35356
|
textUnifiedBackBtn.onclick = function () {
|
|
34090
|
-
var
|
|
34091
|
-
var widgetMode = ((
|
|
35357
|
+
var _this0$config$behavio;
|
|
35358
|
+
var widgetMode = ((_this0$config$behavio = _this0.config.behavior) === null || _this0$config$behavio === void 0 ? void 0 : _this0$config$behavio.mode) || 'unified';
|
|
34092
35359
|
if (widgetMode !== 'unified') return;
|
|
34093
|
-
|
|
34094
|
-
|
|
35360
|
+
_this0.showLanding();
|
|
35361
|
+
_this0._openMobileCallTextLanding();
|
|
34095
35362
|
};
|
|
34096
35363
|
}
|
|
34097
35364
|
|
|
@@ -34121,30 +35388,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34121
35388
|
// Setup back button handler
|
|
34122
35389
|
if (backBtn) {
|
|
34123
35390
|
backBtn.onclick = function () {
|
|
34124
|
-
var
|
|
35391
|
+
var _this0$voiceInterface, _this0$voiceInterface3;
|
|
34125
35392
|
// Check if we're showing a domain error — clear it and return to voice hero
|
|
34126
|
-
if ((
|
|
34127
|
-
var
|
|
35393
|
+
if ((_this0$voiceInterface = _this0.voiceInterface) !== null && _this0$voiceInterface !== void 0 && _this0$voiceInterface.isShowingDomainError) {
|
|
35394
|
+
var _this0$voiceInterface2;
|
|
34128
35395
|
console.log('🔙 Back button clicked - clearing domain error and returning to voice hero');
|
|
34129
35396
|
// Clear the domain error flag
|
|
34130
|
-
|
|
35397
|
+
_this0.voiceInterface.isShowingDomainError = false;
|
|
34131
35398
|
// Reset the connecting state (this will restore normal UI)
|
|
34132
|
-
if ((
|
|
34133
|
-
|
|
35399
|
+
if ((_this0$voiceInterface2 = _this0.voiceInterface) !== null && _this0$voiceInterface2 !== void 0 && _this0$voiceInterface2.resetConnectingState) {
|
|
35400
|
+
_this0.voiceInterface.resetConnectingState();
|
|
34134
35401
|
}
|
|
34135
|
-
|
|
34136
|
-
|
|
35402
|
+
_this0.showLanding();
|
|
35403
|
+
_this0._openMobileCallTextLanding();
|
|
34137
35404
|
return;
|
|
34138
35405
|
}
|
|
34139
|
-
if ((
|
|
35406
|
+
if ((_this0$voiceInterface3 = _this0.voiceInterface) !== null && _this0$voiceInterface3 !== void 0 && _this0$voiceInterface3.isActive) {
|
|
34140
35407
|
// If call is active, show message inside widget instead of modal
|
|
34141
|
-
|
|
35408
|
+
_this0.showBackButtonWarning();
|
|
34142
35409
|
} else if (window.innerWidth <= 768) {
|
|
34143
|
-
|
|
34144
|
-
|
|
35410
|
+
_this0.showLanding();
|
|
35411
|
+
_this0._openMobileCallTextLanding();
|
|
34145
35412
|
} else {
|
|
34146
35413
|
// Desktop: return to voice hero (unified home)
|
|
34147
|
-
|
|
35414
|
+
_this0.showLanding();
|
|
34148
35415
|
}
|
|
34149
35416
|
};
|
|
34150
35417
|
}
|
|
@@ -34187,7 +35454,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34187
35454
|
// Setup header button handlers
|
|
34188
35455
|
if (newChatBtn) {
|
|
34189
35456
|
newChatBtn.onclick = function () {
|
|
34190
|
-
return
|
|
35457
|
+
return _this0.textInterface.startNewChat();
|
|
34191
35458
|
};
|
|
34192
35459
|
// Hide new chat on unified home (voice hero) initially
|
|
34193
35460
|
if (isUnified && this.currentView !== 'text') {
|
|
@@ -34333,7 +35600,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34333
35600
|
}, {
|
|
34334
35601
|
key: "_restoreUnitOffset",
|
|
34335
35602
|
value: function _restoreUnitOffset(key) {
|
|
34336
|
-
var
|
|
35603
|
+
var _this1 = this;
|
|
34337
35604
|
var saved;
|
|
34338
35605
|
try {
|
|
34339
35606
|
saved = JSON.parse(window.localStorage.getItem(key) || 'null');
|
|
@@ -34342,13 +35609,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34342
35609
|
}
|
|
34343
35610
|
if (!saved || typeof saved.x !== 'number' || typeof saved.y !== 'number') return;
|
|
34344
35611
|
requestAnimationFrame(function () {
|
|
34345
|
-
|
|
35612
|
+
_this1._unitOffset = {
|
|
34346
35613
|
x: 0,
|
|
34347
35614
|
y: 0
|
|
34348
35615
|
}; // ensure DOM matches before measuring
|
|
34349
|
-
var bases =
|
|
34350
|
-
|
|
34351
|
-
|
|
35616
|
+
var bases = _this1._unitBaseRects();
|
|
35617
|
+
_this1._unitOffset = _this1._clampUnitOffset(saved.x, saved.y, bases);
|
|
35618
|
+
_this1._applyUnitOffset();
|
|
34352
35619
|
});
|
|
34353
35620
|
}
|
|
34354
35621
|
|
|
@@ -34365,7 +35632,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34365
35632
|
}, {
|
|
34366
35633
|
key: "_attachUnitDrag",
|
|
34367
35634
|
value: function _attachUnitDrag(handle, opts) {
|
|
34368
|
-
var
|
|
35635
|
+
var _this10 = this;
|
|
34369
35636
|
var persist = opts.persist,
|
|
34370
35637
|
key = opts.key,
|
|
34371
35638
|
excludeSelector = opts.excludeSelector,
|
|
@@ -34386,8 +35653,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34386
35653
|
var dy = e.clientY - startY;
|
|
34387
35654
|
if (!moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
|
|
34388
35655
|
moved = true;
|
|
34389
|
-
|
|
34390
|
-
|
|
35656
|
+
_this10._unitOffset = _this10._clampUnitOffset(baseX + dx, baseY + dy, bases);
|
|
35657
|
+
_this10._applyUnitOffset();
|
|
34391
35658
|
};
|
|
34392
35659
|
var _onUp = function onUp(e) {
|
|
34393
35660
|
window.removeEventListener('pointermove', onMove);
|
|
@@ -34401,7 +35668,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34401
35668
|
if (typeof onMoved === 'function') onMoved();
|
|
34402
35669
|
if (persist && key) {
|
|
34403
35670
|
try {
|
|
34404
|
-
window.localStorage.setItem(key, JSON.stringify(
|
|
35671
|
+
window.localStorage.setItem(key, JSON.stringify(_this10._unitOffset));
|
|
34405
35672
|
} catch (err) {/* unavailable */}
|
|
34406
35673
|
}
|
|
34407
35674
|
}
|
|
@@ -34412,7 +35679,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34412
35679
|
if (excludeSelector && e.target && e.target.closest && e.target.closest(excludeSelector)) return;
|
|
34413
35680
|
dragging = true;
|
|
34414
35681
|
moved = false;
|
|
34415
|
-
var o =
|
|
35682
|
+
var o = _this10._unitOffset || (_this10._unitOffset = {
|
|
34416
35683
|
x: 0,
|
|
34417
35684
|
y: 0
|
|
34418
35685
|
});
|
|
@@ -34420,7 +35687,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34420
35687
|
startY = e.clientY;
|
|
34421
35688
|
baseX = o.x;
|
|
34422
35689
|
baseY = o.y;
|
|
34423
|
-
bases =
|
|
35690
|
+
bases = _this10._unitBaseRects();
|
|
34424
35691
|
handle.style.setProperty('cursor', 'grabbing');
|
|
34425
35692
|
try {
|
|
34426
35693
|
handle.setPointerCapture(e.pointerId);
|
|
@@ -34442,7 +35709,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34442
35709
|
key: "setupDraggableWidget",
|
|
34443
35710
|
value: function setupDraggableWidget() {
|
|
34444
35711
|
var _this$config$position6,
|
|
34445
|
-
|
|
35712
|
+
_this11 = this;
|
|
34446
35713
|
var root = this.shadowRoot;
|
|
34447
35714
|
if (!root) return;
|
|
34448
35715
|
var container = root.getElementById('text-chat-button-container');
|
|
@@ -34458,14 +35725,14 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34458
35725
|
|
|
34459
35726
|
// Launcher handles: pill + mobile FAB (suppress the click after a drag).
|
|
34460
35727
|
[root.getElementById('text-chat-button'), root.querySelector('.ttp-mobile-fab')].filter(Boolean).forEach(function (h) {
|
|
34461
|
-
return
|
|
35728
|
+
return _this11._attachUnitDrag(h, {
|
|
34462
35729
|
persist: persist,
|
|
34463
35730
|
key: key,
|
|
34464
35731
|
restCursor: 'grab',
|
|
34465
35732
|
onMoved: function onMoved() {
|
|
34466
|
-
|
|
35733
|
+
_this11._suppressLauncherClick = true;
|
|
34467
35734
|
setTimeout(function () {
|
|
34468
|
-
|
|
35735
|
+
_this11._suppressLauncherClick = false;
|
|
34469
35736
|
}, 0);
|
|
34470
35737
|
}
|
|
34471
35738
|
});
|
|
@@ -34476,7 +35743,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34476
35743
|
['.ttp-header', '.ttp-call-topbar', '.text-interface-top-bar'].map(function (sel) {
|
|
34477
35744
|
return panel.querySelector(sel);
|
|
34478
35745
|
}).filter(Boolean).forEach(function (h) {
|
|
34479
|
-
return
|
|
35746
|
+
return _this11._attachUnitDrag(h, {
|
|
34480
35747
|
persist: persist,
|
|
34481
35748
|
key: key,
|
|
34482
35749
|
restCursor: 'move',
|
|
@@ -34511,13 +35778,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34511
35778
|
}, {
|
|
34512
35779
|
key: "_bindDragResize",
|
|
34513
35780
|
value: function _bindDragResize() {
|
|
34514
|
-
var
|
|
35781
|
+
var _this12 = this;
|
|
34515
35782
|
if (this._dragResizeBound) return;
|
|
34516
35783
|
this._dragResizeBound = true;
|
|
34517
35784
|
window.addEventListener('resize', function () {
|
|
34518
|
-
var
|
|
34519
|
-
|
|
34520
|
-
(
|
|
35785
|
+
var _this12$_ecommerceVoi, _this12$_ecommerceVoi2;
|
|
35786
|
+
_this12._reclampUnit();
|
|
35787
|
+
(_this12$_ecommerceVoi = _this12._ecommerceVoiceStrip) === null || _this12$_ecommerceVoi === void 0 || (_this12$_ecommerceVoi2 = _this12$_ecommerceVoi.reclampDrag) === null || _this12$_ecommerceVoi2 === void 0 || _this12$_ecommerceVoi2.call(_this12$_ecommerceVoi);
|
|
34521
35788
|
});
|
|
34522
35789
|
}
|
|
34523
35790
|
}, {
|
|
@@ -34566,9 +35833,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34566
35833
|
}, {
|
|
34567
35834
|
key: "_isDomainErrorVisible",
|
|
34568
35835
|
value: function _isDomainErrorVisible() {
|
|
34569
|
-
var _this$
|
|
34570
|
-
if ((_this$
|
|
34571
|
-
var idleState = (_this$
|
|
35836
|
+
var _this$voiceInterface5, _this$voiceInterface6, _idleState$dataset;
|
|
35837
|
+
if ((_this$voiceInterface5 = this.voiceInterface) !== null && _this$voiceInterface5 !== void 0 && _this$voiceInterface5.isShowingDomainError) return true;
|
|
35838
|
+
var idleState = (_this$voiceInterface6 = this.voiceInterface) === null || _this$voiceInterface6 === void 0 || (_this$voiceInterface6 = _this$voiceInterface6.shadowRoot) === null || _this$voiceInterface6 === void 0 ? void 0 : _this$voiceInterface6.getElementById('voiceIdleState');
|
|
34572
35839
|
return idleState && ((_idleState$dataset = idleState.dataset) === null || _idleState$dataset === void 0 ? void 0 : _idleState$dataset.domainError) === 'true';
|
|
34573
35840
|
}
|
|
34574
35841
|
}, {
|
|
@@ -34596,7 +35863,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34596
35863
|
}, {
|
|
34597
35864
|
key: "_openMobileCallTextLanding",
|
|
34598
35865
|
value: function _openMobileCallTextLanding() {
|
|
34599
|
-
var
|
|
35866
|
+
var _this13 = this;
|
|
34600
35867
|
if (!this.shadowRoot || window.innerWidth > 768) return;
|
|
34601
35868
|
var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
|
|
34602
35869
|
var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
|
|
@@ -34607,30 +35874,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34607
35874
|
// "Back" button: composedPath includes the panel but not #ttpMobileLanding, so it treated
|
|
34608
35875
|
// the click as "outside" and closed the landing immediately (user only saw the FAB again).
|
|
34609
35876
|
var open = function open() {
|
|
34610
|
-
if (!
|
|
34611
|
-
var panel =
|
|
35877
|
+
if (!_this13.shadowRoot || window.innerWidth > 768) return;
|
|
35878
|
+
var panel = _this13.shadowRoot.getElementById('text-chat-panel');
|
|
34612
35879
|
if (panel) {
|
|
34613
35880
|
panel.classList.remove('open');
|
|
34614
|
-
|
|
35881
|
+
_this13.isOpen = false;
|
|
34615
35882
|
}
|
|
34616
|
-
if (
|
|
34617
|
-
|
|
35883
|
+
if (_this13.config.promptAnimation.hideAfterClick) {
|
|
35884
|
+
_this13.hidePrompt();
|
|
34618
35885
|
}
|
|
34619
|
-
var errorBanner =
|
|
35886
|
+
var errorBanner = _this13.shadowRoot.getElementById('ttpMobileLandingError');
|
|
34620
35887
|
if (errorBanner) errorBanner.style.display = 'none';
|
|
34621
|
-
var fab =
|
|
34622
|
-
var landing =
|
|
35888
|
+
var fab = _this13.shadowRoot.querySelector('.ttp-mobile-fab');
|
|
35889
|
+
var landing = _this13.shadowRoot.getElementById('ttpMobileLanding');
|
|
34623
35890
|
if (!fab || !landing) return;
|
|
34624
35891
|
fab.style.display = 'none';
|
|
34625
35892
|
landing.classList.add('active');
|
|
34626
|
-
|
|
35893
|
+
_this13.isMobileLandingOpen = true;
|
|
34627
35894
|
};
|
|
34628
35895
|
queueMicrotask(open);
|
|
34629
35896
|
}
|
|
34630
35897
|
}, {
|
|
34631
35898
|
key: "setupMobileWidgetEvents",
|
|
34632
35899
|
value: function setupMobileWidgetEvents() {
|
|
34633
|
-
var
|
|
35900
|
+
var _this14 = this;
|
|
34634
35901
|
if (!this.shadowRoot) return;
|
|
34635
35902
|
var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
|
|
34636
35903
|
var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
|
|
@@ -34638,12 +35905,12 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34638
35905
|
var closeMobileLanding = function closeMobileLanding() {
|
|
34639
35906
|
mobileLanding.classList.remove('active');
|
|
34640
35907
|
mobileFab.style.display = '';
|
|
34641
|
-
|
|
35908
|
+
_this14.isMobileLandingOpen = false;
|
|
34642
35909
|
};
|
|
34643
35910
|
mobileFab.onclick = function () {
|
|
34644
35911
|
// A drag just ended — don't open the landing on the trailing click.
|
|
34645
|
-
if (
|
|
34646
|
-
|
|
35912
|
+
if (_this14._suppressLauncherClick) return;
|
|
35913
|
+
_this14._openMobileCallTextLanding();
|
|
34647
35914
|
};
|
|
34648
35915
|
var mobileClose = mobileLanding.querySelector('.ttp-mobile-landing__close');
|
|
34649
35916
|
if (mobileClose) {
|
|
@@ -34653,18 +35920,18 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34653
35920
|
if (mobileCallBtn) {
|
|
34654
35921
|
mobileCallBtn.onclick = function () {
|
|
34655
35922
|
closeMobileLanding();
|
|
34656
|
-
var panel =
|
|
35923
|
+
var panel = _this14.shadowRoot.getElementById('text-chat-panel');
|
|
34657
35924
|
if (panel) {
|
|
34658
35925
|
panel.style.removeProperty('display');
|
|
34659
35926
|
panel.classList.add('open');
|
|
34660
|
-
|
|
35927
|
+
_this14.isOpen = true;
|
|
34661
35928
|
}
|
|
34662
35929
|
mobileFab.style.display = 'none';
|
|
34663
|
-
|
|
35930
|
+
_this14.showVoice();
|
|
34664
35931
|
// Landing already chose "Voice call" — start the call (mic permission / pre-prompt) instead of
|
|
34665
35932
|
// leaving users on a second "Start Call" tap that feels broken.
|
|
34666
35933
|
queueMicrotask(function () {
|
|
34667
|
-
|
|
35934
|
+
_this14.startVoiceCall().catch(function (err) {
|
|
34668
35935
|
console.error('[TTPChatWidget] Mobile landing voice start failed:', err);
|
|
34669
35936
|
});
|
|
34670
35937
|
});
|
|
@@ -34674,20 +35941,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34674
35941
|
if (mobileChatBtn) {
|
|
34675
35942
|
mobileChatBtn.onclick = function () {
|
|
34676
35943
|
closeMobileLanding();
|
|
34677
|
-
var panel =
|
|
35944
|
+
var panel = _this14.shadowRoot.getElementById('text-chat-panel');
|
|
34678
35945
|
if (panel) {
|
|
34679
35946
|
panel.style.removeProperty('display');
|
|
34680
35947
|
panel.classList.add('open');
|
|
34681
|
-
|
|
35948
|
+
_this14.isOpen = true;
|
|
34682
35949
|
}
|
|
34683
35950
|
mobileFab.style.display = 'none';
|
|
34684
|
-
|
|
35951
|
+
_this14.showText();
|
|
34685
35952
|
};
|
|
34686
35953
|
}
|
|
34687
35954
|
|
|
34688
35955
|
// Close mobile landing on outside click
|
|
34689
35956
|
document.addEventListener('click', function (e) {
|
|
34690
|
-
if (!
|
|
35957
|
+
if (!_this14.isMobileLandingOpen) return;
|
|
34691
35958
|
var path = e.composedPath();
|
|
34692
35959
|
if (!path.includes(mobileLanding) && !path.includes(mobileFab)) {
|
|
34693
35960
|
closeMobileLanding();
|
|
@@ -34696,7 +35963,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34696
35963
|
|
|
34697
35964
|
// Close mobile landing on Escape
|
|
34698
35965
|
document.addEventListener('keydown', function (e) {
|
|
34699
|
-
if (e.key === 'Escape' &&
|
|
35966
|
+
if (e.key === 'Escape' && _this14.isMobileLandingOpen) {
|
|
34700
35967
|
closeMobileLanding();
|
|
34701
35968
|
}
|
|
34702
35969
|
});
|
|
@@ -34712,19 +35979,19 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34712
35979
|
_prevIsMobile = nowMobile;
|
|
34713
35980
|
if (nowMobile) {
|
|
34714
35981
|
// Switched desktop → mobile: close desktop panel so only mobile FAB shows
|
|
34715
|
-
if (
|
|
34716
|
-
var
|
|
34717
|
-
var panel = (
|
|
35982
|
+
if (_this14.isOpen) {
|
|
35983
|
+
var _this14$shadowRoot, _this14$shadowRoot2;
|
|
35984
|
+
var panel = (_this14$shadowRoot = _this14.shadowRoot) === null || _this14$shadowRoot === void 0 ? void 0 : _this14$shadowRoot.getElementById('text-chat-panel');
|
|
34718
35985
|
if (panel) {
|
|
34719
35986
|
panel.classList.remove('open');
|
|
34720
|
-
|
|
35987
|
+
_this14.isOpen = false;
|
|
34721
35988
|
}
|
|
34722
|
-
var pill = (
|
|
35989
|
+
var pill = (_this14$shadowRoot2 = _this14.shadowRoot) === null || _this14$shadowRoot2 === void 0 ? void 0 : _this14$shadowRoot2.getElementById('text-chat-button');
|
|
34723
35990
|
if (pill) pill.classList.remove('open');
|
|
34724
35991
|
}
|
|
34725
35992
|
} else {
|
|
34726
35993
|
// Switched mobile → desktop: close mobile landing/FAB so only desktop pill shows
|
|
34727
|
-
if (
|
|
35994
|
+
if (_this14.isMobileLandingOpen) {
|
|
34728
35995
|
closeMobileLanding();
|
|
34729
35996
|
}
|
|
34730
35997
|
// Ensure mobile FAB is reset to CSS-controlled state (media query hides it on desktop)
|
|
@@ -34736,10 +36003,10 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34736
36003
|
}, {
|
|
34737
36004
|
key: "setupKeyboardNavigation",
|
|
34738
36005
|
value: function setupKeyboardNavigation() {
|
|
34739
|
-
var
|
|
36006
|
+
var _this15 = this;
|
|
34740
36007
|
document.addEventListener('keydown', function (e) {
|
|
34741
|
-
if (e.key === 'Escape' &&
|
|
34742
|
-
|
|
36008
|
+
if (e.key === 'Escape' && _this15.isOpen) {
|
|
36009
|
+
_this15.togglePanel();
|
|
34743
36010
|
}
|
|
34744
36011
|
});
|
|
34745
36012
|
}
|
|
@@ -34750,7 +36017,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34750
36017
|
}, {
|
|
34751
36018
|
key: "setupPromptAnimation",
|
|
34752
36019
|
value: function setupPromptAnimation() {
|
|
34753
|
-
var
|
|
36020
|
+
var _this16 = this;
|
|
34754
36021
|
if (!this.shadowRoot) return;
|
|
34755
36022
|
var promptConfig = this.config.promptAnimation || {};
|
|
34756
36023
|
// Default to disabled if not specified (enabled === true means explicitly enabled)
|
|
@@ -34780,7 +36047,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34780
36047
|
// Auto-hide after configured seconds (only if widget is closed)
|
|
34781
36048
|
if (!this.isOpen && promptConfig.hideAfterSeconds !== null && promptConfig.hideAfterSeconds > 0) {
|
|
34782
36049
|
this.promptAutoHideTimer = setTimeout(function () {
|
|
34783
|
-
|
|
36050
|
+
_this16.hidePrompt();
|
|
34784
36051
|
}, promptConfig.hideAfterSeconds * 1000);
|
|
34785
36052
|
}
|
|
34786
36053
|
|
|
@@ -34792,7 +36059,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34792
36059
|
// Wrap the callback to also hide pulse rings
|
|
34793
36060
|
this.config.onConversationStart = function () {
|
|
34794
36061
|
// Hide pulse rings when call starts
|
|
34795
|
-
var pulseRings =
|
|
36062
|
+
var pulseRings = _this16.shadowRoot.getElementById('prompt-pulse-rings');
|
|
34796
36063
|
if (pulseRings) pulseRings.style.display = 'none';
|
|
34797
36064
|
|
|
34798
36065
|
// Call original callback if it exists
|
|
@@ -34804,7 +36071,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34804
36071
|
// Also listen to recordingStarted event from SDK if available
|
|
34805
36072
|
if (this.voiceInterface.sdk.voiceSDK) {
|
|
34806
36073
|
this.voiceInterface.sdk.voiceSDK.on('recordingStarted', function () {
|
|
34807
|
-
var pulseRings =
|
|
36074
|
+
var pulseRings = _this16.shadowRoot.getElementById('prompt-pulse-rings');
|
|
34808
36075
|
if (pulseRings) pulseRings.style.display = 'none';
|
|
34809
36076
|
});
|
|
34810
36077
|
}
|
|
@@ -34852,7 +36119,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34852
36119
|
}, {
|
|
34853
36120
|
key: "showPrompt",
|
|
34854
36121
|
value: function showPrompt() {
|
|
34855
|
-
var
|
|
36122
|
+
var _this17 = this;
|
|
34856
36123
|
if (!this.shadowRoot) return;
|
|
34857
36124
|
var promptConfig = this.config.promptAnimation || {};
|
|
34858
36125
|
// Default to enabled if not specified
|
|
@@ -34872,8 +36139,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34872
36139
|
// Function to actually show the elements
|
|
34873
36140
|
var doShow = function doShow() {
|
|
34874
36141
|
// Show prompt bubble (check both shadow root and document for compatibility)
|
|
34875
|
-
var promptBubble =
|
|
34876
|
-
if (!promptBubble &&
|
|
36142
|
+
var promptBubble = _this17.shadowRoot.getElementById('prompt-bubble');
|
|
36143
|
+
if (!promptBubble && _this17.shadowRoot !== document) {
|
|
34877
36144
|
promptBubble = document.getElementById('prompt-bubble');
|
|
34878
36145
|
}
|
|
34879
36146
|
if (promptBubble) {
|
|
@@ -34887,8 +36154,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34887
36154
|
|
|
34888
36155
|
// Show pulse rings if enabled
|
|
34889
36156
|
if (promptConfig.showPulseRings !== false) {
|
|
34890
|
-
var _pulseRings =
|
|
34891
|
-
if (!_pulseRings &&
|
|
36157
|
+
var _pulseRings = _this17.shadowRoot.getElementById('prompt-pulse-rings');
|
|
36158
|
+
if (!_pulseRings && _this17.shadowRoot !== document) {
|
|
34892
36159
|
_pulseRings = document.getElementById('prompt-pulse-rings');
|
|
34893
36160
|
}
|
|
34894
36161
|
if (_pulseRings) {
|
|
@@ -34925,7 +36192,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34925
36192
|
}
|
|
34926
36193
|
// Start new timer
|
|
34927
36194
|
this.promptAutoHideTimer = setTimeout(function () {
|
|
34928
|
-
|
|
36195
|
+
_this17.hidePrompt();
|
|
34929
36196
|
}, promptConfig.hideAfterSeconds * 1000);
|
|
34930
36197
|
}
|
|
34931
36198
|
}
|
|
@@ -34941,7 +36208,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34941
36208
|
}, {
|
|
34942
36209
|
key: "_doTogglePanel",
|
|
34943
36210
|
value: function _doTogglePanel() {
|
|
34944
|
-
var
|
|
36211
|
+
var _this18 = this;
|
|
34945
36212
|
if (!this.shadowRoot) return;
|
|
34946
36213
|
this.isOpen = !this.isOpen;
|
|
34947
36214
|
var panel = this.shadowRoot.getElementById('text-chat-panel');
|
|
@@ -34955,7 +36222,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34955
36222
|
if ((_this$config$position8 = this.config.position) !== null && _this$config$position8 !== void 0 && _this$config$position8.draggable) {
|
|
34956
36223
|
this._applyUnitOffset();
|
|
34957
36224
|
requestAnimationFrame(function () {
|
|
34958
|
-
return
|
|
36225
|
+
return _this18._reclampUnit();
|
|
34959
36226
|
});
|
|
34960
36227
|
}
|
|
34961
36228
|
}
|
|
@@ -34972,7 +36239,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34972
36239
|
// Panel is opening - hide prompt
|
|
34973
36240
|
this.hidePrompt();
|
|
34974
36241
|
setTimeout(function () {
|
|
34975
|
-
var input =
|
|
36242
|
+
var input = _this18.shadowRoot.getElementById('messageInput');
|
|
34976
36243
|
if (input) input.focus();
|
|
34977
36244
|
}, 100);
|
|
34978
36245
|
} else {
|
|
@@ -34984,13 +36251,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34984
36251
|
// Panel is closing - show prompt (if enabled)
|
|
34985
36252
|
this.showPrompt();
|
|
34986
36253
|
setTimeout(function () {
|
|
34987
|
-
var
|
|
34988
|
-
var promptBubble =
|
|
36254
|
+
var _this18$config$prompt;
|
|
36255
|
+
var promptBubble = _this18.shadowRoot.getElementById('prompt-bubble');
|
|
34989
36256
|
if (promptBubble && promptBubble.style.display === 'none') {
|
|
34990
36257
|
promptBubble.style.display = 'block';
|
|
34991
36258
|
}
|
|
34992
|
-
var pulseRings =
|
|
34993
|
-
if (pulseRings && ((
|
|
36259
|
+
var pulseRings = _this18.shadowRoot.getElementById('prompt-pulse-rings');
|
|
36260
|
+
if (pulseRings && ((_this18$config$prompt = _this18.config.promptAnimation) === null || _this18$config$prompt === void 0 ? void 0 : _this18$config$prompt.showPulseRings) !== false) {
|
|
34994
36261
|
if (pulseRings.style.display === 'none') {
|
|
34995
36262
|
pulseRings.style.display = 'block';
|
|
34996
36263
|
}
|
|
@@ -35182,8 +36449,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35182
36449
|
}, {
|
|
35183
36450
|
key: "showBackButtonWarning",
|
|
35184
36451
|
value: function showBackButtonWarning() {
|
|
35185
|
-
var _this$
|
|
35186
|
-
if (!((_this$
|
|
36452
|
+
var _this$voiceInterface7, _this$voiceInterface$;
|
|
36453
|
+
if (!((_this$voiceInterface7 = this.voiceInterface) !== null && _this$voiceInterface7 !== void 0 && _this$voiceInterface7.isActive)) return;
|
|
35187
36454
|
|
|
35188
36455
|
// Show warning message in the voice interface
|
|
35189
36456
|
if ((_this$voiceInterface$ = this.voiceInterface.desktop) !== null && _this$voiceInterface$ !== void 0 && _this$voiceInterface$.showBackButtonWarning) {
|
|
@@ -35258,13 +36525,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35258
36525
|
value: function updateConfig(newConfig) {
|
|
35259
36526
|
var _this$config3,
|
|
35260
36527
|
_this$config4,
|
|
35261
|
-
_this$config$
|
|
36528
|
+
_this$config$flavor3,
|
|
35262
36529
|
_this$config$voice8,
|
|
35263
36530
|
_this$config$voice9,
|
|
35264
36531
|
_this$config$voice0,
|
|
35265
36532
|
_this$config$voice1,
|
|
35266
36533
|
_this$config$voice10,
|
|
35267
|
-
|
|
36534
|
+
_this19 = this;
|
|
35268
36535
|
// Deep merge nested objects
|
|
35269
36536
|
var mergedConfig = _objectSpread({}, this.config);
|
|
35270
36537
|
|
|
@@ -35462,7 +36729,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35462
36729
|
// Recreate interfaces with new config (after mergeWithDefaults, so language is current)
|
|
35463
36730
|
// Ensure language is correctly passed - use the merged config value
|
|
35464
36731
|
var currentLanguage = this.config.language || 'en';
|
|
35465
|
-
var desktopMinimizedEcommerceStripUi = typeof window !== 'undefined' && window.innerWidth > 768 && ((_this$config$
|
|
36732
|
+
var desktopMinimizedEcommerceStripUi = typeof window !== 'undefined' && window.innerWidth > 768 && ((_this$config$flavor3 = this.config.flavor) === null || _this$config$flavor3 === void 0 ? void 0 : _this$config$flavor3.callView) === 'minimized';
|
|
35466
36733
|
var voiceConfig = _objectSpread(_objectSpread(_objectSpread({}, this.config), this.config.voice), {}, {
|
|
35467
36734
|
agentName: this.config.agentName,
|
|
35468
36735
|
language: currentLanguage,
|
|
@@ -35482,20 +36749,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35482
36749
|
outputBitDepth: ((_this$config$voice10 = this.config.voice) === null || _this$config$voice10 === void 0 ? void 0 : _this$config$voice10.outputBitDepth) || 16,
|
|
35483
36750
|
desktopMinimizedEcommerceStripUi: desktopMinimizedEcommerceStripUi,
|
|
35484
36751
|
onDesktopMinimizedStripCallStart: desktopMinimizedEcommerceStripUi ? function () {
|
|
35485
|
-
var
|
|
35486
|
-
(
|
|
35487
|
-
if (
|
|
35488
|
-
|
|
35489
|
-
|
|
36752
|
+
var _this19$_ecommerceVoi;
|
|
36753
|
+
(_this19$_ecommerceVoi = _this19._ecommerceVoiceStrip) === null || _this19$_ecommerceVoi === void 0 || _this19$_ecommerceVoi.show();
|
|
36754
|
+
if (_this19.isOpen) _this19.minimize();
|
|
36755
|
+
_this19._setPanelFooterVisible(false);
|
|
36756
|
+
_this19._setEcommerceStripLauncherVisible(false);
|
|
35490
36757
|
} : undefined,
|
|
35491
36758
|
onDesktopMinimizedStripLauncherRestore: desktopMinimizedEcommerceStripUi ? function () {
|
|
35492
|
-
return
|
|
36759
|
+
return _this19._restoreDesktopEcommerceStripChrome();
|
|
35493
36760
|
} : undefined,
|
|
35494
36761
|
// Pass event callbacks to voice interface (forward only; panel is not auto-minimized on call start)
|
|
35495
36762
|
onConversationStart: function onConversationStart() {
|
|
35496
|
-
if (typeof
|
|
35497
|
-
var
|
|
35498
|
-
(
|
|
36763
|
+
if (typeof _this19.config.onConversationStart === 'function') {
|
|
36764
|
+
var _this19$config;
|
|
36765
|
+
(_this19$config = _this19.config).onConversationStart.apply(_this19$config, arguments);
|
|
35499
36766
|
}
|
|
35500
36767
|
},
|
|
35501
36768
|
onConversationEnd: this.config.onConversationEnd,
|
|
@@ -35504,48 +36771,48 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35504
36771
|
onAudioStoppedPlaying: this.config.onAudioStoppedPlaying,
|
|
35505
36772
|
onSubtitleDisplay: this.config.onSubtitleDisplay,
|
|
35506
36773
|
onCallEnd: function onCallEnd() {
|
|
35507
|
-
var
|
|
35508
|
-
if (
|
|
35509
|
-
var widgetMode = ((
|
|
36774
|
+
var _this19$config$behavi;
|
|
36775
|
+
if (_this19._isDomainErrorVisible()) return;
|
|
36776
|
+
var widgetMode = ((_this19$config$behavi = _this19.config.behavior) === null || _this19$config$behavi === void 0 ? void 0 : _this19$config$behavi.mode) || 'unified';
|
|
35510
36777
|
if (widgetMode === 'unified') {
|
|
35511
36778
|
if (window.innerWidth <= 768) {
|
|
35512
|
-
var
|
|
35513
|
-
var panel = (
|
|
36779
|
+
var _this19$shadowRoot, _this19$shadowRoot2;
|
|
36780
|
+
var panel = (_this19$shadowRoot = _this19.shadowRoot) === null || _this19$shadowRoot === void 0 ? void 0 : _this19$shadowRoot.getElementById('text-chat-panel');
|
|
35514
36781
|
if (panel) {
|
|
35515
36782
|
panel.classList.remove('open');
|
|
35516
|
-
|
|
36783
|
+
_this19.isOpen = false;
|
|
35517
36784
|
}
|
|
35518
|
-
var fab = (
|
|
36785
|
+
var fab = (_this19$shadowRoot2 = _this19.shadowRoot) === null || _this19$shadowRoot2 === void 0 ? void 0 : _this19$shadowRoot2.querySelector('.ttp-mobile-fab');
|
|
35519
36786
|
if (fab) fab.style.display = '';
|
|
35520
36787
|
}
|
|
35521
|
-
|
|
36788
|
+
_this19.showLanding();
|
|
35522
36789
|
}
|
|
35523
36790
|
},
|
|
35524
36791
|
onShowVoice: function onShowVoice() {
|
|
35525
|
-
|
|
36792
|
+
_this19.showVoice();
|
|
35526
36793
|
},
|
|
35527
36794
|
onShowLanding: function onShowLanding() {
|
|
35528
|
-
|
|
36795
|
+
_this19.showLanding();
|
|
35529
36796
|
},
|
|
35530
36797
|
onDisclaimerDeclined: function onDisclaimerDeclined() {
|
|
35531
|
-
var
|
|
35532
|
-
if (
|
|
35533
|
-
var widgetMode = ((
|
|
36798
|
+
var _this19$config$behavi2;
|
|
36799
|
+
if (_this19._isDomainErrorVisible()) return;
|
|
36800
|
+
var widgetMode = ((_this19$config$behavi2 = _this19.config.behavior) === null || _this19$config$behavi2 === void 0 ? void 0 : _this19$config$behavi2.mode) || 'unified';
|
|
35534
36801
|
if (widgetMode === 'voice-only') {
|
|
35535
|
-
|
|
36802
|
+
_this19.showVoice();
|
|
35536
36803
|
return;
|
|
35537
36804
|
}
|
|
35538
36805
|
if (widgetMode !== 'unified') return;
|
|
35539
36806
|
if (window.innerWidth <= 768) {
|
|
35540
|
-
var
|
|
35541
|
-
var panel = (
|
|
36807
|
+
var _this19$shadowRoot3;
|
|
36808
|
+
var panel = (_this19$shadowRoot3 = _this19.shadowRoot) === null || _this19$shadowRoot3 === void 0 ? void 0 : _this19$shadowRoot3.getElementById('text-chat-panel');
|
|
35542
36809
|
if (panel) {
|
|
35543
36810
|
panel.classList.remove('open');
|
|
35544
|
-
|
|
36811
|
+
_this19.isOpen = false;
|
|
35545
36812
|
}
|
|
35546
|
-
|
|
36813
|
+
_this19._openMobileCallTextLanding();
|
|
35547
36814
|
} else {
|
|
35548
|
-
|
|
36815
|
+
_this19.showLanding();
|
|
35549
36816
|
}
|
|
35550
36817
|
},
|
|
35551
36818
|
direction: this.getEffectiveTextDirection()
|
|
@@ -35592,9 +36859,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35592
36859
|
}, {
|
|
35593
36860
|
key: "_initEcommerceVoiceStrip",
|
|
35594
36861
|
value: function _initEcommerceVoiceStrip() {
|
|
35595
|
-
var
|
|
36862
|
+
var _this20 = this,
|
|
35596
36863
|
_this$config$position9,
|
|
35597
|
-
_this$
|
|
36864
|
+
_this$voiceInterface8;
|
|
35598
36865
|
var flavor = this.config.flavor && _typeof(this.config.flavor) === 'object' ? this.config.flavor : null;
|
|
35599
36866
|
if (window.innerWidth <= 768) return;
|
|
35600
36867
|
if (!flavor || flavor.callView !== 'minimized') return;
|
|
@@ -35615,34 +36882,44 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35615
36882
|
endCallButtonColor: v.endCallButtonColor || '#ef4444'
|
|
35616
36883
|
},
|
|
35617
36884
|
getVoiceUiState: function getVoiceUiState() {
|
|
35618
|
-
var
|
|
36885
|
+
var _this20$voiceInterfac, _this20$voiceInterfac2, _this20$voiceInterfac3;
|
|
35619
36886
|
return {
|
|
35620
|
-
isMicMuted: !!((
|
|
35621
|
-
isPaused: !!((
|
|
35622
|
-
isSpeakerMuted: !!((
|
|
36887
|
+
isMicMuted: !!((_this20$voiceInterfac = _this20.voiceInterface) !== null && _this20$voiceInterfac !== void 0 && _this20$voiceInterfac.isMicMuted),
|
|
36888
|
+
isPaused: !!((_this20$voiceInterfac2 = _this20.voiceInterface) !== null && _this20$voiceInterfac2 !== void 0 && _this20$voiceInterfac2.isPaused),
|
|
36889
|
+
isSpeakerMuted: !!((_this20$voiceInterfac3 = _this20.voiceInterface) !== null && _this20$voiceInterfac3 !== void 0 && _this20$voiceInterfac3.isSpeakerMuted)
|
|
35623
36890
|
};
|
|
35624
36891
|
},
|
|
35625
36892
|
onAbout: function onAbout() {
|
|
35626
|
-
return
|
|
36893
|
+
return _this20._openAboutModal();
|
|
36894
|
+
},
|
|
36895
|
+
onSettings: function onSettings() {
|
|
36896
|
+
return _this20._openCallSettingsModal();
|
|
36897
|
+
},
|
|
36898
|
+
onRecipeSelect: function onRecipeSelect(recipe) {
|
|
36899
|
+
var _this20$_flavor, _this20$_flavor$_getR, _this20$_flavor$_getR2;
|
|
36900
|
+
(_this20$_flavor = _this20._flavor) === null || _this20$_flavor === void 0 || (_this20$_flavor$_getR = _this20$_flavor._getRecipeHandler) === null || _this20$_flavor$_getR === void 0 || (_this20$_flavor$_getR = _this20$_flavor$_getR.call(_this20$_flavor)) === null || _this20$_flavor$_getR === void 0 || (_this20$_flavor$_getR2 = _this20$_flavor$_getR.handleShowRecipe) === null || _this20$_flavor$_getR2 === void 0 || _this20$_flavor$_getR2.call(_this20$_flavor$_getR, {
|
|
36901
|
+
recipe: recipe,
|
|
36902
|
+
reshow: true
|
|
36903
|
+
});
|
|
35627
36904
|
},
|
|
35628
36905
|
onHangup: function onHangup() {
|
|
35629
|
-
if (
|
|
36906
|
+
if (_this20.voiceInterface) _this20.voiceInterface.endVoiceCall();
|
|
35630
36907
|
},
|
|
35631
36908
|
onToggleMute: function onToggleMute() {
|
|
35632
|
-
if (
|
|
36909
|
+
if (_this20.voiceInterface) _this20.voiceInterface.toggleMute();
|
|
35633
36910
|
strip.syncFromVoice();
|
|
35634
36911
|
},
|
|
35635
36912
|
onTogglePause: function onTogglePause() {
|
|
35636
|
-
if (
|
|
36913
|
+
if (_this20.voiceInterface) _this20.voiceInterface.togglePause();
|
|
35637
36914
|
strip.syncFromVoice();
|
|
35638
36915
|
},
|
|
35639
36916
|
onToggleSpeaker: function onToggleSpeaker() {
|
|
35640
|
-
if (
|
|
36917
|
+
if (_this20.voiceInterface) _this20.voiceInterface.toggleSpeaker();
|
|
35641
36918
|
strip.syncFromVoice();
|
|
35642
36919
|
},
|
|
35643
36920
|
onSendText: function onSendText(text) {
|
|
35644
|
-
var
|
|
35645
|
-
var voiceSDK = (
|
|
36921
|
+
var _this20$voiceInterfac4;
|
|
36922
|
+
var voiceSDK = (_this20$voiceInterfac4 = _this20.voiceInterface) === null || _this20$voiceInterfac4 === void 0 || (_this20$voiceInterfac4 = _this20$voiceInterfac4.sdk) === null || _this20$voiceInterfac4 === void 0 ? void 0 : _this20$voiceInterfac4.voiceSDK;
|
|
35646
36923
|
if (voiceSDK && typeof voiceSDK.sendMessage === 'function') {
|
|
35647
36924
|
voiceSDK.sendMessage({
|
|
35648
36925
|
t: 'text_inject',
|
|
@@ -35652,6 +36929,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35652
36929
|
}
|
|
35653
36930
|
});
|
|
35654
36931
|
this._ecommerceVoiceStrip = strip;
|
|
36932
|
+
strip.bindRecipeStore(this.getRecipeStore());
|
|
35655
36933
|
|
|
35656
36934
|
// Make the strip draggable too when position.draggable is enabled.
|
|
35657
36935
|
if ((_this$config$position9 = this.config.position) !== null && _this$config$position9 !== void 0 && _this$config$position9.draggable) {
|
|
@@ -35659,7 +36937,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35659
36937
|
}
|
|
35660
36938
|
|
|
35661
36939
|
// Show strip when conversation starts
|
|
35662
|
-
var agentSDK = (_this$
|
|
36940
|
+
var agentSDK = (_this$voiceInterface8 = this.voiceInterface) === null || _this$voiceInterface8 === void 0 ? void 0 : _this$voiceInterface8.sdk;
|
|
35663
36941
|
if (agentSDK) {
|
|
35664
36942
|
var origConvStart = agentSDK.onConversationStart;
|
|
35665
36943
|
agentSDK.onConversationStart = function () {
|
|
@@ -35697,7 +36975,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35697
36975
|
var _this$voiceInterface$2;
|
|
35698
36976
|
var origOnCallEnd = this.voiceInterface.config.onCallEnd;
|
|
35699
36977
|
this.voiceInterface.config.onCallEnd = function () {
|
|
35700
|
-
|
|
36978
|
+
_this20._restoreDesktopEcommerceStripChrome();
|
|
35701
36979
|
if (typeof origOnCallEnd === 'function') origOnCallEnd();
|
|
35702
36980
|
};
|
|
35703
36981
|
|
|
@@ -35821,7 +37099,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35821
37099
|
key: "injectData",
|
|
35822
37100
|
value: (function () {
|
|
35823
37101
|
var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
|
|
35824
|
-
var _this$
|
|
37102
|
+
var _this$voiceInterface9;
|
|
35825
37103
|
var options,
|
|
35826
37104
|
voiceSDK,
|
|
35827
37105
|
ack,
|
|
@@ -35846,7 +37124,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35846
37124
|
throw new Error('Voice call is not active');
|
|
35847
37125
|
case 2:
|
|
35848
37126
|
// Check if SDK is available
|
|
35849
|
-
voiceSDK = (_this$
|
|
37127
|
+
voiceSDK = (_this$voiceInterface9 = this.voiceInterface) === null || _this$voiceInterface9 === void 0 ? void 0 : _this$voiceInterface9.getVoiceSDK();
|
|
35850
37128
|
if (voiceSDK) {
|
|
35851
37129
|
_context6.n = 3;
|
|
35852
37130
|
break;
|
|
@@ -36880,7 +38158,9 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
36880
38158
|
flavor: config.flavor,
|
|
36881
38159
|
// Shared client-tool handler map from TTPChatWidget (so the same handler
|
|
36882
38160
|
// map serves both voice and text channels).
|
|
36883
|
-
sharedToolHandlers: config.sharedToolHandlers
|
|
38161
|
+
sharedToolHandlers: config.sharedToolHandlers,
|
|
38162
|
+
// Persisted in-call settings provider (voice speed / response length).
|
|
38163
|
+
callSettingsProvider: config.callSettingsProvider
|
|
36884
38164
|
});
|
|
36885
38165
|
|
|
36886
38166
|
// Initialize modules with context (delegation pattern)
|
|
@@ -41256,6 +42536,22 @@ var Templates = /*#__PURE__*/function () {
|
|
|
41256
42536
|
return "<button type=\"button\" class=\"".concat(cls, "\" aria-label=\"").concat(escapeHtmlAttr(label), "\" title=\"").concat(escapeHtmlAttr(label), "\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"9\"/>\n <line x1=\"12\" y1=\"11\" x2=\"12\" y2=\"16\"/>\n <circle cx=\"12\" cy=\"7.7\" r=\"1.05\" fill=\"currentColor\" stroke=\"none\"/>\n </svg>\n </button>");
|
|
41257
42537
|
}
|
|
41258
42538
|
|
|
42539
|
+
/**
|
|
42540
|
+
* Shared in-call settings gear button markup. Opens the call-settings dialog
|
|
42541
|
+
* (voice speed / response length sliders) wired by TTPChatWidget. Shares the
|
|
42542
|
+
* .ttp-info-btn styling class; .ttp-settings-btn is the wiring discriminator.
|
|
42543
|
+
* @param {string} [extraClass] - extra class(es) for positioning per view
|
|
42544
|
+
* @returns {string}
|
|
42545
|
+
*/
|
|
42546
|
+
}, {
|
|
42547
|
+
key: "settingsButton",
|
|
42548
|
+
value: function settingsButton() {
|
|
42549
|
+
var extraClass = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
|
|
42550
|
+
var cls = extraClass ? "ttp-info-btn ttp-settings-btn ".concat(extraClass) : 'ttp-info-btn ttp-settings-btn';
|
|
42551
|
+
var label = this.t('settingsTitle') || 'Call settings';
|
|
42552
|
+
return "<button type=\"button\" class=\"".concat(cls, "\" aria-label=\"").concat(escapeHtmlAttr(label), "\" title=\"").concat(escapeHtmlAttr(label), "\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <circle cx=\"12\" cy=\"12\" r=\"3\"/>\n <path d=\"M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h.01a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h.01a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v.01a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z\"/>\n </svg>\n </button>");
|
|
42553
|
+
}
|
|
42554
|
+
|
|
41259
42555
|
/**
|
|
41260
42556
|
* Generate HTML for voice interface.
|
|
41261
42557
|
* Automatically detects mobile vs desktop based on voiceInterface.isMobile
|
|
@@ -41286,7 +42582,7 @@ var Templates = /*#__PURE__*/function () {
|
|
|
41286
42582
|
var transcriptPlaceholder = this.t('transcriptWillAppear') || '';
|
|
41287
42583
|
var transcriptDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForTranscriptSnippet)(transcriptPlaceholder, this.config);
|
|
41288
42584
|
var voiceInputDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForAssistantStreamingText)(this.config);
|
|
41289
|
-
return "<div class=\"voice-interface\" id=\"voiceInterface\">\n <!-- Idle View -->\n <div id=\"voiceIdleState\">\n <div class=\"ttp-hero\">\n <div class=\"ttp-header\">\n <div class=\"ttp-agent\">\n <div class=\"ttp-avatar-wrap\">\n <div class=\"".concat(idleAvatarClass, "\">").concat(idleAvatarInner, "</div>\n <div class=\"ttp-online-dot\"></div>\n </div>\n <div>\n <div class=\"ttp-agent-name\">").concat(agentName, "</div>\n <div class=\"ttp-agent-role\">").concat(agentRole, "</div>\n </div>\n </div>\n <div class=\"ttp-header-actions\">\n ").concat(this.infoButton(), "\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseIdle\" aria-label=\"Close widget\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n </div>\n <div class=\"ttp-headline\">").concat(headline, "</div>\n <div class=\"ttp-subline\">").concat(subline, "</div>\n </div>\n\n <div class=\"ttp-body\">\n <button type=\"button\" class=\"ttp-btn-primary\" id=\"startCallBtn\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"").concat(this.config.startCallButtonTextColor || 'white', "\" stroke-width=\"2\">\n <path d=\"M12 2a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V5a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2M12 19v3M8 22h8\"/>\n </svg>\n ").concat(this.getText('startCallButtonText', 'startCall') || 'Start Voice Call', "\n </button>\n ").concat((((_this$config$behavior = this.config.behavior) === null || _this$config$behavior === void 0 ? void 0 : _this$config$behavior.mode) || 'unified') !== 'voice-only' ? "\n <button type=\"button\" class=\"ttp-btn-secondary\" id=\"startTextBtn\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n ".concat(this.config.sendMessageText || this.getText('sendMessageText', 'sendMessage') || 'Send a Message', "\n </button>\n ") : '', "\n ").concat((_this$config$whatsapp = this.config.whatsapp) !== null && _this$config$whatsapp !== void 0 && _this$config$whatsapp.number ? "\n <a class=\"ttp-btn-wa\" id=\"ttpWhatsAppBtn\"\n href=\"https://wa.me/".concat(this.config.whatsapp.number).concat(this.config.whatsapp.text ? '?text=' + encodeURIComponent(this.config.whatsapp.text) : '', "\"\n target=\"_blank\" rel=\"noopener\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"#25d366\">\n <path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.655-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z\"/>\n </svg>\n WhatsApp\n </a>\n ") : '', "\n </div>\n </div>\n\n <!-- Active Call View -->\n <div id=\"voiceActiveState\" style=\"display: none;\">\n <!-- Full voice section (hidden when items/rooms are shown) -->\n <div class=\"desktop-voice-section\" id=\"desktopVoiceSection\">\n <div class=\"ttp-call-hero\">\n <div class=\"ttp-call-topbar\">\n <div class=\"ttp-rec\">\n <div class=\"ttp-rec-dot\"></div>\n <span class=\"ttp-timer\" id=\"desktopTimerText\">00:00</span>\n </div>\n <span class=\"ttp-call-label\">Voice call active</span>\n <div class=\"ttp-header-actions\">\n ").concat(this.infoButton(), "\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseActive\" aria-label=\"Close widget\">\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"ttp-orb-wrap\">\n <div class=\"ttp-orb-rings\">\n <div class=\"ttp-ring ttp-ring-1\"></div>\n <div class=\"ttp-ring ttp-ring-2\"></div>\n <div class=\"ttp-orb\" id=\"desktopMainWaveform\">\n <div class=\"ttp-wave\" id=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"ttp-listen-label\" id=\"desktopStatusText\">").concat(this.t('listening') || 'Listening to you...', "</div>\n </div>\n </div>\n\n <div class=\"ttp-controls\">\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopMuteBtn\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopPauseBtn\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopSpeakerBtn\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-end-btn\" id=\"desktopEndCallBtn\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Compact voice section (shown when items/rooms are visible) -->\n <div class=\"compact-voice-section\" id=\"compactVoiceSection\" style=\"display: none;\">\n <div class=\"compact-left\">\n <div class=\"compact-avatar\" id=\"desktopAvatarCompact\">\n <div class=\"ttp-orb compact-orb\" id=\"desktopMainWaveformCompact\">\n <div class=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"compact-info\">\n <div class=\"compact-timer\" id=\"desktopTimerCompact\">\n <span class=\"ttp-rec-dot\"></span>\n <span id=\"compactTimerText\">00:00</span>\n </div>\n <div class=\"compact-status\" id=\"desktopStatusCompact\">\n <span id=\"compactStatusText\">").concat(this.t('listening') || 'Listening...', "</span>\n </div>\n </div>\n </div>\n <div class=\"compact-controls\">\n ").concat(this.infoButton('ttp-info-btn--onctrl'), "\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopMuteBtnCompact\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopPauseBtnCompact\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopSpeakerBtnCompact\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn danger\" id=\"desktopEndCallBtnCompact\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" style=\"overflow: visible;\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" transform=\"rotate(135 12 12)\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Transcript -->\n <div class=\"ttp-transcript desktop-conversation-panel\" id=\"desktopConversationPanel\" dir=\"").concat(textDir, "\">\n <div class=\"ttp-transcript-hdr\" id=\"conversationHeader\">\n <span class=\"ttp-live-label\">Live</span>\n <span class=\"ttp-toggle-text\" id=\"conversationToggleText\">Show history</span>\n <div class=\"ttp-dots\">\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n </div>\n </div>\n <div class=\"live-transcript-collapsed\" id=\"liveTranscriptCollapsed\">\n <div class=\"ttp-transcript-text\" id=\"liveTextCollapsed\" dir=\"").concat(transcriptDir, "\">\n ").concat(this.t('transcriptWillAppear') || 'Transcript will appear here...', "<span class=\"ttp-cursor\"></span>\n </div>\n </div>\n <div class=\"conversation-history\" id=\"conversationHistory\">\n <div class=\"conversation-messages\" id=\"conversationMessages\"></div>\n <div class=\"live-message-row\" id=\"liveMessageRow\" style=\"display: none;\">\n <div class=\"message-bubble\" dir=\"").concat(transcriptDir, "\">\n <span class=\"live-badge\">Live</span>\n <span id=\"liveMessageText\"></span><span class=\"ttp-cursor\"></span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Type row -->\n <div class=\"ttp-type-row voice-text-input-area\">\n <input class=\"ttp-input\" type=\"text\" id=\"voiceTextInput\" dir=\"").concat(voiceInputDir, "\" placeholder=\"").concat(this.getText('inputPlaceholder', 'typeMessage') || 'Or type here…', "\" aria-label=\"Type a message\" />\n <button type=\"button\" class=\"ttp-send-btn\" id=\"voiceSendBtn\" aria-label=\"Send message\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>");
|
|
42585
|
+
return "<div class=\"voice-interface\" id=\"voiceInterface\">\n <!-- Idle View -->\n <div id=\"voiceIdleState\">\n <div class=\"ttp-hero\">\n <div class=\"ttp-header\">\n <div class=\"ttp-agent\">\n <div class=\"ttp-avatar-wrap\">\n <div class=\"".concat(idleAvatarClass, "\">").concat(idleAvatarInner, "</div>\n <div class=\"ttp-online-dot\"></div>\n </div>\n <div>\n <div class=\"ttp-agent-name\">").concat(agentName, "</div>\n <div class=\"ttp-agent-role\">").concat(agentRole, "</div>\n </div>\n </div>\n <div class=\"ttp-header-actions\">\n ").concat(this.infoButton(), "\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseIdle\" aria-label=\"Close widget\">\n <svg width=\"10\" height=\"10\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n </div>\n <div class=\"ttp-headline\">").concat(headline, "</div>\n <div class=\"ttp-subline\">").concat(subline, "</div>\n </div>\n\n <div class=\"ttp-body\">\n <button type=\"button\" class=\"ttp-btn-primary\" id=\"startCallBtn\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"").concat(this.config.startCallButtonTextColor || 'white', "\" stroke-width=\"2\">\n <path d=\"M12 2a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V5a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2M12 19v3M8 22h8\"/>\n </svg>\n ").concat(this.getText('startCallButtonText', 'startCall') || 'Start Voice Call', "\n </button>\n ").concat((((_this$config$behavior = this.config.behavior) === null || _this$config$behavior === void 0 ? void 0 : _this$config$behavior.mode) || 'unified') !== 'voice-only' ? "\n <button type=\"button\" class=\"ttp-btn-secondary\" id=\"startTextBtn\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z\"/>\n </svg>\n ".concat(this.config.sendMessageText || this.getText('sendMessageText', 'sendMessage') || 'Send a Message', "\n </button>\n ") : '', "\n ").concat((_this$config$whatsapp = this.config.whatsapp) !== null && _this$config$whatsapp !== void 0 && _this$config$whatsapp.number ? "\n <a class=\"ttp-btn-wa\" id=\"ttpWhatsAppBtn\"\n href=\"https://wa.me/".concat(this.config.whatsapp.number).concat(this.config.whatsapp.text ? '?text=' + encodeURIComponent(this.config.whatsapp.text) : '', "\"\n target=\"_blank\" rel=\"noopener\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"#25d366\">\n <path d=\"M17.472 14.382c-.297-.149-1.758-.867-2.03-.967-.273-.099-.471-.148-.67.15-.197.297-.767.966-.94 1.164-.173.199-.347.223-.644.075-.297-.15-1.255-.463-2.39-1.475-.883-.788-1.48-1.761-1.655-2.059-.173-.297-.018-.458.13-.606.134-.133.298-.347.446-.52.149-.174.198-.298.298-.497.099-.198.05-.371-.025-.52-.075-.149-.669-1.612-.916-2.207-.242-.579-.487-.5-.669-.51-.173-.008-.371-.01-.57-.01-.198 0-.52.074-.792.372-.272.297-1.04 1.016-1.04 2.479 0 1.462 1.065 2.875 1.213 3.074.149.198 2.096 3.2 5.077 4.487.709.306 1.262.489 1.694.625.712.227 1.36.195 1.871.118.571-.085 1.758-.719 2.006-1.413.248-.694.248-1.289.173-1.413-.074-.124-.272-.198-.57-.347m-5.421 7.403h-.004a9.87 9.87 0 01-5.031-1.378l-.361-.214-3.741.982.998-3.648-.235-.374a9.86 9.86 0 01-1.51-5.26c.001-5.45 4.436-9.884 9.888-9.884 2.64 0 5.122 1.03 6.988 2.898a9.825 9.825 0 012.893 6.994c-.003 5.45-4.437 9.884-9.885 9.884m8.413-18.297A11.815 11.815 0 0012.05 0C5.495 0 .16 5.335.157 11.892c0 2.096.547 4.142 1.588 5.945L.057 24l6.305-1.654a11.882 11.882 0 005.683 1.448h.005c6.554 0 11.89-5.335 11.893-11.893a11.821 11.821 0 00-3.48-8.413z\"/>\n </svg>\n WhatsApp\n </a>\n ") : '', "\n </div>\n </div>\n\n <!-- Active Call View -->\n <div id=\"voiceActiveState\" style=\"display: none;\">\n <!-- Full voice section (hidden when items/rooms are shown) -->\n <div class=\"desktop-voice-section\" id=\"desktopVoiceSection\">\n <div class=\"ttp-call-hero\">\n <div class=\"ttp-call-topbar\">\n <div class=\"ttp-rec\">\n <div class=\"ttp-rec-dot\"></div>\n <span class=\"ttp-timer\" id=\"desktopTimerText\">00:00</span>\n </div>\n <span class=\"ttp-call-label\">Voice call active</span>\n <div class=\"ttp-header-actions\">\n ").concat(this.settingsButton(), "\n ").concat(this.infoButton(), "\n <button type=\"button\" class=\"ttp-close-btn\" id=\"ttpCloseActive\" aria-label=\"Close widget\">\n <svg width=\"9\" height=\"9\" viewBox=\"0 0 12 12\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M10 2L2 10M2 2l8 8\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <div class=\"ttp-orb-wrap\">\n <div class=\"ttp-orb-rings\">\n <div class=\"ttp-ring ttp-ring-1\"></div>\n <div class=\"ttp-ring ttp-ring-2\"></div>\n <div class=\"ttp-orb\" id=\"desktopMainWaveform\">\n <div class=\"ttp-wave\" id=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"ttp-listen-label\" id=\"desktopStatusText\">").concat(this.t('listening') || 'Listening to you...', "</div>\n </div>\n </div>\n\n <div class=\"ttp-controls\">\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopMuteBtn\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopPauseBtn\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-ctrl-btn\" id=\"desktopSpeakerBtn\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"ttp-end-btn\" id=\"desktopEndCallBtn\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Compact voice section (shown when items/rooms are visible) -->\n <div class=\"compact-voice-section\" id=\"compactVoiceSection\" style=\"display: none;\">\n <div class=\"compact-left\">\n <div class=\"compact-avatar\" id=\"desktopAvatarCompact\">\n <div class=\"ttp-orb compact-orb\" id=\"desktopMainWaveformCompact\">\n <div class=\"ttp-wave\"></div>\n </div>\n </div>\n <div class=\"compact-info\">\n <div class=\"compact-timer\" id=\"desktopTimerCompact\">\n <span class=\"ttp-rec-dot\"></span>\n <span id=\"compactTimerText\">00:00</span>\n </div>\n <div class=\"compact-status\" id=\"desktopStatusCompact\">\n <span id=\"compactStatusText\">").concat(this.t('listening') || 'Listening...', "</span>\n </div>\n </div>\n </div>\n <div class=\"compact-controls\">\n ").concat(this.settingsButton('ttp-info-btn--onctrl'), "\n ").concat(this.infoButton('ttp-info-btn--onctrl'), "\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopMuteBtnCompact\" title=\"").concat(this.getTooltip('mute'), "\" aria-label=\"Mute microphone\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-mic-icon\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-mic-off-icon\" style=\"display: none; position: absolute;\">\n <path d=\"M12 1a3 3 0 0 1 3 3v7a3 3 0 0 1-6 0V4a3 3 0 0 1 3-3z\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopPauseBtnCompact\" title=\"Pause call\" aria-label=\"Pause call\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" class=\"desktop-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"currentColor\" stroke=\"none\" class=\"desktop-play-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn secondary\" id=\"desktopSpeakerBtnCompact\" title=\"").concat(this.getTooltip('speaker'), "\" aria-label=\"Toggle speaker\">\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"1.8\" class=\"desktop-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 24 24\" fill=\"none\" class=\"desktop-speaker-off-icon\" style=\"display: none; position: absolute;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\" stroke=\"currentColor\" stroke-width=\"1.8\" fill=\"none\"/>\n <line x1=\"5\" y1=\"5\" x2=\"19\" y2=\"19\" stroke=\"#ef4444\" stroke-width=\"1.5\" stroke-linecap=\"round\" opacity=\"0.85\"/>\n </svg>\n </button>\n <button type=\"button\" class=\"compact-control-btn danger\" id=\"desktopEndCallBtnCompact\" title=\"").concat(this.getTooltip('endCall'), "\" aria-label=\"End call\">\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" style=\"overflow: visible;\">\n <path d=\"M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07A19.5 19.5 0 0 1 4.99 12 19.79 19.79 0 0 1 1.97 3.4 2 2 0 0 1 3.95 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z\" transform=\"rotate(135 12 12)\"/>\n </svg>\n </button>\n </div>\n </div>\n\n <!-- Transcript -->\n <div class=\"ttp-transcript desktop-conversation-panel\" id=\"desktopConversationPanel\" dir=\"").concat(textDir, "\">\n <div class=\"ttp-transcript-hdr\" id=\"conversationHeader\">\n <span class=\"ttp-live-label\">Live</span>\n <span class=\"ttp-toggle-text\" id=\"conversationToggleText\">Show history</span>\n <div class=\"ttp-dots\">\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n <div class=\"ttp-dot\"></div>\n </div>\n </div>\n <div class=\"live-transcript-collapsed\" id=\"liveTranscriptCollapsed\">\n <div class=\"ttp-transcript-text\" id=\"liveTextCollapsed\" dir=\"").concat(transcriptDir, "\">\n ").concat(this.t('transcriptWillAppear') || 'Transcript will appear here...', "<span class=\"ttp-cursor\"></span>\n </div>\n </div>\n <div class=\"conversation-history\" id=\"conversationHistory\">\n <div class=\"conversation-messages\" id=\"conversationMessages\"></div>\n <div class=\"live-message-row\" id=\"liveMessageRow\" style=\"display: none;\">\n <div class=\"message-bubble\" dir=\"").concat(transcriptDir, "\">\n <span class=\"live-badge\">Live</span>\n <span id=\"liveMessageText\"></span><span class=\"ttp-cursor\"></span>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Type row -->\n <div class=\"ttp-type-row voice-text-input-area\">\n <input class=\"ttp-input\" type=\"text\" id=\"voiceTextInput\" dir=\"").concat(voiceInputDir, "\" placeholder=\"").concat(this.getText('inputPlaceholder', 'typeMessage') || 'Or type here…', "\" aria-label=\"Type a message\" />\n <button type=\"button\" class=\"ttp-send-btn\" id=\"voiceSendBtn\" aria-label=\"Send message\">\n <svg width=\"13\" height=\"13\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"white\" stroke-width=\"2\">\n <line x1=\"22\" y1=\"2\" x2=\"11\" y2=\"13\"/>\n <polygon points=\"22 2 15 22 11 13 2 9 22 2\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>");
|
|
41290
42586
|
}
|
|
41291
42587
|
|
|
41292
42588
|
/**
|
|
@@ -41303,7 +42599,7 @@ var Templates = /*#__PURE__*/function () {
|
|
|
41303
42599
|
var headerAvatarUrl = resolveIdleHeaderAvatarUrl(this.config);
|
|
41304
42600
|
var mobileAvatarInner = headerAvatarUrl ? "<img src=\"".concat(escapeHtmlAttr(headerAvatarUrl), "\" alt=\"\" class=\"voice-avatar-img\" />") : '🤖';
|
|
41305
42601
|
var mobileAvatarClass = headerAvatarUrl ? 'voice-avatar voice-avatar--image' : 'voice-avatar';
|
|
41306
|
-
return "<div class=\"voice-interface mobile-voice-interface\" id=\"voiceInterface\" dir=\"".concat(textDir, "\">\n <!-- Before Call State (same as desktop) -->\n <div id=\"voiceIdleState\">\n ").concat(this.infoButton('ttp-info-btn--floating'), "\n <div class=\"").concat(mobileAvatarClass, "\" id=\"voiceAvatar\">").concat(mobileAvatarInner, "</div>\n <div class=\"voice-status\">\n <div class=\"voice-status-title\">").concat(this.getText('startCallTitle', 'clickToStartCall'), "</div>\n <div class=\"voice-status-subtitle\">").concat(this.getText('startCallSubtitle', 'realTimeVoice'), "</div>\n </div>\n <button type=\"button\" class=\"start-call-btn\" id=\"startCallBtn\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20.01 15.38c-1.23 0-2.42-.2-3.53-.56-.35-.12-.74-.03-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z\"/>\n </svg>\n <span>").concat(this.getText('startCallButtonText', 'startCall'), "</span>\n </button>\n </div>\n \n <!-- Mobile Active Call State - Hidden placeholder (actual bar will be appended to body) -->\n <div id=\"voiceActiveState\" class=\"mobile-active-state\" style=\"display: none;\">\n <!-- Duration Badge -->\n <div class=\"mobile-duration-badge\" id=\"mobileDurationBadge\">\n <div class=\"mobile-duration-dot\"></div>\n <span id=\"mobileDurationText\">00:00</span>\n ").concat(this.infoButton('ttp-info-btn--onbadge'), "\n </div>\n\n <!-- Main Bar -->\n <div class=\"mobile-voice-bar\">\n <!-- Top Row: Status, Waveform, Controls -->\n <div class=\"mobile-top-row\">\n <!-- Status Indicator -->\n <div class=\"mobile-status-indicator\">\n <div class=\"mobile-status-dot\" id=\"mobileStatusDot\"></div>\n <span class=\"mobile-status-text\" id=\"mobileStatusText\">Listening...</span>\n </div>\n \n <!-- Centered Waveform -->\n <div class=\"mobile-waveform-center\" id=\"mobileWaveform\">\n ").concat(Array(7).fill(0).map(function (_, i) {
|
|
42602
|
+
return "<div class=\"voice-interface mobile-voice-interface\" id=\"voiceInterface\" dir=\"".concat(textDir, "\">\n <!-- Before Call State (same as desktop) -->\n <div id=\"voiceIdleState\">\n ").concat(this.infoButton('ttp-info-btn--floating'), "\n <div class=\"").concat(mobileAvatarClass, "\" id=\"voiceAvatar\">").concat(mobileAvatarInner, "</div>\n <div class=\"voice-status\">\n <div class=\"voice-status-title\">").concat(this.getText('startCallTitle', 'clickToStartCall'), "</div>\n <div class=\"voice-status-subtitle\">").concat(this.getText('startCallSubtitle', 'realTimeVoice'), "</div>\n </div>\n <button type=\"button\" class=\"start-call-btn\" id=\"startCallBtn\">\n <svg width=\"32\" height=\"32\" viewBox=\"0 0 24 24\" fill=\"currentColor\">\n <path d=\"M20.01 15.38c-1.23 0-2.42-.2-3.53-.56-.35-.12-.74-.03-1.01.24l-1.57 1.97c-2.83-1.35-5.48-3.9-6.89-6.83l1.95-1.66c.27-.28.35-.67.24-1.02-.37-1.11-.56-2.3-.56-3.53 0-.54-.45-.99-.99-.99H4.19C3.65 3 3 3.24 3 3.99 3 13.28 10.73 21 20.01 21c.71 0 .99-.63.99-1.18v-3.45c0-.54-.45-.99-.99-.99z\"/>\n </svg>\n <span>").concat(this.getText('startCallButtonText', 'startCall'), "</span>\n </button>\n </div>\n \n <!-- Mobile Active Call State - Hidden placeholder (actual bar will be appended to body) -->\n <div id=\"voiceActiveState\" class=\"mobile-active-state\" style=\"display: none;\">\n <!-- Duration Badge -->\n <div class=\"mobile-duration-badge\" id=\"mobileDurationBadge\">\n <div class=\"mobile-duration-dot\"></div>\n <span id=\"mobileDurationText\">00:00</span>\n ").concat(this.settingsButton('ttp-info-btn--onbadge'), "\n ").concat(this.infoButton('ttp-info-btn--onbadge'), "\n </div>\n\n <!-- Main Bar -->\n <div class=\"mobile-voice-bar\">\n <!-- Top Row: Status, Waveform, Controls -->\n <div class=\"mobile-top-row\">\n <!-- Status Indicator -->\n <div class=\"mobile-status-indicator\">\n <div class=\"mobile-status-dot\" id=\"mobileStatusDot\"></div>\n <span class=\"mobile-status-text\" id=\"mobileStatusText\">Listening...</span>\n </div>\n \n <!-- Centered Waveform -->\n <div class=\"mobile-waveform-center\" id=\"mobileWaveform\">\n ").concat(Array(7).fill(0).map(function (_, i) {
|
|
41307
42603
|
return "<div class=\"mobile-waveform-bar\" data-index=\"".concat(i, "\"></div>");
|
|
41308
42604
|
}).join(''), "\n </div>\n \n <!-- Controls -->\n <div class=\"mobile-controls\">\n <button type=\"button\" class=\"mobile-control-btn\" id=\"mobileMuteBtn\" aria-label=\"Mute microphone\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-mic-icon\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\n </svg>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-mic-off-icon\" style=\"display: none;\">\n <path d=\"M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z\"/>\n <path d=\"M19 10v2a7 7 0 0 1-14 0v-2\"/>\n <line x1=\"12\" x2=\"12\" y1=\"19\" y2=\"22\"/>\n <line x1=\"4\" y1=\"4\" x2=\"20\" y2=\"20\" stroke=\"#ef4444\" stroke-width=\"1.5\" opacity=\"0.85\"/>\n </svg>\n </button>\n \n <button type=\"button\" class=\"mobile-control-btn\" id=\"mobilePauseBtn\" aria-label=\"Pause call\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2\" class=\"mobile-pause-icon\">\n <rect x=\"6\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n <rect x=\"14\" y=\"4\" width=\"4\" height=\"16\" rx=\"1\"/>\n </svg>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"#fff\" stroke=\"none\" class=\"mobile-play-icon\" style=\"display: none;\">\n <polygon points=\"6,4 20,12 6,20\"/>\n </svg>\n </button>\n\n <button type=\"button\" class=\"mobile-control-btn\" id=\"mobileSpeakerBtn\" aria-label=\"Toggle speaker\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-speaker-icon\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n </svg>\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"mobile-speaker-off-icon\" style=\"display: none;\">\n <polygon points=\"11 5 6 9 2 9 2 15 6 15 11 19 11 5\"/>\n <path d=\"M15.54 8.46a5 5 0 0 1 0 7.07\"/>\n <line x1=\"4\" y1=\"4\" x2=\"20\" y2=\"20\" stroke=\"#ef4444\" stroke-width=\"1.5\" opacity=\"0.85\"/>\n </svg>\n </button>\n\n <button type=\"button\" class=\"mobile-end-call-btn\" id=\"mobileEndCallBtn\" aria-label=\"End call\">\n <svg width=\"15\" height=\"15\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"#fff\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M10.68 13.31a16 16 0 0 0 3.41 2.6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7 2 2 0 0 1 1.72 2v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.42 19.42 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.63A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91\"/>\n <line x1=\"22\" x2=\"2\" y1=\"2\" y2=\"22\"/>\n </svg>\n </button>\n </div>\n </div>\n \n <!-- Bottom Row: Transcript (expandable) -->\n <button type=\"button\" class=\"mobile-transcript-row\" id=\"mobileTranscriptRow\">\n <p class=\"mobile-transcript-text\" id=\"mobileTranscriptText\" dir=\"").concat(transcriptDir, "\">").concat(this.t('transcriptWillAppear'), "</p>\n <div class=\"mobile-transcript-footer\">\n <span class=\"mobile-expand-hint\">tap to expand & type</span>\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" style=\"opacity: 0.6;\">\n <path d=\"M7 17L17 7M17 7H7M17 7V17\"/>\n </svg>\n </div>\n </button>\n </div>\n </div>\n \n <!-- Expanded Transcript Overlay -->\n <div class=\"mobile-transcript-overlay\" id=\"mobileTranscriptOverlay\">\n <div class=\"mobile-expanded-transcript\" id=\"mobileExpandedTranscript\">\n <!-- Header -->\n <div class=\"mobile-transcript-header\">\n <div class=\"mobile-header-left\">\n <div class=\"mobile-header-status\">\n <div class=\"mobile-header-status-dot\"></div>\n <span class=\"mobile-header-status-text\" id=\"mobileHeaderStatusText\">Listening...</span>\n <span class=\"mobile-header-duration\" id=\"mobileHeaderDuration\">00:00</span>\n </div>\n <span class=\"mobile-transcript-label\">CONVERSATION</span>\n </div>\n <button type=\"button\" class=\"mobile-close-transcript-btn\" id=\"mobileCloseTranscriptBtn\">\n <svg width=\"14\" height=\"14\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M18 6L6 18M6 6l12 12\"/>\n </svg>\n </button>\n </div>\n \n <!-- Messages Container -->\n <div class=\"mobile-messages-container\" id=\"mobileMessagesContainer\">\n <!-- Messages will be dynamically added here -->\n </div>\n \n <!-- Text Input Area -->\n <div class=\"mobile-input-area\">\n <div class=\"mobile-input-wrapper\">\n <input\n type=\"text\"\n placeholder=\"Type a message...\"\n id=\"mobileTextInput\"\n class=\"mobile-text-input\"\n dir=\"").concat(voiceInputDir, "\"\n />\n <button type=\"button\" class=\"mobile-send-btn\" id=\"mobileSendBtn\" disabled>\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\">\n <path d=\"M22 2L11 13M22 2l-7 20-4-9-9-4 20-7z\"/>\n </svg>\n </button>\n </div>\n <p class=\"mobile-input-hint\">\uD83C\uDF99\uFE0F Voice is still active \u2022 Type or speak</p>\n </div>\n </div>\n </div>\n </div>");
|
|
41309
42605
|
}
|
|
@@ -42152,7 +43448,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42152
43448
|
"aboutTitle": "About",
|
|
42153
43449
|
"aboutVersion": "SDK version",
|
|
42154
43450
|
"aboutConversationId": "Last conversation ID",
|
|
42155
|
-
"aboutNoConversation": "No conversation yet"
|
|
43451
|
+
"aboutNoConversation": "No conversation yet",
|
|
43452
|
+
"settingsTitle": "Call settings",
|
|
43453
|
+
"settingsVoiceSpeed": "Voice speed",
|
|
43454
|
+
"settingsResponseLength": "Response length",
|
|
43455
|
+
"lengthDetailed": "Detailed",
|
|
43456
|
+
"lengthNormal": "Normal",
|
|
43457
|
+
"lengthBrief": "Brief",
|
|
43458
|
+
"lengthVeryBrief": "Very brief"
|
|
42156
43459
|
},
|
|
42157
43460
|
"he": {
|
|
42158
43461
|
"landingTitle": "איך תרצה לתקשר?",
|
|
@@ -42189,7 +43492,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42189
43492
|
"aboutTitle": "אודות",
|
|
42190
43493
|
"aboutVersion": "גרסת SDK",
|
|
42191
43494
|
"aboutConversationId": "מזהה שיחה אחרון",
|
|
42192
|
-
"aboutNoConversation": "אין שיחה עדיין"
|
|
43495
|
+
"aboutNoConversation": "אין שיחה עדיין",
|
|
43496
|
+
"settingsTitle": "הגדרות שיחה",
|
|
43497
|
+
"settingsVoiceSpeed": "מהירות דיבור",
|
|
43498
|
+
"settingsResponseLength": "אורך תשובות",
|
|
43499
|
+
"lengthDetailed": "מפורט",
|
|
43500
|
+
"lengthNormal": "רגיל",
|
|
43501
|
+
"lengthBrief": "קצר",
|
|
43502
|
+
"lengthVeryBrief": "קצר מאוד"
|
|
42193
43503
|
},
|
|
42194
43504
|
"ar": {
|
|
42195
43505
|
"landingTitle": "كيف تريد التواصل؟",
|
|
@@ -42226,7 +43536,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42226
43536
|
"aboutTitle": "حول",
|
|
42227
43537
|
"aboutVersion": "إصدار SDK",
|
|
42228
43538
|
"aboutConversationId": "معرّف آخر محادثة",
|
|
42229
|
-
"aboutNoConversation": "لا توجد محادثة بعد"
|
|
43539
|
+
"aboutNoConversation": "لا توجد محادثة بعد",
|
|
43540
|
+
"settingsTitle": "إعدادات المكالمة",
|
|
43541
|
+
"settingsVoiceSpeed": "سرعة الصوت",
|
|
43542
|
+
"settingsResponseLength": "طول الإجابات",
|
|
43543
|
+
"lengthDetailed": "مفصّل",
|
|
43544
|
+
"lengthNormal": "عادي",
|
|
43545
|
+
"lengthBrief": "مختصر",
|
|
43546
|
+
"lengthVeryBrief": "مختصر جداً"
|
|
42230
43547
|
},
|
|
42231
43548
|
"ru": {
|
|
42232
43549
|
"landingTitle": "Как вы хотите общаться?",
|
|
@@ -42263,7 +43580,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42263
43580
|
"aboutTitle": "О приложении",
|
|
42264
43581
|
"aboutVersion": "Версия SDK",
|
|
42265
43582
|
"aboutConversationId": "ID последнего разговора",
|
|
42266
|
-
"aboutNoConversation": "Разговоров пока нет"
|
|
43583
|
+
"aboutNoConversation": "Разговоров пока нет",
|
|
43584
|
+
"settingsTitle": "Настройки звонка",
|
|
43585
|
+
"settingsVoiceSpeed": "Скорость речи",
|
|
43586
|
+
"settingsResponseLength": "Длина ответов",
|
|
43587
|
+
"lengthDetailed": "Подробно",
|
|
43588
|
+
"lengthNormal": "Обычно",
|
|
43589
|
+
"lengthBrief": "Кратко",
|
|
43590
|
+
"lengthVeryBrief": "Очень кратко"
|
|
42267
43591
|
},
|
|
42268
43592
|
"es": {
|
|
42269
43593
|
"landingTitle": "¿Cómo te gustaría comunicarte?",
|
|
@@ -42300,7 +43624,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42300
43624
|
"aboutTitle": "Acerca de",
|
|
42301
43625
|
"aboutVersion": "Versión del SDK",
|
|
42302
43626
|
"aboutConversationId": "ID de última conversación",
|
|
42303
|
-
"aboutNoConversation": "Aún no hay conversación"
|
|
43627
|
+
"aboutNoConversation": "Aún no hay conversación",
|
|
43628
|
+
"settingsTitle": "Ajustes de llamada",
|
|
43629
|
+
"settingsVoiceSpeed": "Velocidad de voz",
|
|
43630
|
+
"settingsResponseLength": "Longitud de respuesta",
|
|
43631
|
+
"lengthDetailed": "Detallada",
|
|
43632
|
+
"lengthNormal": "Normal",
|
|
43633
|
+
"lengthBrief": "Breve",
|
|
43634
|
+
"lengthVeryBrief": "Muy breve"
|
|
42304
43635
|
},
|
|
42305
43636
|
"fr": {
|
|
42306
43637
|
"landingTitle": "Comment souhaitez-vous communiquer?",
|
|
@@ -42337,7 +43668,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42337
43668
|
"aboutTitle": "À propos",
|
|
42338
43669
|
"aboutVersion": "Version du SDK",
|
|
42339
43670
|
"aboutConversationId": "ID de la dernière conversation",
|
|
42340
|
-
"aboutNoConversation": "Aucune conversation pour l'instant"
|
|
43671
|
+
"aboutNoConversation": "Aucune conversation pour l'instant",
|
|
43672
|
+
"settingsTitle": "Paramètres d'appel",
|
|
43673
|
+
"settingsVoiceSpeed": "Vitesse de la voix",
|
|
43674
|
+
"settingsResponseLength": "Longueur des réponses",
|
|
43675
|
+
"lengthDetailed": "Détaillée",
|
|
43676
|
+
"lengthNormal": "Normale",
|
|
43677
|
+
"lengthBrief": "Brève",
|
|
43678
|
+
"lengthVeryBrief": "Très brève"
|
|
42341
43679
|
},
|
|
42342
43680
|
"de": {
|
|
42343
43681
|
"landingTitle": "Wie möchten Sie kommunizieren?",
|
|
@@ -42374,7 +43712,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42374
43712
|
"aboutTitle": "Über",
|
|
42375
43713
|
"aboutVersion": "SDK-Version",
|
|
42376
43714
|
"aboutConversationId": "Letzte Konversations-ID",
|
|
42377
|
-
"aboutNoConversation": "Noch keine Konversation"
|
|
43715
|
+
"aboutNoConversation": "Noch keine Konversation",
|
|
43716
|
+
"settingsTitle": "Anrufeinstellungen",
|
|
43717
|
+
"settingsVoiceSpeed": "Sprechgeschwindigkeit",
|
|
43718
|
+
"settingsResponseLength": "Antwortlänge",
|
|
43719
|
+
"lengthDetailed": "Ausführlich",
|
|
43720
|
+
"lengthNormal": "Normal",
|
|
43721
|
+
"lengthBrief": "Kurz",
|
|
43722
|
+
"lengthVeryBrief": "Sehr kurz"
|
|
42378
43723
|
}
|
|
42379
43724
|
});
|
|
42380
43725
|
|