ttp-agent-sdk 2.45.14 → 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 +1560 -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
|
|
@@ -27010,6 +27912,10 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27010
27912
|
websocketUrl: config.websocketUrl || 'wss://speech.talktopc.com/ws/conv',
|
|
27011
27913
|
agentId: config.agentId,
|
|
27012
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,
|
|
27013
27919
|
// Input format (what we send to server)
|
|
27014
27920
|
|
|
27015
27921
|
sampleRate: config.sampleRate || 16000,
|
|
@@ -27651,12 +28557,28 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27651
28557
|
/**
|
|
27652
28558
|
* Build WebSocket URL with query parameters
|
|
27653
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
|
+
}
|
|
27654
28566
|
}, {
|
|
27655
28567
|
key: "buildWebSocketUrl",
|
|
27656
28568
|
value: function buildWebSocketUrl() {
|
|
27657
28569
|
var baseUrl = this.config.websocketUrl;
|
|
27658
28570
|
var url = new URL(baseUrl, 'wss://placeholder.com');
|
|
27659
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
|
+
}
|
|
27660
28582
|
if (this.config.agentId && !params.has('agentId')) {
|
|
27661
28583
|
params.append('agentId', this.config.agentId);
|
|
27662
28584
|
}
|
|
@@ -27738,9 +28660,12 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27738
28660
|
});
|
|
27739
28661
|
}
|
|
27740
28662
|
|
|
27741
|
-
// Send hello message
|
|
27742
|
-
|
|
27743
|
-
|
|
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
|
+
}
|
|
27744
28669
|
_this5.emit('connected');
|
|
27745
28670
|
resolve(true);
|
|
27746
28671
|
};
|
|
@@ -27952,7 +28877,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
27952
28877
|
|
|
27953
28878
|
// Include SDK build time for debugging
|
|
27954
28879
|
if (true) {
|
|
27955
|
-
helloMessage.lastBuildTime = "2026-
|
|
28880
|
+
helloMessage.lastBuildTime = "2026-07-13T08:30:44.984Z";
|
|
27956
28881
|
}
|
|
27957
28882
|
|
|
27958
28883
|
// Page context is intentionally NOT attached to the hello message.
|
|
@@ -28254,6 +29179,8 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28254
29179
|
break;
|
|
28255
29180
|
case 'show_items':
|
|
28256
29181
|
case 'show_products':
|
|
29182
|
+
case 'show_recipe':
|
|
29183
|
+
case 'dismiss_recipe':
|
|
28257
29184
|
case 'cart_updated':
|
|
28258
29185
|
case 'add_to_store_cart':
|
|
28259
29186
|
case 'add_to_site_cart':
|
|
@@ -28519,6 +29446,11 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
28519
29446
|
// VoiceInterface waits for this flag before starting recording,
|
|
28520
29447
|
// so config.sampleRate must be finalized first.
|
|
28521
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();
|
|
28522
29454
|
if (message.outputAudioFormat) {
|
|
28523
29455
|
// v2 protocol: format was negotiated
|
|
28524
29456
|
|
|
@@ -29332,6 +30264,79 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29332
30264
|
}
|
|
29333
30265
|
}
|
|
29334
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
|
+
|
|
29335
30340
|
/**
|
|
29336
30341
|
* Pause the call. Stops sending/receiving audio.
|
|
29337
30342
|
*/
|
|
@@ -29455,64 +30460,72 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29455
30460
|
while (1) switch (_context8.p = _context8.n) {
|
|
29456
30461
|
case 0:
|
|
29457
30462
|
existingMediaStream = _args8.length > 0 && _args8[0] !== undefined ? _args8[0] : null;
|
|
29458
|
-
if (this.
|
|
30463
|
+
if (!this.isMonitor()) {
|
|
29459
30464
|
_context8.n = 1;
|
|
29460
30465
|
break;
|
|
29461
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
|
+
}
|
|
29462
30475
|
error = new Error('Not connected to voice server');
|
|
29463
30476
|
this.emit('error', error);
|
|
29464
30477
|
throw error;
|
|
29465
|
-
case
|
|
30478
|
+
case 2:
|
|
29466
30479
|
if (!this.isRecording) {
|
|
29467
|
-
_context8.n =
|
|
30480
|
+
_context8.n = 3;
|
|
29468
30481
|
break;
|
|
29469
30482
|
}
|
|
29470
30483
|
console.warn('VoiceSDK v2: Already recording');
|
|
29471
30484
|
return _context8.a(2, true);
|
|
29472
|
-
case
|
|
30485
|
+
case 3:
|
|
29473
30486
|
if (!this.disclaimersPending) {
|
|
29474
|
-
_context8.n =
|
|
30487
|
+
_context8.n = 4;
|
|
29475
30488
|
break;
|
|
29476
30489
|
}
|
|
29477
30490
|
_error4 = new Error('Server disclaimers must be accepted before recording. Call sendDisclaimerAck(true) first.');
|
|
29478
30491
|
_error4.code = 'DISCLAIMER_PENDING';
|
|
29479
30492
|
this.emit('error', _error4);
|
|
29480
30493
|
throw _error4;
|
|
29481
|
-
case
|
|
30494
|
+
case 4:
|
|
29482
30495
|
console.log('🎤 VoiceSDK v2: Starting recording...');
|
|
29483
|
-
_context8.p =
|
|
30496
|
+
_context8.p = 5;
|
|
29484
30497
|
// CRITICAL for mobile browsers: Request microphone permission FIRST
|
|
29485
30498
|
// iOS: Pass existingMediaStream to avoid second getUserMedia (can fail on iOS)
|
|
29486
30499
|
console.log('🎤 VoiceSDK v2: Requesting microphone permission (mobile-friendly)...');
|
|
29487
|
-
_context8.n =
|
|
30500
|
+
_context8.n = 6;
|
|
29488
30501
|
return this.audioRecorder.start(existingMediaStream ? {
|
|
29489
30502
|
existingMediaStream: existingMediaStream
|
|
29490
30503
|
} : {});
|
|
29491
|
-
case
|
|
30504
|
+
case 6:
|
|
29492
30505
|
if (!(!this.isConnected || !this.websocket || this.websocket.readyState !== WebSocket.OPEN)) {
|
|
29493
|
-
_context8.n =
|
|
30506
|
+
_context8.n = 11;
|
|
29494
30507
|
break;
|
|
29495
30508
|
}
|
|
29496
|
-
_context8.p =
|
|
29497
|
-
_context8.n =
|
|
30509
|
+
_context8.p = 7;
|
|
30510
|
+
_context8.n = 8;
|
|
29498
30511
|
return this.audioRecorder.stop();
|
|
29499
|
-
case 7:
|
|
29500
|
-
_context8.n = 9;
|
|
29501
|
-
break;
|
|
29502
30512
|
case 8:
|
|
29503
|
-
_context8.
|
|
29504
|
-
|
|
30513
|
+
_context8.n = 10;
|
|
30514
|
+
break;
|
|
29505
30515
|
case 9:
|
|
30516
|
+
_context8.p = 9;
|
|
30517
|
+
_t6 = _context8.v;
|
|
30518
|
+
case 10:
|
|
29506
30519
|
_error5 = new Error('Connection lost - server may have rejected the call');
|
|
29507
30520
|
_error5.name = 'ServerRejected';
|
|
29508
30521
|
_error5.isServerRejection = true;
|
|
29509
30522
|
// Don't emit error event - this is expected when server rejects
|
|
29510
30523
|
// The error handler in VoiceInterface will handle it appropriately
|
|
29511
30524
|
throw _error5;
|
|
29512
|
-
case 10:
|
|
29513
|
-
_context8.n = 11;
|
|
29514
|
-
return this.audioPlayer.resumeAudioContext();
|
|
29515
30525
|
case 11:
|
|
30526
|
+
_context8.n = 12;
|
|
30527
|
+
return this.audioPlayer.resumeAudioContext();
|
|
30528
|
+
case 12:
|
|
29516
30529
|
// After permission is granted, send start_continuous_mode message to server
|
|
29517
30530
|
this.sendMessage({
|
|
29518
30531
|
t: 'start_continuous_mode',
|
|
@@ -29522,29 +30535,29 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29522
30535
|
// Request screen wake lock to keep screen on during voice call (mobile)
|
|
29523
30536
|
this._requestWakeLock();
|
|
29524
30537
|
return _context8.a(2, true);
|
|
29525
|
-
case
|
|
29526
|
-
_context8.p =
|
|
30538
|
+
case 13:
|
|
30539
|
+
_context8.p = 13;
|
|
29527
30540
|
_t7 = _context8.v;
|
|
29528
30541
|
if (!(this.audioRecorder && this.audioRecorder.isRecording)) {
|
|
29529
|
-
_context8.n =
|
|
30542
|
+
_context8.n = 17;
|
|
29530
30543
|
break;
|
|
29531
30544
|
}
|
|
29532
|
-
_context8.p =
|
|
29533
|
-
_context8.n =
|
|
30545
|
+
_context8.p = 14;
|
|
30546
|
+
_context8.n = 15;
|
|
29534
30547
|
return this.audioRecorder.stop();
|
|
29535
|
-
case 14:
|
|
29536
|
-
_context8.n = 16;
|
|
29537
|
-
break;
|
|
29538
30548
|
case 15:
|
|
29539
|
-
_context8.
|
|
29540
|
-
|
|
30549
|
+
_context8.n = 17;
|
|
30550
|
+
break;
|
|
29541
30551
|
case 16:
|
|
30552
|
+
_context8.p = 16;
|
|
30553
|
+
_t8 = _context8.v;
|
|
30554
|
+
case 17:
|
|
29542
30555
|
if (!(_t7.isServerRejection || _t7.name === 'ServerRejected')) {
|
|
29543
|
-
_context8.n =
|
|
30556
|
+
_context8.n = 18;
|
|
29544
30557
|
break;
|
|
29545
30558
|
}
|
|
29546
30559
|
return _context8.a(2, false);
|
|
29547
|
-
case
|
|
30560
|
+
case 18:
|
|
29548
30561
|
// Log and emit other errors (permission denied, etc.)
|
|
29549
30562
|
console.error('❌ VoiceSDK v2: Failed to start recording:', _t7);
|
|
29550
30563
|
|
|
@@ -29559,7 +30572,7 @@ var VoiceSDK_v2 = /*#__PURE__*/function (_EventEmitter) {
|
|
|
29559
30572
|
}
|
|
29560
30573
|
return _context8.a(2, false);
|
|
29561
30574
|
}
|
|
29562
|
-
}, _callee8, this, [[
|
|
30575
|
+
}, _callee8, this, [[14, 16], [7, 9], [5, 13]]);
|
|
29563
30576
|
}));
|
|
29564
30577
|
function startRecording() {
|
|
29565
30578
|
return _startRecording.apply(this, arguments);
|
|
@@ -31391,7 +32404,10 @@ var AgentSDK = /*#__PURE__*/function () {
|
|
|
31391
32404
|
flavor: this.config.flavor || null,
|
|
31392
32405
|
// Shared client-tool handler map (set by TTPChatWidget so voice + text SDKs
|
|
31393
32406
|
// both look up handlers in the same registration site).
|
|
31394
|
-
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
|
|
31395
32411
|
}));
|
|
31396
32412
|
|
|
31397
32413
|
// If we have stored resume info from checkResumeBeforeConnect(), use it
|
|
@@ -32387,6 +33403,7 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
32387
33403
|
/* harmony import */ var _widget_translations_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./widget-translations.js */ "./src/widget/widget-translations.js");
|
|
32388
33404
|
/* harmony import */ var _flavors_index_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../flavors/index.js */ "./src/flavors/index.js");
|
|
32389
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");
|
|
32390
33407
|
var _excluded = ["agentName"];
|
|
32391
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; }
|
|
32392
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; }
|
|
@@ -32415,6 +33432,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
|
|
|
32415
33432
|
|
|
32416
33433
|
|
|
32417
33434
|
|
|
33435
|
+
|
|
32418
33436
|
/** Fallback for `buildWebSocketUrl()` when no optional `websocketUrl` override is set (VoiceSDK v2 uses the same default). */
|
|
32419
33437
|
var DEFAULT_VOICE_WEBSOCKET_URL = 'wss://speech.talktopc.com/ws/conv';
|
|
32420
33438
|
function isNonEmptyConfigString(v) {
|
|
@@ -32507,7 +33525,8 @@ function talkToPcLinkColorForPanel(isLightPanel, mergedVoice, rawConfig, voiceUi
|
|
|
32507
33525
|
}
|
|
32508
33526
|
var TTPChatWidget = /*#__PURE__*/function () {
|
|
32509
33527
|
function TTPChatWidget() {
|
|
32510
|
-
var _this
|
|
33528
|
+
var _this = this,
|
|
33529
|
+
_this$config$behavior,
|
|
32511
33530
|
_this$config$panel,
|
|
32512
33531
|
_this$config$flavor,
|
|
32513
33532
|
_this$config$text,
|
|
@@ -32517,8 +33536,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
32517
33536
|
_this$config$voice3,
|
|
32518
33537
|
_this$config$voice4,
|
|
32519
33538
|
_this$config$voice5,
|
|
32520
|
-
_this$config$voice6
|
|
32521
|
-
_this = this;
|
|
33539
|
+
_this$config$voice6;
|
|
32522
33540
|
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
32523
33541
|
_classCallCheck(this, TTPChatWidget);
|
|
32524
33542
|
this._rawConfig = config;
|
|
@@ -32526,6 +33544,14 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
32526
33544
|
this.config = this.mergeWithDefaults(config);
|
|
32527
33545
|
// Silently ignore allowOverride (now server-side only)
|
|
32528
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
|
+
|
|
32529
33555
|
// Shared client-tool handler map. Both VoiceSDK and TextChatSDK look up
|
|
32530
33556
|
// handlers in this Map, so a single registerToolHandler() call works for
|
|
32531
33557
|
// whichever channel the LLM happens to be running on at tool-call time.
|
|
@@ -32847,11 +33873,21 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
32847
33873
|
if (flavor.messageHandlers['dismiss_media']) {
|
|
32848
33874
|
flavor.messageHandlers['dismiss_media']();
|
|
32849
33875
|
}
|
|
33876
|
+
if (flavor.messageHandlers['dismiss_recipe']) {
|
|
33877
|
+
flavor.messageHandlers['dismiss_recipe']({
|
|
33878
|
+
silent: true
|
|
33879
|
+
});
|
|
33880
|
+
}
|
|
32850
33881
|
});
|
|
32851
33882
|
this.voiceSDK.on('bargeIn', function () {
|
|
32852
33883
|
if (flavor.messageHandlers['dismiss_media']) {
|
|
32853
33884
|
flavor.messageHandlers['dismiss_media']();
|
|
32854
33885
|
}
|
|
33886
|
+
if (flavor.messageHandlers['dismiss_recipe']) {
|
|
33887
|
+
flavor.messageHandlers['dismiss_recipe']({
|
|
33888
|
+
silent: true
|
|
33889
|
+
});
|
|
33890
|
+
}
|
|
32855
33891
|
});
|
|
32856
33892
|
console.log("[TTPChatWidget] Flavor \"".concat(flavorName, "\" message listeners attached (voice)"));
|
|
32857
33893
|
}
|
|
@@ -33767,6 +34803,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
33767
34803
|
};
|
|
33768
34804
|
}
|
|
33769
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
|
+
|
|
33770
34820
|
/**
|
|
33771
34821
|
* Generate footer branding HTML
|
|
33772
34822
|
*/
|
|
@@ -33854,7 +34904,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
33854
34904
|
return;
|
|
33855
34905
|
}
|
|
33856
34906
|
this._ensureAboutStyles();
|
|
33857
|
-
var version = true ? "2.
|
|
34907
|
+
var version = true ? "2.46.1" : 0;
|
|
33858
34908
|
var convId = this._getLastConversationId();
|
|
33859
34909
|
var t = function t(k, fb) {
|
|
33860
34910
|
try {
|
|
@@ -33911,6 +34961,190 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
33911
34961
|
this._aboutOverlay = null;
|
|
33912
34962
|
}
|
|
33913
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
|
+
}
|
|
33914
35148
|
}, {
|
|
33915
35149
|
key: "generatePositionStyles",
|
|
33916
35150
|
value: function generatePositionStyles() {
|
|
@@ -34047,7 +35281,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34047
35281
|
}, {
|
|
34048
35282
|
key: "setupWidgetEvents",
|
|
34049
35283
|
value: function setupWidgetEvents() {
|
|
34050
|
-
var
|
|
35284
|
+
var _this0 = this,
|
|
34051
35285
|
_this$config$behavior8,
|
|
34052
35286
|
_this$config$position5;
|
|
34053
35287
|
if (!this.shadowRoot) return;
|
|
@@ -34061,17 +35295,17 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34061
35295
|
launcherBtn.onclick = function (e) {
|
|
34062
35296
|
e.stopPropagation();
|
|
34063
35297
|
// A drag just ended — don't treat the trailing click as "open panel".
|
|
34064
|
-
if (
|
|
34065
|
-
if (
|
|
34066
|
-
|
|
35298
|
+
if (_this0._suppressLauncherClick) return;
|
|
35299
|
+
if (_this0.config.promptAnimation.hideAfterClick) {
|
|
35300
|
+
_this0.hidePrompt();
|
|
34067
35301
|
}
|
|
34068
|
-
|
|
35302
|
+
_this0.togglePanel();
|
|
34069
35303
|
};
|
|
34070
35304
|
}
|
|
34071
35305
|
var closeBtn = this.shadowRoot.getElementById('closeBtn');
|
|
34072
35306
|
if (closeBtn) {
|
|
34073
35307
|
closeBtn.onclick = function () {
|
|
34074
|
-
|
|
35308
|
+
_this0._doTogglePanel();
|
|
34075
35309
|
};
|
|
34076
35310
|
}
|
|
34077
35311
|
|
|
@@ -34079,23 +35313,34 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34079
35313
|
var closeIdle = this.shadowRoot.getElementById('ttpCloseIdle');
|
|
34080
35314
|
if (closeIdle) {
|
|
34081
35315
|
closeIdle.onclick = function () {
|
|
34082
|
-
return
|
|
35316
|
+
return _this0._doTogglePanel();
|
|
34083
35317
|
};
|
|
34084
35318
|
}
|
|
34085
35319
|
var closeActive = this.shadowRoot.getElementById('ttpCloseActive');
|
|
34086
35320
|
if (closeActive) {
|
|
34087
35321
|
closeActive.onclick = function () {
|
|
34088
|
-
return
|
|
35322
|
+
return _this0._doTogglePanel();
|
|
34089
35323
|
};
|
|
34090
35324
|
}
|
|
34091
35325
|
|
|
34092
35326
|
// "About" info buttons (present in every view: idle / active / compact /
|
|
34093
35327
|
// mobile idle / mobile active / text top-bar). One shared dialog.
|
|
34094
|
-
|
|
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) {
|
|
34095
35340
|
btn.onclick = function (e) {
|
|
34096
35341
|
e.stopPropagation();
|
|
34097
35342
|
e.preventDefault();
|
|
34098
|
-
|
|
35343
|
+
_this0._openCallSettingsModal();
|
|
34099
35344
|
};
|
|
34100
35345
|
});
|
|
34101
35346
|
|
|
@@ -34103,17 +35348,17 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34103
35348
|
var startTextBtn = this.shadowRoot.getElementById('startTextBtn');
|
|
34104
35349
|
if (startTextBtn) {
|
|
34105
35350
|
startTextBtn.onclick = function () {
|
|
34106
|
-
return
|
|
35351
|
+
return _this0.showText();
|
|
34107
35352
|
};
|
|
34108
35353
|
}
|
|
34109
35354
|
var textUnifiedBackBtn = this.shadowRoot.getElementById('textUnifiedBackBtn');
|
|
34110
35355
|
if (textUnifiedBackBtn) {
|
|
34111
35356
|
textUnifiedBackBtn.onclick = function () {
|
|
34112
|
-
var
|
|
34113
|
-
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';
|
|
34114
35359
|
if (widgetMode !== 'unified') return;
|
|
34115
|
-
|
|
34116
|
-
|
|
35360
|
+
_this0.showLanding();
|
|
35361
|
+
_this0._openMobileCallTextLanding();
|
|
34117
35362
|
};
|
|
34118
35363
|
}
|
|
34119
35364
|
|
|
@@ -34143,30 +35388,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34143
35388
|
// Setup back button handler
|
|
34144
35389
|
if (backBtn) {
|
|
34145
35390
|
backBtn.onclick = function () {
|
|
34146
|
-
var
|
|
35391
|
+
var _this0$voiceInterface, _this0$voiceInterface3;
|
|
34147
35392
|
// Check if we're showing a domain error — clear it and return to voice hero
|
|
34148
|
-
if ((
|
|
34149
|
-
var
|
|
35393
|
+
if ((_this0$voiceInterface = _this0.voiceInterface) !== null && _this0$voiceInterface !== void 0 && _this0$voiceInterface.isShowingDomainError) {
|
|
35394
|
+
var _this0$voiceInterface2;
|
|
34150
35395
|
console.log('🔙 Back button clicked - clearing domain error and returning to voice hero');
|
|
34151
35396
|
// Clear the domain error flag
|
|
34152
|
-
|
|
35397
|
+
_this0.voiceInterface.isShowingDomainError = false;
|
|
34153
35398
|
// Reset the connecting state (this will restore normal UI)
|
|
34154
|
-
if ((
|
|
34155
|
-
|
|
35399
|
+
if ((_this0$voiceInterface2 = _this0.voiceInterface) !== null && _this0$voiceInterface2 !== void 0 && _this0$voiceInterface2.resetConnectingState) {
|
|
35400
|
+
_this0.voiceInterface.resetConnectingState();
|
|
34156
35401
|
}
|
|
34157
|
-
|
|
34158
|
-
|
|
35402
|
+
_this0.showLanding();
|
|
35403
|
+
_this0._openMobileCallTextLanding();
|
|
34159
35404
|
return;
|
|
34160
35405
|
}
|
|
34161
|
-
if ((
|
|
35406
|
+
if ((_this0$voiceInterface3 = _this0.voiceInterface) !== null && _this0$voiceInterface3 !== void 0 && _this0$voiceInterface3.isActive) {
|
|
34162
35407
|
// If call is active, show message inside widget instead of modal
|
|
34163
|
-
|
|
35408
|
+
_this0.showBackButtonWarning();
|
|
34164
35409
|
} else if (window.innerWidth <= 768) {
|
|
34165
|
-
|
|
34166
|
-
|
|
35410
|
+
_this0.showLanding();
|
|
35411
|
+
_this0._openMobileCallTextLanding();
|
|
34167
35412
|
} else {
|
|
34168
35413
|
// Desktop: return to voice hero (unified home)
|
|
34169
|
-
|
|
35414
|
+
_this0.showLanding();
|
|
34170
35415
|
}
|
|
34171
35416
|
};
|
|
34172
35417
|
}
|
|
@@ -34209,7 +35454,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34209
35454
|
// Setup header button handlers
|
|
34210
35455
|
if (newChatBtn) {
|
|
34211
35456
|
newChatBtn.onclick = function () {
|
|
34212
|
-
return
|
|
35457
|
+
return _this0.textInterface.startNewChat();
|
|
34213
35458
|
};
|
|
34214
35459
|
// Hide new chat on unified home (voice hero) initially
|
|
34215
35460
|
if (isUnified && this.currentView !== 'text') {
|
|
@@ -34355,7 +35600,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34355
35600
|
}, {
|
|
34356
35601
|
key: "_restoreUnitOffset",
|
|
34357
35602
|
value: function _restoreUnitOffset(key) {
|
|
34358
|
-
var
|
|
35603
|
+
var _this1 = this;
|
|
34359
35604
|
var saved;
|
|
34360
35605
|
try {
|
|
34361
35606
|
saved = JSON.parse(window.localStorage.getItem(key) || 'null');
|
|
@@ -34364,13 +35609,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34364
35609
|
}
|
|
34365
35610
|
if (!saved || typeof saved.x !== 'number' || typeof saved.y !== 'number') return;
|
|
34366
35611
|
requestAnimationFrame(function () {
|
|
34367
|
-
|
|
35612
|
+
_this1._unitOffset = {
|
|
34368
35613
|
x: 0,
|
|
34369
35614
|
y: 0
|
|
34370
35615
|
}; // ensure DOM matches before measuring
|
|
34371
|
-
var bases =
|
|
34372
|
-
|
|
34373
|
-
|
|
35616
|
+
var bases = _this1._unitBaseRects();
|
|
35617
|
+
_this1._unitOffset = _this1._clampUnitOffset(saved.x, saved.y, bases);
|
|
35618
|
+
_this1._applyUnitOffset();
|
|
34374
35619
|
});
|
|
34375
35620
|
}
|
|
34376
35621
|
|
|
@@ -34387,7 +35632,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34387
35632
|
}, {
|
|
34388
35633
|
key: "_attachUnitDrag",
|
|
34389
35634
|
value: function _attachUnitDrag(handle, opts) {
|
|
34390
|
-
var
|
|
35635
|
+
var _this10 = this;
|
|
34391
35636
|
var persist = opts.persist,
|
|
34392
35637
|
key = opts.key,
|
|
34393
35638
|
excludeSelector = opts.excludeSelector,
|
|
@@ -34408,8 +35653,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34408
35653
|
var dy = e.clientY - startY;
|
|
34409
35654
|
if (!moved && Math.hypot(dx, dy) < DRAG_THRESHOLD) return;
|
|
34410
35655
|
moved = true;
|
|
34411
|
-
|
|
34412
|
-
|
|
35656
|
+
_this10._unitOffset = _this10._clampUnitOffset(baseX + dx, baseY + dy, bases);
|
|
35657
|
+
_this10._applyUnitOffset();
|
|
34413
35658
|
};
|
|
34414
35659
|
var _onUp = function onUp(e) {
|
|
34415
35660
|
window.removeEventListener('pointermove', onMove);
|
|
@@ -34423,7 +35668,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34423
35668
|
if (typeof onMoved === 'function') onMoved();
|
|
34424
35669
|
if (persist && key) {
|
|
34425
35670
|
try {
|
|
34426
|
-
window.localStorage.setItem(key, JSON.stringify(
|
|
35671
|
+
window.localStorage.setItem(key, JSON.stringify(_this10._unitOffset));
|
|
34427
35672
|
} catch (err) {/* unavailable */}
|
|
34428
35673
|
}
|
|
34429
35674
|
}
|
|
@@ -34434,7 +35679,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34434
35679
|
if (excludeSelector && e.target && e.target.closest && e.target.closest(excludeSelector)) return;
|
|
34435
35680
|
dragging = true;
|
|
34436
35681
|
moved = false;
|
|
34437
|
-
var o =
|
|
35682
|
+
var o = _this10._unitOffset || (_this10._unitOffset = {
|
|
34438
35683
|
x: 0,
|
|
34439
35684
|
y: 0
|
|
34440
35685
|
});
|
|
@@ -34442,7 +35687,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34442
35687
|
startY = e.clientY;
|
|
34443
35688
|
baseX = o.x;
|
|
34444
35689
|
baseY = o.y;
|
|
34445
|
-
bases =
|
|
35690
|
+
bases = _this10._unitBaseRects();
|
|
34446
35691
|
handle.style.setProperty('cursor', 'grabbing');
|
|
34447
35692
|
try {
|
|
34448
35693
|
handle.setPointerCapture(e.pointerId);
|
|
@@ -34464,7 +35709,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34464
35709
|
key: "setupDraggableWidget",
|
|
34465
35710
|
value: function setupDraggableWidget() {
|
|
34466
35711
|
var _this$config$position6,
|
|
34467
|
-
|
|
35712
|
+
_this11 = this;
|
|
34468
35713
|
var root = this.shadowRoot;
|
|
34469
35714
|
if (!root) return;
|
|
34470
35715
|
var container = root.getElementById('text-chat-button-container');
|
|
@@ -34480,14 +35725,14 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34480
35725
|
|
|
34481
35726
|
// Launcher handles: pill + mobile FAB (suppress the click after a drag).
|
|
34482
35727
|
[root.getElementById('text-chat-button'), root.querySelector('.ttp-mobile-fab')].filter(Boolean).forEach(function (h) {
|
|
34483
|
-
return
|
|
35728
|
+
return _this11._attachUnitDrag(h, {
|
|
34484
35729
|
persist: persist,
|
|
34485
35730
|
key: key,
|
|
34486
35731
|
restCursor: 'grab',
|
|
34487
35732
|
onMoved: function onMoved() {
|
|
34488
|
-
|
|
35733
|
+
_this11._suppressLauncherClick = true;
|
|
34489
35734
|
setTimeout(function () {
|
|
34490
|
-
|
|
35735
|
+
_this11._suppressLauncherClick = false;
|
|
34491
35736
|
}, 0);
|
|
34492
35737
|
}
|
|
34493
35738
|
});
|
|
@@ -34498,7 +35743,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34498
35743
|
['.ttp-header', '.ttp-call-topbar', '.text-interface-top-bar'].map(function (sel) {
|
|
34499
35744
|
return panel.querySelector(sel);
|
|
34500
35745
|
}).filter(Boolean).forEach(function (h) {
|
|
34501
|
-
return
|
|
35746
|
+
return _this11._attachUnitDrag(h, {
|
|
34502
35747
|
persist: persist,
|
|
34503
35748
|
key: key,
|
|
34504
35749
|
restCursor: 'move',
|
|
@@ -34533,13 +35778,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34533
35778
|
}, {
|
|
34534
35779
|
key: "_bindDragResize",
|
|
34535
35780
|
value: function _bindDragResize() {
|
|
34536
|
-
var
|
|
35781
|
+
var _this12 = this;
|
|
34537
35782
|
if (this._dragResizeBound) return;
|
|
34538
35783
|
this._dragResizeBound = true;
|
|
34539
35784
|
window.addEventListener('resize', function () {
|
|
34540
|
-
var
|
|
34541
|
-
|
|
34542
|
-
(
|
|
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);
|
|
34543
35788
|
});
|
|
34544
35789
|
}
|
|
34545
35790
|
}, {
|
|
@@ -34588,9 +35833,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34588
35833
|
}, {
|
|
34589
35834
|
key: "_isDomainErrorVisible",
|
|
34590
35835
|
value: function _isDomainErrorVisible() {
|
|
34591
|
-
var _this$
|
|
34592
|
-
if ((_this$
|
|
34593
|
-
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');
|
|
34594
35839
|
return idleState && ((_idleState$dataset = idleState.dataset) === null || _idleState$dataset === void 0 ? void 0 : _idleState$dataset.domainError) === 'true';
|
|
34595
35840
|
}
|
|
34596
35841
|
}, {
|
|
@@ -34618,7 +35863,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34618
35863
|
}, {
|
|
34619
35864
|
key: "_openMobileCallTextLanding",
|
|
34620
35865
|
value: function _openMobileCallTextLanding() {
|
|
34621
|
-
var
|
|
35866
|
+
var _this13 = this;
|
|
34622
35867
|
if (!this.shadowRoot || window.innerWidth > 768) return;
|
|
34623
35868
|
var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
|
|
34624
35869
|
var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
|
|
@@ -34629,30 +35874,30 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34629
35874
|
// "Back" button: composedPath includes the panel but not #ttpMobileLanding, so it treated
|
|
34630
35875
|
// the click as "outside" and closed the landing immediately (user only saw the FAB again).
|
|
34631
35876
|
var open = function open() {
|
|
34632
|
-
if (!
|
|
34633
|
-
var panel =
|
|
35877
|
+
if (!_this13.shadowRoot || window.innerWidth > 768) return;
|
|
35878
|
+
var panel = _this13.shadowRoot.getElementById('text-chat-panel');
|
|
34634
35879
|
if (panel) {
|
|
34635
35880
|
panel.classList.remove('open');
|
|
34636
|
-
|
|
35881
|
+
_this13.isOpen = false;
|
|
34637
35882
|
}
|
|
34638
|
-
if (
|
|
34639
|
-
|
|
35883
|
+
if (_this13.config.promptAnimation.hideAfterClick) {
|
|
35884
|
+
_this13.hidePrompt();
|
|
34640
35885
|
}
|
|
34641
|
-
var errorBanner =
|
|
35886
|
+
var errorBanner = _this13.shadowRoot.getElementById('ttpMobileLandingError');
|
|
34642
35887
|
if (errorBanner) errorBanner.style.display = 'none';
|
|
34643
|
-
var fab =
|
|
34644
|
-
var landing =
|
|
35888
|
+
var fab = _this13.shadowRoot.querySelector('.ttp-mobile-fab');
|
|
35889
|
+
var landing = _this13.shadowRoot.getElementById('ttpMobileLanding');
|
|
34645
35890
|
if (!fab || !landing) return;
|
|
34646
35891
|
fab.style.display = 'none';
|
|
34647
35892
|
landing.classList.add('active');
|
|
34648
|
-
|
|
35893
|
+
_this13.isMobileLandingOpen = true;
|
|
34649
35894
|
};
|
|
34650
35895
|
queueMicrotask(open);
|
|
34651
35896
|
}
|
|
34652
35897
|
}, {
|
|
34653
35898
|
key: "setupMobileWidgetEvents",
|
|
34654
35899
|
value: function setupMobileWidgetEvents() {
|
|
34655
|
-
var
|
|
35900
|
+
var _this14 = this;
|
|
34656
35901
|
if (!this.shadowRoot) return;
|
|
34657
35902
|
var mobileFab = this.shadowRoot.querySelector('.ttp-mobile-fab');
|
|
34658
35903
|
var mobileLanding = this.shadowRoot.getElementById('ttpMobileLanding');
|
|
@@ -34660,12 +35905,12 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34660
35905
|
var closeMobileLanding = function closeMobileLanding() {
|
|
34661
35906
|
mobileLanding.classList.remove('active');
|
|
34662
35907
|
mobileFab.style.display = '';
|
|
34663
|
-
|
|
35908
|
+
_this14.isMobileLandingOpen = false;
|
|
34664
35909
|
};
|
|
34665
35910
|
mobileFab.onclick = function () {
|
|
34666
35911
|
// A drag just ended — don't open the landing on the trailing click.
|
|
34667
|
-
if (
|
|
34668
|
-
|
|
35912
|
+
if (_this14._suppressLauncherClick) return;
|
|
35913
|
+
_this14._openMobileCallTextLanding();
|
|
34669
35914
|
};
|
|
34670
35915
|
var mobileClose = mobileLanding.querySelector('.ttp-mobile-landing__close');
|
|
34671
35916
|
if (mobileClose) {
|
|
@@ -34675,18 +35920,18 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34675
35920
|
if (mobileCallBtn) {
|
|
34676
35921
|
mobileCallBtn.onclick = function () {
|
|
34677
35922
|
closeMobileLanding();
|
|
34678
|
-
var panel =
|
|
35923
|
+
var panel = _this14.shadowRoot.getElementById('text-chat-panel');
|
|
34679
35924
|
if (panel) {
|
|
34680
35925
|
panel.style.removeProperty('display');
|
|
34681
35926
|
panel.classList.add('open');
|
|
34682
|
-
|
|
35927
|
+
_this14.isOpen = true;
|
|
34683
35928
|
}
|
|
34684
35929
|
mobileFab.style.display = 'none';
|
|
34685
|
-
|
|
35930
|
+
_this14.showVoice();
|
|
34686
35931
|
// Landing already chose "Voice call" — start the call (mic permission / pre-prompt) instead of
|
|
34687
35932
|
// leaving users on a second "Start Call" tap that feels broken.
|
|
34688
35933
|
queueMicrotask(function () {
|
|
34689
|
-
|
|
35934
|
+
_this14.startVoiceCall().catch(function (err) {
|
|
34690
35935
|
console.error('[TTPChatWidget] Mobile landing voice start failed:', err);
|
|
34691
35936
|
});
|
|
34692
35937
|
});
|
|
@@ -34696,20 +35941,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34696
35941
|
if (mobileChatBtn) {
|
|
34697
35942
|
mobileChatBtn.onclick = function () {
|
|
34698
35943
|
closeMobileLanding();
|
|
34699
|
-
var panel =
|
|
35944
|
+
var panel = _this14.shadowRoot.getElementById('text-chat-panel');
|
|
34700
35945
|
if (panel) {
|
|
34701
35946
|
panel.style.removeProperty('display');
|
|
34702
35947
|
panel.classList.add('open');
|
|
34703
|
-
|
|
35948
|
+
_this14.isOpen = true;
|
|
34704
35949
|
}
|
|
34705
35950
|
mobileFab.style.display = 'none';
|
|
34706
|
-
|
|
35951
|
+
_this14.showText();
|
|
34707
35952
|
};
|
|
34708
35953
|
}
|
|
34709
35954
|
|
|
34710
35955
|
// Close mobile landing on outside click
|
|
34711
35956
|
document.addEventListener('click', function (e) {
|
|
34712
|
-
if (!
|
|
35957
|
+
if (!_this14.isMobileLandingOpen) return;
|
|
34713
35958
|
var path = e.composedPath();
|
|
34714
35959
|
if (!path.includes(mobileLanding) && !path.includes(mobileFab)) {
|
|
34715
35960
|
closeMobileLanding();
|
|
@@ -34718,7 +35963,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34718
35963
|
|
|
34719
35964
|
// Close mobile landing on Escape
|
|
34720
35965
|
document.addEventListener('keydown', function (e) {
|
|
34721
|
-
if (e.key === 'Escape' &&
|
|
35966
|
+
if (e.key === 'Escape' && _this14.isMobileLandingOpen) {
|
|
34722
35967
|
closeMobileLanding();
|
|
34723
35968
|
}
|
|
34724
35969
|
});
|
|
@@ -34734,19 +35979,19 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34734
35979
|
_prevIsMobile = nowMobile;
|
|
34735
35980
|
if (nowMobile) {
|
|
34736
35981
|
// Switched desktop → mobile: close desktop panel so only mobile FAB shows
|
|
34737
|
-
if (
|
|
34738
|
-
var
|
|
34739
|
-
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');
|
|
34740
35985
|
if (panel) {
|
|
34741
35986
|
panel.classList.remove('open');
|
|
34742
|
-
|
|
35987
|
+
_this14.isOpen = false;
|
|
34743
35988
|
}
|
|
34744
|
-
var pill = (
|
|
35989
|
+
var pill = (_this14$shadowRoot2 = _this14.shadowRoot) === null || _this14$shadowRoot2 === void 0 ? void 0 : _this14$shadowRoot2.getElementById('text-chat-button');
|
|
34745
35990
|
if (pill) pill.classList.remove('open');
|
|
34746
35991
|
}
|
|
34747
35992
|
} else {
|
|
34748
35993
|
// Switched mobile → desktop: close mobile landing/FAB so only desktop pill shows
|
|
34749
|
-
if (
|
|
35994
|
+
if (_this14.isMobileLandingOpen) {
|
|
34750
35995
|
closeMobileLanding();
|
|
34751
35996
|
}
|
|
34752
35997
|
// Ensure mobile FAB is reset to CSS-controlled state (media query hides it on desktop)
|
|
@@ -34758,10 +36003,10 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34758
36003
|
}, {
|
|
34759
36004
|
key: "setupKeyboardNavigation",
|
|
34760
36005
|
value: function setupKeyboardNavigation() {
|
|
34761
|
-
var
|
|
36006
|
+
var _this15 = this;
|
|
34762
36007
|
document.addEventListener('keydown', function (e) {
|
|
34763
|
-
if (e.key === 'Escape' &&
|
|
34764
|
-
|
|
36008
|
+
if (e.key === 'Escape' && _this15.isOpen) {
|
|
36009
|
+
_this15.togglePanel();
|
|
34765
36010
|
}
|
|
34766
36011
|
});
|
|
34767
36012
|
}
|
|
@@ -34772,7 +36017,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34772
36017
|
}, {
|
|
34773
36018
|
key: "setupPromptAnimation",
|
|
34774
36019
|
value: function setupPromptAnimation() {
|
|
34775
|
-
var
|
|
36020
|
+
var _this16 = this;
|
|
34776
36021
|
if (!this.shadowRoot) return;
|
|
34777
36022
|
var promptConfig = this.config.promptAnimation || {};
|
|
34778
36023
|
// Default to disabled if not specified (enabled === true means explicitly enabled)
|
|
@@ -34802,7 +36047,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34802
36047
|
// Auto-hide after configured seconds (only if widget is closed)
|
|
34803
36048
|
if (!this.isOpen && promptConfig.hideAfterSeconds !== null && promptConfig.hideAfterSeconds > 0) {
|
|
34804
36049
|
this.promptAutoHideTimer = setTimeout(function () {
|
|
34805
|
-
|
|
36050
|
+
_this16.hidePrompt();
|
|
34806
36051
|
}, promptConfig.hideAfterSeconds * 1000);
|
|
34807
36052
|
}
|
|
34808
36053
|
|
|
@@ -34814,7 +36059,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34814
36059
|
// Wrap the callback to also hide pulse rings
|
|
34815
36060
|
this.config.onConversationStart = function () {
|
|
34816
36061
|
// Hide pulse rings when call starts
|
|
34817
|
-
var pulseRings =
|
|
36062
|
+
var pulseRings = _this16.shadowRoot.getElementById('prompt-pulse-rings');
|
|
34818
36063
|
if (pulseRings) pulseRings.style.display = 'none';
|
|
34819
36064
|
|
|
34820
36065
|
// Call original callback if it exists
|
|
@@ -34826,7 +36071,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34826
36071
|
// Also listen to recordingStarted event from SDK if available
|
|
34827
36072
|
if (this.voiceInterface.sdk.voiceSDK) {
|
|
34828
36073
|
this.voiceInterface.sdk.voiceSDK.on('recordingStarted', function () {
|
|
34829
|
-
var pulseRings =
|
|
36074
|
+
var pulseRings = _this16.shadowRoot.getElementById('prompt-pulse-rings');
|
|
34830
36075
|
if (pulseRings) pulseRings.style.display = 'none';
|
|
34831
36076
|
});
|
|
34832
36077
|
}
|
|
@@ -34874,7 +36119,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34874
36119
|
}, {
|
|
34875
36120
|
key: "showPrompt",
|
|
34876
36121
|
value: function showPrompt() {
|
|
34877
|
-
var
|
|
36122
|
+
var _this17 = this;
|
|
34878
36123
|
if (!this.shadowRoot) return;
|
|
34879
36124
|
var promptConfig = this.config.promptAnimation || {};
|
|
34880
36125
|
// Default to enabled if not specified
|
|
@@ -34894,8 +36139,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34894
36139
|
// Function to actually show the elements
|
|
34895
36140
|
var doShow = function doShow() {
|
|
34896
36141
|
// Show prompt bubble (check both shadow root and document for compatibility)
|
|
34897
|
-
var promptBubble =
|
|
34898
|
-
if (!promptBubble &&
|
|
36142
|
+
var promptBubble = _this17.shadowRoot.getElementById('prompt-bubble');
|
|
36143
|
+
if (!promptBubble && _this17.shadowRoot !== document) {
|
|
34899
36144
|
promptBubble = document.getElementById('prompt-bubble');
|
|
34900
36145
|
}
|
|
34901
36146
|
if (promptBubble) {
|
|
@@ -34909,8 +36154,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34909
36154
|
|
|
34910
36155
|
// Show pulse rings if enabled
|
|
34911
36156
|
if (promptConfig.showPulseRings !== false) {
|
|
34912
|
-
var _pulseRings =
|
|
34913
|
-
if (!_pulseRings &&
|
|
36157
|
+
var _pulseRings = _this17.shadowRoot.getElementById('prompt-pulse-rings');
|
|
36158
|
+
if (!_pulseRings && _this17.shadowRoot !== document) {
|
|
34914
36159
|
_pulseRings = document.getElementById('prompt-pulse-rings');
|
|
34915
36160
|
}
|
|
34916
36161
|
if (_pulseRings) {
|
|
@@ -34947,7 +36192,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34947
36192
|
}
|
|
34948
36193
|
// Start new timer
|
|
34949
36194
|
this.promptAutoHideTimer = setTimeout(function () {
|
|
34950
|
-
|
|
36195
|
+
_this17.hidePrompt();
|
|
34951
36196
|
}, promptConfig.hideAfterSeconds * 1000);
|
|
34952
36197
|
}
|
|
34953
36198
|
}
|
|
@@ -34963,7 +36208,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34963
36208
|
}, {
|
|
34964
36209
|
key: "_doTogglePanel",
|
|
34965
36210
|
value: function _doTogglePanel() {
|
|
34966
|
-
var
|
|
36211
|
+
var _this18 = this;
|
|
34967
36212
|
if (!this.shadowRoot) return;
|
|
34968
36213
|
this.isOpen = !this.isOpen;
|
|
34969
36214
|
var panel = this.shadowRoot.getElementById('text-chat-panel');
|
|
@@ -34977,7 +36222,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34977
36222
|
if ((_this$config$position8 = this.config.position) !== null && _this$config$position8 !== void 0 && _this$config$position8.draggable) {
|
|
34978
36223
|
this._applyUnitOffset();
|
|
34979
36224
|
requestAnimationFrame(function () {
|
|
34980
|
-
return
|
|
36225
|
+
return _this18._reclampUnit();
|
|
34981
36226
|
});
|
|
34982
36227
|
}
|
|
34983
36228
|
}
|
|
@@ -34994,7 +36239,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
34994
36239
|
// Panel is opening - hide prompt
|
|
34995
36240
|
this.hidePrompt();
|
|
34996
36241
|
setTimeout(function () {
|
|
34997
|
-
var input =
|
|
36242
|
+
var input = _this18.shadowRoot.getElementById('messageInput');
|
|
34998
36243
|
if (input) input.focus();
|
|
34999
36244
|
}, 100);
|
|
35000
36245
|
} else {
|
|
@@ -35006,13 +36251,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35006
36251
|
// Panel is closing - show prompt (if enabled)
|
|
35007
36252
|
this.showPrompt();
|
|
35008
36253
|
setTimeout(function () {
|
|
35009
|
-
var
|
|
35010
|
-
var promptBubble =
|
|
36254
|
+
var _this18$config$prompt;
|
|
36255
|
+
var promptBubble = _this18.shadowRoot.getElementById('prompt-bubble');
|
|
35011
36256
|
if (promptBubble && promptBubble.style.display === 'none') {
|
|
35012
36257
|
promptBubble.style.display = 'block';
|
|
35013
36258
|
}
|
|
35014
|
-
var pulseRings =
|
|
35015
|
-
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) {
|
|
35016
36261
|
if (pulseRings.style.display === 'none') {
|
|
35017
36262
|
pulseRings.style.display = 'block';
|
|
35018
36263
|
}
|
|
@@ -35204,8 +36449,8 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35204
36449
|
}, {
|
|
35205
36450
|
key: "showBackButtonWarning",
|
|
35206
36451
|
value: function showBackButtonWarning() {
|
|
35207
|
-
var _this$
|
|
35208
|
-
if (!((_this$
|
|
36452
|
+
var _this$voiceInterface7, _this$voiceInterface$;
|
|
36453
|
+
if (!((_this$voiceInterface7 = this.voiceInterface) !== null && _this$voiceInterface7 !== void 0 && _this$voiceInterface7.isActive)) return;
|
|
35209
36454
|
|
|
35210
36455
|
// Show warning message in the voice interface
|
|
35211
36456
|
if ((_this$voiceInterface$ = this.voiceInterface.desktop) !== null && _this$voiceInterface$ !== void 0 && _this$voiceInterface$.showBackButtonWarning) {
|
|
@@ -35280,13 +36525,13 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35280
36525
|
value: function updateConfig(newConfig) {
|
|
35281
36526
|
var _this$config3,
|
|
35282
36527
|
_this$config4,
|
|
35283
|
-
_this$config$
|
|
36528
|
+
_this$config$flavor3,
|
|
35284
36529
|
_this$config$voice8,
|
|
35285
36530
|
_this$config$voice9,
|
|
35286
36531
|
_this$config$voice0,
|
|
35287
36532
|
_this$config$voice1,
|
|
35288
36533
|
_this$config$voice10,
|
|
35289
|
-
|
|
36534
|
+
_this19 = this;
|
|
35290
36535
|
// Deep merge nested objects
|
|
35291
36536
|
var mergedConfig = _objectSpread({}, this.config);
|
|
35292
36537
|
|
|
@@ -35484,7 +36729,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35484
36729
|
// Recreate interfaces with new config (after mergeWithDefaults, so language is current)
|
|
35485
36730
|
// Ensure language is correctly passed - use the merged config value
|
|
35486
36731
|
var currentLanguage = this.config.language || 'en';
|
|
35487
|
-
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';
|
|
35488
36733
|
var voiceConfig = _objectSpread(_objectSpread(_objectSpread({}, this.config), this.config.voice), {}, {
|
|
35489
36734
|
agentName: this.config.agentName,
|
|
35490
36735
|
language: currentLanguage,
|
|
@@ -35504,20 +36749,20 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35504
36749
|
outputBitDepth: ((_this$config$voice10 = this.config.voice) === null || _this$config$voice10 === void 0 ? void 0 : _this$config$voice10.outputBitDepth) || 16,
|
|
35505
36750
|
desktopMinimizedEcommerceStripUi: desktopMinimizedEcommerceStripUi,
|
|
35506
36751
|
onDesktopMinimizedStripCallStart: desktopMinimizedEcommerceStripUi ? function () {
|
|
35507
|
-
var
|
|
35508
|
-
(
|
|
35509
|
-
if (
|
|
35510
|
-
|
|
35511
|
-
|
|
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);
|
|
35512
36757
|
} : undefined,
|
|
35513
36758
|
onDesktopMinimizedStripLauncherRestore: desktopMinimizedEcommerceStripUi ? function () {
|
|
35514
|
-
return
|
|
36759
|
+
return _this19._restoreDesktopEcommerceStripChrome();
|
|
35515
36760
|
} : undefined,
|
|
35516
36761
|
// Pass event callbacks to voice interface (forward only; panel is not auto-minimized on call start)
|
|
35517
36762
|
onConversationStart: function onConversationStart() {
|
|
35518
|
-
if (typeof
|
|
35519
|
-
var
|
|
35520
|
-
(
|
|
36763
|
+
if (typeof _this19.config.onConversationStart === 'function') {
|
|
36764
|
+
var _this19$config;
|
|
36765
|
+
(_this19$config = _this19.config).onConversationStart.apply(_this19$config, arguments);
|
|
35521
36766
|
}
|
|
35522
36767
|
},
|
|
35523
36768
|
onConversationEnd: this.config.onConversationEnd,
|
|
@@ -35526,48 +36771,48 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35526
36771
|
onAudioStoppedPlaying: this.config.onAudioStoppedPlaying,
|
|
35527
36772
|
onSubtitleDisplay: this.config.onSubtitleDisplay,
|
|
35528
36773
|
onCallEnd: function onCallEnd() {
|
|
35529
|
-
var
|
|
35530
|
-
if (
|
|
35531
|
-
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';
|
|
35532
36777
|
if (widgetMode === 'unified') {
|
|
35533
36778
|
if (window.innerWidth <= 768) {
|
|
35534
|
-
var
|
|
35535
|
-
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');
|
|
35536
36781
|
if (panel) {
|
|
35537
36782
|
panel.classList.remove('open');
|
|
35538
|
-
|
|
36783
|
+
_this19.isOpen = false;
|
|
35539
36784
|
}
|
|
35540
|
-
var fab = (
|
|
36785
|
+
var fab = (_this19$shadowRoot2 = _this19.shadowRoot) === null || _this19$shadowRoot2 === void 0 ? void 0 : _this19$shadowRoot2.querySelector('.ttp-mobile-fab');
|
|
35541
36786
|
if (fab) fab.style.display = '';
|
|
35542
36787
|
}
|
|
35543
|
-
|
|
36788
|
+
_this19.showLanding();
|
|
35544
36789
|
}
|
|
35545
36790
|
},
|
|
35546
36791
|
onShowVoice: function onShowVoice() {
|
|
35547
|
-
|
|
36792
|
+
_this19.showVoice();
|
|
35548
36793
|
},
|
|
35549
36794
|
onShowLanding: function onShowLanding() {
|
|
35550
|
-
|
|
36795
|
+
_this19.showLanding();
|
|
35551
36796
|
},
|
|
35552
36797
|
onDisclaimerDeclined: function onDisclaimerDeclined() {
|
|
35553
|
-
var
|
|
35554
|
-
if (
|
|
35555
|
-
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';
|
|
35556
36801
|
if (widgetMode === 'voice-only') {
|
|
35557
|
-
|
|
36802
|
+
_this19.showVoice();
|
|
35558
36803
|
return;
|
|
35559
36804
|
}
|
|
35560
36805
|
if (widgetMode !== 'unified') return;
|
|
35561
36806
|
if (window.innerWidth <= 768) {
|
|
35562
|
-
var
|
|
35563
|
-
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');
|
|
35564
36809
|
if (panel) {
|
|
35565
36810
|
panel.classList.remove('open');
|
|
35566
|
-
|
|
36811
|
+
_this19.isOpen = false;
|
|
35567
36812
|
}
|
|
35568
|
-
|
|
36813
|
+
_this19._openMobileCallTextLanding();
|
|
35569
36814
|
} else {
|
|
35570
|
-
|
|
36815
|
+
_this19.showLanding();
|
|
35571
36816
|
}
|
|
35572
36817
|
},
|
|
35573
36818
|
direction: this.getEffectiveTextDirection()
|
|
@@ -35614,9 +36859,9 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35614
36859
|
}, {
|
|
35615
36860
|
key: "_initEcommerceVoiceStrip",
|
|
35616
36861
|
value: function _initEcommerceVoiceStrip() {
|
|
35617
|
-
var
|
|
36862
|
+
var _this20 = this,
|
|
35618
36863
|
_this$config$position9,
|
|
35619
|
-
_this$
|
|
36864
|
+
_this$voiceInterface8;
|
|
35620
36865
|
var flavor = this.config.flavor && _typeof(this.config.flavor) === 'object' ? this.config.flavor : null;
|
|
35621
36866
|
if (window.innerWidth <= 768) return;
|
|
35622
36867
|
if (!flavor || flavor.callView !== 'minimized') return;
|
|
@@ -35637,34 +36882,44 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35637
36882
|
endCallButtonColor: v.endCallButtonColor || '#ef4444'
|
|
35638
36883
|
},
|
|
35639
36884
|
getVoiceUiState: function getVoiceUiState() {
|
|
35640
|
-
var
|
|
36885
|
+
var _this20$voiceInterfac, _this20$voiceInterfac2, _this20$voiceInterfac3;
|
|
35641
36886
|
return {
|
|
35642
|
-
isMicMuted: !!((
|
|
35643
|
-
isPaused: !!((
|
|
35644
|
-
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)
|
|
35645
36890
|
};
|
|
35646
36891
|
},
|
|
35647
36892
|
onAbout: function onAbout() {
|
|
35648
|
-
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
|
+
});
|
|
35649
36904
|
},
|
|
35650
36905
|
onHangup: function onHangup() {
|
|
35651
|
-
if (
|
|
36906
|
+
if (_this20.voiceInterface) _this20.voiceInterface.endVoiceCall();
|
|
35652
36907
|
},
|
|
35653
36908
|
onToggleMute: function onToggleMute() {
|
|
35654
|
-
if (
|
|
36909
|
+
if (_this20.voiceInterface) _this20.voiceInterface.toggleMute();
|
|
35655
36910
|
strip.syncFromVoice();
|
|
35656
36911
|
},
|
|
35657
36912
|
onTogglePause: function onTogglePause() {
|
|
35658
|
-
if (
|
|
36913
|
+
if (_this20.voiceInterface) _this20.voiceInterface.togglePause();
|
|
35659
36914
|
strip.syncFromVoice();
|
|
35660
36915
|
},
|
|
35661
36916
|
onToggleSpeaker: function onToggleSpeaker() {
|
|
35662
|
-
if (
|
|
36917
|
+
if (_this20.voiceInterface) _this20.voiceInterface.toggleSpeaker();
|
|
35663
36918
|
strip.syncFromVoice();
|
|
35664
36919
|
},
|
|
35665
36920
|
onSendText: function onSendText(text) {
|
|
35666
|
-
var
|
|
35667
|
-
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;
|
|
35668
36923
|
if (voiceSDK && typeof voiceSDK.sendMessage === 'function') {
|
|
35669
36924
|
voiceSDK.sendMessage({
|
|
35670
36925
|
t: 'text_inject',
|
|
@@ -35674,6 +36929,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35674
36929
|
}
|
|
35675
36930
|
});
|
|
35676
36931
|
this._ecommerceVoiceStrip = strip;
|
|
36932
|
+
strip.bindRecipeStore(this.getRecipeStore());
|
|
35677
36933
|
|
|
35678
36934
|
// Make the strip draggable too when position.draggable is enabled.
|
|
35679
36935
|
if ((_this$config$position9 = this.config.position) !== null && _this$config$position9 !== void 0 && _this$config$position9.draggable) {
|
|
@@ -35681,7 +36937,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35681
36937
|
}
|
|
35682
36938
|
|
|
35683
36939
|
// Show strip when conversation starts
|
|
35684
|
-
var agentSDK = (_this$
|
|
36940
|
+
var agentSDK = (_this$voiceInterface8 = this.voiceInterface) === null || _this$voiceInterface8 === void 0 ? void 0 : _this$voiceInterface8.sdk;
|
|
35685
36941
|
if (agentSDK) {
|
|
35686
36942
|
var origConvStart = agentSDK.onConversationStart;
|
|
35687
36943
|
agentSDK.onConversationStart = function () {
|
|
@@ -35719,7 +36975,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35719
36975
|
var _this$voiceInterface$2;
|
|
35720
36976
|
var origOnCallEnd = this.voiceInterface.config.onCallEnd;
|
|
35721
36977
|
this.voiceInterface.config.onCallEnd = function () {
|
|
35722
|
-
|
|
36978
|
+
_this20._restoreDesktopEcommerceStripChrome();
|
|
35723
36979
|
if (typeof origOnCallEnd === 'function') origOnCallEnd();
|
|
35724
36980
|
};
|
|
35725
36981
|
|
|
@@ -35843,7 +37099,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35843
37099
|
key: "injectData",
|
|
35844
37100
|
value: (function () {
|
|
35845
37101
|
var _injectData = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee6(data) {
|
|
35846
|
-
var _this$
|
|
37102
|
+
var _this$voiceInterface9;
|
|
35847
37103
|
var options,
|
|
35848
37104
|
voiceSDK,
|
|
35849
37105
|
ack,
|
|
@@ -35868,7 +37124,7 @@ var TTPChatWidget = /*#__PURE__*/function () {
|
|
|
35868
37124
|
throw new Error('Voice call is not active');
|
|
35869
37125
|
case 2:
|
|
35870
37126
|
// Check if SDK is available
|
|
35871
|
-
voiceSDK = (_this$
|
|
37127
|
+
voiceSDK = (_this$voiceInterface9 = this.voiceInterface) === null || _this$voiceInterface9 === void 0 ? void 0 : _this$voiceInterface9.getVoiceSDK();
|
|
35872
37128
|
if (voiceSDK) {
|
|
35873
37129
|
_context6.n = 3;
|
|
35874
37130
|
break;
|
|
@@ -36902,7 +38158,9 @@ var VoiceInterface = /*#__PURE__*/function () {
|
|
|
36902
38158
|
flavor: config.flavor,
|
|
36903
38159
|
// Shared client-tool handler map from TTPChatWidget (so the same handler
|
|
36904
38160
|
// map serves both voice and text channels).
|
|
36905
|
-
sharedToolHandlers: config.sharedToolHandlers
|
|
38161
|
+
sharedToolHandlers: config.sharedToolHandlers,
|
|
38162
|
+
// Persisted in-call settings provider (voice speed / response length).
|
|
38163
|
+
callSettingsProvider: config.callSettingsProvider
|
|
36906
38164
|
});
|
|
36907
38165
|
|
|
36908
38166
|
// Initialize modules with context (delegation pattern)
|
|
@@ -41278,6 +42536,22 @@ var Templates = /*#__PURE__*/function () {
|
|
|
41278
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>");
|
|
41279
42537
|
}
|
|
41280
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
|
+
|
|
41281
42555
|
/**
|
|
41282
42556
|
* Generate HTML for voice interface.
|
|
41283
42557
|
* Automatically detects mobile vs desktop based on voiceInterface.isMobile
|
|
@@ -41308,7 +42582,7 @@ var Templates = /*#__PURE__*/function () {
|
|
|
41308
42582
|
var transcriptPlaceholder = this.t('transcriptWillAppear') || '';
|
|
41309
42583
|
var transcriptDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForTranscriptSnippet)(transcriptPlaceholder, this.config);
|
|
41310
42584
|
var voiceInputDir = (0,_rtlText_js__WEBPACK_IMPORTED_MODULE_0__.dirForAssistantStreamingText)(this.config);
|
|
41311
|
-
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>");
|
|
41312
42586
|
}
|
|
41313
42587
|
|
|
41314
42588
|
/**
|
|
@@ -41325,7 +42599,7 @@ var Templates = /*#__PURE__*/function () {
|
|
|
41325
42599
|
var headerAvatarUrl = resolveIdleHeaderAvatarUrl(this.config);
|
|
41326
42600
|
var mobileAvatarInner = headerAvatarUrl ? "<img src=\"".concat(escapeHtmlAttr(headerAvatarUrl), "\" alt=\"\" class=\"voice-avatar-img\" />") : '🤖';
|
|
41327
42601
|
var mobileAvatarClass = headerAvatarUrl ? 'voice-avatar voice-avatar--image' : 'voice-avatar';
|
|
41328
|
-
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) {
|
|
41329
42603
|
return "<div class=\"mobile-waveform-bar\" data-index=\"".concat(i, "\"></div>");
|
|
41330
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>");
|
|
41331
42605
|
}
|
|
@@ -42174,7 +43448,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42174
43448
|
"aboutTitle": "About",
|
|
42175
43449
|
"aboutVersion": "SDK version",
|
|
42176
43450
|
"aboutConversationId": "Last conversation ID",
|
|
42177
|
-
"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"
|
|
42178
43459
|
},
|
|
42179
43460
|
"he": {
|
|
42180
43461
|
"landingTitle": "איך תרצה לתקשר?",
|
|
@@ -42211,7 +43492,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42211
43492
|
"aboutTitle": "אודות",
|
|
42212
43493
|
"aboutVersion": "גרסת SDK",
|
|
42213
43494
|
"aboutConversationId": "מזהה שיחה אחרון",
|
|
42214
|
-
"aboutNoConversation": "אין שיחה עדיין"
|
|
43495
|
+
"aboutNoConversation": "אין שיחה עדיין",
|
|
43496
|
+
"settingsTitle": "הגדרות שיחה",
|
|
43497
|
+
"settingsVoiceSpeed": "מהירות דיבור",
|
|
43498
|
+
"settingsResponseLength": "אורך תשובות",
|
|
43499
|
+
"lengthDetailed": "מפורט",
|
|
43500
|
+
"lengthNormal": "רגיל",
|
|
43501
|
+
"lengthBrief": "קצר",
|
|
43502
|
+
"lengthVeryBrief": "קצר מאוד"
|
|
42215
43503
|
},
|
|
42216
43504
|
"ar": {
|
|
42217
43505
|
"landingTitle": "كيف تريد التواصل؟",
|
|
@@ -42248,7 +43536,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42248
43536
|
"aboutTitle": "حول",
|
|
42249
43537
|
"aboutVersion": "إصدار SDK",
|
|
42250
43538
|
"aboutConversationId": "معرّف آخر محادثة",
|
|
42251
|
-
"aboutNoConversation": "لا توجد محادثة بعد"
|
|
43539
|
+
"aboutNoConversation": "لا توجد محادثة بعد",
|
|
43540
|
+
"settingsTitle": "إعدادات المكالمة",
|
|
43541
|
+
"settingsVoiceSpeed": "سرعة الصوت",
|
|
43542
|
+
"settingsResponseLength": "طول الإجابات",
|
|
43543
|
+
"lengthDetailed": "مفصّل",
|
|
43544
|
+
"lengthNormal": "عادي",
|
|
43545
|
+
"lengthBrief": "مختصر",
|
|
43546
|
+
"lengthVeryBrief": "مختصر جداً"
|
|
42252
43547
|
},
|
|
42253
43548
|
"ru": {
|
|
42254
43549
|
"landingTitle": "Как вы хотите общаться?",
|
|
@@ -42285,7 +43580,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42285
43580
|
"aboutTitle": "О приложении",
|
|
42286
43581
|
"aboutVersion": "Версия SDK",
|
|
42287
43582
|
"aboutConversationId": "ID последнего разговора",
|
|
42288
|
-
"aboutNoConversation": "Разговоров пока нет"
|
|
43583
|
+
"aboutNoConversation": "Разговоров пока нет",
|
|
43584
|
+
"settingsTitle": "Настройки звонка",
|
|
43585
|
+
"settingsVoiceSpeed": "Скорость речи",
|
|
43586
|
+
"settingsResponseLength": "Длина ответов",
|
|
43587
|
+
"lengthDetailed": "Подробно",
|
|
43588
|
+
"lengthNormal": "Обычно",
|
|
43589
|
+
"lengthBrief": "Кратко",
|
|
43590
|
+
"lengthVeryBrief": "Очень кратко"
|
|
42289
43591
|
},
|
|
42290
43592
|
"es": {
|
|
42291
43593
|
"landingTitle": "¿Cómo te gustaría comunicarte?",
|
|
@@ -42322,7 +43624,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42322
43624
|
"aboutTitle": "Acerca de",
|
|
42323
43625
|
"aboutVersion": "Versión del SDK",
|
|
42324
43626
|
"aboutConversationId": "ID de última conversación",
|
|
42325
|
-
"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"
|
|
42326
43635
|
},
|
|
42327
43636
|
"fr": {
|
|
42328
43637
|
"landingTitle": "Comment souhaitez-vous communiquer?",
|
|
@@ -42359,7 +43668,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42359
43668
|
"aboutTitle": "À propos",
|
|
42360
43669
|
"aboutVersion": "Version du SDK",
|
|
42361
43670
|
"aboutConversationId": "ID de la dernière conversation",
|
|
42362
|
-
"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"
|
|
42363
43679
|
},
|
|
42364
43680
|
"de": {
|
|
42365
43681
|
"landingTitle": "Wie möchten Sie kommunizieren?",
|
|
@@ -42396,7 +43712,14 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
42396
43712
|
"aboutTitle": "Über",
|
|
42397
43713
|
"aboutVersion": "SDK-Version",
|
|
42398
43714
|
"aboutConversationId": "Letzte Konversations-ID",
|
|
42399
|
-
"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"
|
|
42400
43723
|
}
|
|
42401
43724
|
});
|
|
42402
43725
|
|