From 900e7935ebdc35a62baa3981435b756e4477226d Mon Sep 17 00:00:00 2001 From: Miroslav Pejic Date: Wed, 6 Aug 2025 18:21:43 +0200 Subject: [PATCH] [mirotalksfu] - improve Widgets --- app/src/Server.js | 2 +- package-lock.json | 124 ++--- package.json | 6 +- public/css/widgets/Support.css | 849 +++++++++++++++++++++++++++++++++ public/js/Brand.js | 2 +- public/js/Room.js | 4 +- public/js/RoomClient.js | 2 +- public/js/Widget.js | 726 ++++++++++++++++++++++++++++ widgets/example-0.html | 19 + widgets/example-1.html | 751 +---------------------------- widgets/example-2.html | 47 +- widgets/example-3.html | 835 +++++++++++++++++++++++++++++++- widgets/example-4.html | 17 + widgets/example-5.html | 36 ++ widgets/maker.html | 702 +++++++++++++++++++++++++++ 15 files changed, 3285 insertions(+), 837 deletions(-) create mode 100644 public/css/widgets/Support.css create mode 100644 public/js/Widget.js create mode 100644 widgets/example-0.html create mode 100644 widgets/example-4.html create mode 100644 widgets/example-5.html create mode 100644 widgets/maker.html diff --git a/app/src/Server.js b/app/src/Server.js index a0670f66..fdc6fb20 100644 --- a/app/src/Server.js +++ b/app/src/Server.js @@ -64,7 +64,7 @@ dev dependencies: { * @license For commercial or closed source, contact us at license.mirotalk@gmail.com or purchase directly via CodeCanyon * @license CodeCanyon: https://codecanyon.net/item/mirotalk-sfu-webrtc-realtime-video-conferences/40769970 * @author Miroslav Pejic - miroslav.pejic.85@gmail.com - * @version 1.9.21 + * @version 1.9.22 * */ diff --git a/package-lock.json b/package-lock.json index b52f2ef1..7ce5b8b2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,18 @@ { "name": "mirotalksfu", - "version": "1.9.21", + "version": "1.9.22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "mirotalksfu", - "version": "1.9.21", + "version": "1.9.22", "license": "AGPL-3.0", "dependencies": { "@aws-sdk/client-s3": "^3.859.0", "@aws-sdk/lib-storage": "^3.859.0", "@mattermost/client": "10.9.0", - "@ngrok/ngrok": "1.5.1", + "@ngrok/ngrok": "1.5.2", "@sentry/node": "^10.1.0", "async-mutex": "^0.5.0", "axios": "^1.11.0", @@ -36,7 +36,7 @@ "mediasoup": "3.18.0", "mediasoup-client": "3.14.0", "nodemailer": "^7.0.5", - "openai": "^5.11.0", + "openai": "^5.12.0", "qs": "6.14.0", "sanitize-filename": "^1.6.3", "socket.io": "4.8.1", @@ -2883,33 +2883,33 @@ } }, "node_modules/@ngrok/ngrok": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok/-/ngrok-1.5.1.tgz", - "integrity": "sha512-sfcgdpiAJHqmuO3e6QjQGbavIrR3E72do/NAsnGhm+7SGstLj1aM3Sd8mkfTORb2Hj7ATMuoBYuED5ylKuRQCg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok/-/ngrok-1.5.2.tgz", + "integrity": "sha512-gN7KKdLTKer+wBSk9s9eDx53MUFdcnXNHsXxiC5sJLLD5HY9JRMSn6UzcCqnk7IgeIgCgw5h1k6YDqhjx6lmtg==", "license": "(MIT OR Apache-2.0)", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@ngrok/ngrok-android-arm64": "1.5.1", - "@ngrok/ngrok-darwin-arm64": "1.5.1", - "@ngrok/ngrok-darwin-universal": "1.5.1", - "@ngrok/ngrok-darwin-x64": "1.5.1", - "@ngrok/ngrok-freebsd-x64": "1.5.1", - "@ngrok/ngrok-linux-arm-gnueabihf": "1.5.1", - "@ngrok/ngrok-linux-arm64-gnu": "1.5.1", - "@ngrok/ngrok-linux-arm64-musl": "1.5.1", - "@ngrok/ngrok-linux-x64-gnu": "1.5.1", - "@ngrok/ngrok-linux-x64-musl": "1.5.1", - "@ngrok/ngrok-win32-arm64-msvc": "1.5.1", - "@ngrok/ngrok-win32-ia32-msvc": "1.5.1", - "@ngrok/ngrok-win32-x64-msvc": "1.5.1" + "@ngrok/ngrok-android-arm64": "1.5.2", + "@ngrok/ngrok-darwin-arm64": "1.5.2", + "@ngrok/ngrok-darwin-universal": "1.5.2", + "@ngrok/ngrok-darwin-x64": "1.5.2", + "@ngrok/ngrok-freebsd-x64": "1.5.2", + "@ngrok/ngrok-linux-arm-gnueabihf": "1.5.2", + "@ngrok/ngrok-linux-arm64-gnu": "1.5.2", + "@ngrok/ngrok-linux-arm64-musl": "1.5.2", + "@ngrok/ngrok-linux-x64-gnu": "1.5.2", + "@ngrok/ngrok-linux-x64-musl": "1.5.2", + "@ngrok/ngrok-win32-arm64-msvc": "1.5.2", + "@ngrok/ngrok-win32-ia32-msvc": "1.5.2", + "@ngrok/ngrok-win32-x64-msvc": "1.5.2" } }, "node_modules/@ngrok/ngrok-android-arm64": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-android-arm64/-/ngrok-android-arm64-1.5.1.tgz", - "integrity": "sha512-2Tokwi5GVWNLw3JEoM0Ieb/ypALniZu6fciUTgpuByutbKxOjvahD4fYOKwW3KMdV9bCb3XGGtWJCZXfRPPq1g==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-android-arm64/-/ngrok-android-arm64-1.5.2.tgz", + "integrity": "sha512-v81VbxxAgg2W7jbjhEcn8K9R2aUf0h1AuTx+8tDlw3L4H1YEmbmllIpBAGgMjHRBxLZKOo5GBi0k7oS+VRM5TA==", "cpu": [ "arm64" ], @@ -2923,9 +2923,9 @@ } }, "node_modules/@ngrok/ngrok-darwin-arm64": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-darwin-arm64/-/ngrok-darwin-arm64-1.5.1.tgz", - "integrity": "sha512-HNOhrPDP+nJJY7Bh45DOeh6jmcGASWINGbUuseZM0C8psQMp7crPywjRh0inkRegUrb4K8y06sfmgt2fmsF6jQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-darwin-arm64/-/ngrok-darwin-arm64-1.5.2.tgz", + "integrity": "sha512-8CVzS9AveYpNhWbydm7cJ6XqmVg29/VRKF15l4kJ2djlNoJxuGSibgM9A627dWRdnJyj5uhmU3VzsgeU8t+/3g==", "cpu": [ "arm64" ], @@ -2939,9 +2939,9 @@ } }, "node_modules/@ngrok/ngrok-darwin-universal": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-darwin-universal/-/ngrok-darwin-universal-1.5.1.tgz", - "integrity": "sha512-EsMxYC/tY+ZqhjbeZtVq5MFIuD8SEPgAlHINEszsHd8ZRICc2U9Xl15CbDrew3pcfEg/ZVFrOH9CyC4aZ/V/cA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-darwin-universal/-/ngrok-darwin-universal-1.5.2.tgz", + "integrity": "sha512-mEMH1OxN6RxnqRSWb4xY9RqbtdlCpv+WlRKxq4lVy8JVsxEyFNnzVQ0jn+iuiy981jCXjokctzJeGMvECuSQBQ==", "license": "MIT", "optional": true, "os": [ @@ -2952,9 +2952,9 @@ } }, "node_modules/@ngrok/ngrok-darwin-x64": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-darwin-x64/-/ngrok-darwin-x64-1.5.1.tgz", - "integrity": "sha512-H/x1BsYpAoTMhOtv4oYvwY6WHqbY0MsJ1XFcJQgrpAIjgmYqlwsnsUMHvEdBB/KY9kXF9DPgKUdRMfJwUIpwGA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-darwin-x64/-/ngrok-darwin-x64-1.5.2.tgz", + "integrity": "sha512-rGdcADw4NtMSU7SHUTly7uvMVYX6eMeMCppKyL5g3CSlEQntKf3AWs/89ah2TBWJA2WVl0UgGLkXp4xs1tg9eQ==", "cpu": [ "x64" ], @@ -2968,9 +2968,9 @@ } }, "node_modules/@ngrok/ngrok-freebsd-x64": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-freebsd-x64/-/ngrok-freebsd-x64-1.5.1.tgz", - "integrity": "sha512-dY2W6HUv7e2xkpdfVj7fIk+5qmvrC7kVu6PJWJ8/rshW1FrU7qMcpnU53JvoQJRZzUf5k8xMNdx30zai/8mqYA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-freebsd-x64/-/ngrok-freebsd-x64-1.5.2.tgz", + "integrity": "sha512-WgY54qUekaUGa5+lFvzYUMjlzf22IEXuZHhxnzJM2/gMqa7gjU8N5W4U8XNDjVW/oz6DekrzIjuoAEPO+2icDg==", "cpu": [ "x64" ], @@ -2984,9 +2984,9 @@ } }, "node_modules/@ngrok/ngrok-linux-arm-gnueabihf": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-arm-gnueabihf/-/ngrok-linux-arm-gnueabihf-1.5.1.tgz", - "integrity": "sha512-JvbI/IIycw4Qq02ysyOBsSK5E0bZDgRqXSslHLTwuDAfw14lmrq2U0QkBeEOL8qwJ7wCwCH1PEOJacUyrqa9bg==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-arm-gnueabihf/-/ngrok-linux-arm-gnueabihf-1.5.2.tgz", + "integrity": "sha512-azMxr/TGEeFU4JAUbSu5MO2aZEvdq+TzcxiLw6d+yhdEtNAjDW9TOyCczTrIZPOG5fP8G3lcCd8TP7mVIWdOnw==", "cpu": [ "arm" ], @@ -3000,9 +3000,9 @@ } }, "node_modules/@ngrok/ngrok-linux-arm64-gnu": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-arm64-gnu/-/ngrok-linux-arm64-gnu-1.5.1.tgz", - "integrity": "sha512-yLFAlqTYYvH7QRg589HJarQGw1QrKQZcHiw0gm175eCqc+jpUG/Zcf8wohCTIJVLylMIzjDzVFSUsXC7UtMJdQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-arm64-gnu/-/ngrok-linux-arm64-gnu-1.5.2.tgz", + "integrity": "sha512-79eFCxio4rM0ICRBXx/CVvbXDeWk1Jxr7szkezEYWtHaL+gXivrtS1QjtMnJpGY1GJlLTQL+49w2lGydqPOJQA==", "cpu": [ "arm64" ], @@ -3016,9 +3016,9 @@ } }, "node_modules/@ngrok/ngrok-linux-arm64-musl": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-arm64-musl/-/ngrok-linux-arm64-musl-1.5.1.tgz", - "integrity": "sha512-momB/ZjjrxaGYOZ3YPAw1kT4DAfWT1x3dAHL0YoSVfNCpc8Fw0189ZAcxGn0hUFqkGDmSARS9o8b7hYd1b41oA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-arm64-musl/-/ngrok-linux-arm64-musl-1.5.2.tgz", + "integrity": "sha512-ou9Z7iPQJIQ0RX5bdBhb3y7GwYRt+X0G9tenyRzKLXXvs0XfUUcg/23aBP61hmdRvBq7xpliV1PnvEVBgUIYMg==", "cpu": [ "arm64" ], @@ -3032,9 +3032,9 @@ } }, "node_modules/@ngrok/ngrok-linux-x64-gnu": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-x64-gnu/-/ngrok-linux-x64-gnu-1.5.1.tgz", - "integrity": "sha512-fmMaz0b1Ry2CDLLn0mV8b9nLxqm0taQ2jYyn+C9OrazYNMT4XYYDKRQSm4UEaNoakdnoH+f2FsrWi/712GFxAQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-x64-gnu/-/ngrok-linux-x64-gnu-1.5.2.tgz", + "integrity": "sha512-VI1mmtl3Ie5uXTVAR9thPiMNMsCWeqkjBUbHAyk2vZ2OXR4Vs2DGjOPXK+wTl/hjF29FXoxunjhMy6caF9ht0Q==", "cpu": [ "x64" ], @@ -3048,9 +3048,9 @@ } }, "node_modules/@ngrok/ngrok-linux-x64-musl": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-x64-musl/-/ngrok-linux-x64-musl-1.5.1.tgz", - "integrity": "sha512-6Ajl9wpJSlvukl4WrkIw+WxVwAr7WTGnE35Voec6CERWtKMsO/F+BOSu3pfAa6iwxGK//JBpsTT1IwLLw7b2xQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-linux-x64-musl/-/ngrok-linux-x64-musl-1.5.2.tgz", + "integrity": "sha512-F4j9EyC/0R3IgYSd+OER4bC8bxuBubvj33e24GvQnRF/IQaKhpybkvQbz54fnvsL7y0j2BB42NAIm2CFtk7tCw==", "cpu": [ "x64" ], @@ -3064,9 +3064,9 @@ } }, "node_modules/@ngrok/ngrok-win32-arm64-msvc": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-win32-arm64-msvc/-/ngrok-win32-arm64-msvc-1.5.1.tgz", - "integrity": "sha512-JUH2yZxDPQGmQNT1d2KIu64u2k/R6uG1kEIXjcbsoff37v9aI6nUlzldRWB/wFSYkpZ4W/EuovM4Epar+fQOxQ==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-win32-arm64-msvc/-/ngrok-win32-arm64-msvc-1.5.2.tgz", + "integrity": "sha512-0OMXNjWElM1MQX7lMBnpRtafS9+3ybauqGD4m2dZcIm6hFvexsJFwNgx0mCa5aKxe2mQ4zNarEUd+SqG2Aa4/g==", "cpu": [ "arm64" ], @@ -3080,9 +3080,9 @@ } }, "node_modules/@ngrok/ngrok-win32-ia32-msvc": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-win32-ia32-msvc/-/ngrok-win32-ia32-msvc-1.5.1.tgz", - "integrity": "sha512-zS1JsMTJHnY+lPJFUwKnB5fzPm4GZCKeeZLehHrXP0LpQaKN8Y/vywqDGhuC0WtymvWE88+oreMV/6hQdviLSA==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-win32-ia32-msvc/-/ngrok-win32-ia32-msvc-1.5.2.tgz", + "integrity": "sha512-hdvhnr7Br4XhUblpW67v5XP6FyoQwJ2xSbwas4KW4hZ3F4cw0m6sqXpssRfmqg3/5HJony1H5B2jLi0x4J7uOw==", "cpu": [ "ia32" ], @@ -3096,9 +3096,9 @@ } }, "node_modules/@ngrok/ngrok-win32-x64-msvc": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@ngrok/ngrok-win32-x64-msvc/-/ngrok-win32-x64-msvc-1.5.1.tgz", - "integrity": "sha512-HegRwV9Gchh4p7K7sC6SPpWmFRwDEgwPByrb8tkuWDyP+EWNgpt3GKp8OAIK2xdWWHnN5VIwMa9u3COE/e5S8w==", + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@ngrok/ngrok-win32-x64-msvc/-/ngrok-win32-x64-msvc-1.5.2.tgz", + "integrity": "sha512-aHuMiRti9Taow9DlYLGVmu9CXtXD/v4CBQWpZlmt7VGuK1KsTWWLaGIBFVp6UXnyW87b0A+KC69Kn/Xjylw+sg==", "cpu": [ "x64" ], @@ -8544,9 +8544,9 @@ } }, "node_modules/openai": { - "version": "5.11.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-5.11.0.tgz", - "integrity": "sha512-+AuTc5pVjlnTuA9zvn8rA/k+1RluPIx9AD4eDcnutv6JNwHHZxIhkFy+tmMKCvmMFDQzfA/r1ujvPWB19DQkYg==", + "version": "5.12.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-5.12.0.tgz", + "integrity": "sha512-vUdt02xiWgOHiYUmW0Hj1Qu9OKAiVQu5Bd547ktVCiMKC1BkB5L3ImeEnCyq3WpRKR6ZTaPgekzqdozwdPs7Lg==", "license": "Apache-2.0", "bin": { "openai": "bin/cli" diff --git a/package.json b/package.json index 8dc37daf..0d24be92 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mirotalksfu", - "version": "1.9.21", + "version": "1.9.22", "description": "WebRTC SFU browser-based video calls", "main": "Server.js", "scripts": { @@ -60,7 +60,7 @@ "@aws-sdk/client-s3": "^3.859.0", "@aws-sdk/lib-storage": "^3.859.0", "@mattermost/client": "10.9.0", - "@ngrok/ngrok": "1.5.1", + "@ngrok/ngrok": "1.5.2", "@sentry/node": "^10.1.0", "async-mutex": "^0.5.0", "axios": "^1.11.0", @@ -84,7 +84,7 @@ "mediasoup": "3.18.0", "mediasoup-client": "3.14.0", "nodemailer": "^7.0.5", - "openai": "^5.11.0", + "openai": "^5.12.0", "qs": "6.14.0", "sanitize-filename": "^1.6.3", "socket.io": "4.8.1", diff --git a/public/css/widgets/Support.css b/public/css/widgets/Support.css new file mode 100644 index 00000000..31e064bd --- /dev/null +++ b/public/css/widgets/Support.css @@ -0,0 +1,849 @@ +/* Keyframes */ +@keyframes pulse { + 0% { + transform: scale(1); + opacity: 1; + } + 50% { + transform: scale(1.1); + opacity: 0.8; + } + 100% { + transform: scale(1); + opacity: 1; + } +} + +@keyframes fadeInDown { + from { + opacity: 0; + transform: translateY(-10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes fadeInUp { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Main Widget Styles */ +.mirotalk-support-widget { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: linear-gradient(135deg, #1f1f2e 0%, #2a2a3e 100%); + color: #fff; + padding: 24px; + border-radius: 20px; + width: 320px; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); + position: fixed; + transition: all 0.3s ease; + border: 1px solid rgba(255, 255, 255, 0.1); + z-index: 9999; +} + +/* Light Theme Overrides */ +.mirotalk-support-widget.light-theme { + background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); + color: #333; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); +} + +/* Position Classes */ +.mirotalk-support-widget.bottom-right, +.mirotalk-minimized-btn.bottom-right, +.mirotalk-reopener-btn.bottom-right { + bottom: 20px; + right: 20px; +} + +.mirotalk-support-widget.bottom-left, +.mirotalk-minimized-btn.bottom-left, +.mirotalk-reopener-btn.bottom-left { + bottom: 20px; + left: 20px; +} + +.mirotalk-support-widget.top-right, +.mirotalk-minimized-btn.top-right, +.mirotalk-reopener-btn.top-right { + top: 20px; + right: 20px; +} + +.mirotalk-support-widget.top-left, +.mirotalk-minimized-btn.top-left, +.mirotalk-reopener-btn.top-left { + top: 20px; + left: 20px; +} + +/* Widget Hover Effects */ +.mirotalk-support-widget:hover { + transform: translateY(-2px); + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5); +} + +.mirotalk-support-widget.light-theme:hover { + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2); +} + +/* Online Indicator */ +.mirotalk-support-widget .online-indicator { + display: flex; + align-items: center; + margin-bottom: 16px; + animation: fadeInDown 0.6s ease; +} + +.mirotalk-minimized-btn .status-dot, +.mirotalk-support-widget .status-dot { + width: 12px; + height: 12px; + border-radius: 50%; + margin-right: 8px; +} + +.mirotalk-minimized-btn .status-dot.online, +.mirotalk-support-widget .status-dot.online { + background: #00e676; + box-shadow: 0 0 8px rgba(0, 230, 118, 0.4); + animation: pulse 2s infinite; +} + +.mirotalk-minimized-btn .status-dot.offline, +.mirotalk-support-widget .status-dot.offline { + background: #ff5252; + box-shadow: 0 0 8px rgba(255, 82, 82, 0.4); +} + +.mirotalk-support-widget .online-text { + color: #00e676; + font-weight: 600; + font-size: 14px; +} + +.mirotalk-support-widget .offline-text { + color: #ff5252; + font-weight: 600; + font-size: 14px; +} + +/* Widget Controls */ +.mirotalk-support-widget .widget-controls { + display: flex; + align-items: center; + gap: 8px; + margin-left: auto; +} + +.mirotalk-support-widget .minimize-btn { + background: rgba(255, 255, 255, 0.1); + border: none; + color: #aaa; + cursor: pointer; + padding: 4px 6px; + border-radius: 4px; + transition: all 0.2s ease; + display: flex; + align-items: center; + justify-content: center; +} + +.mirotalk-support-widget.light-theme .minimize-btn { + background: rgba(0, 0, 0, 0.05); + color: #666; +} + +.mirotalk-support-widget .minimize-btn:hover { + background: rgba(255, 255, 255, 0.2); + color: #fff; +} + +.mirotalk-support-widget.light-theme .minimize-btn:hover { + background: rgba(0, 0, 0, 0.1); + color: #333; +} + +.mirotalk-support-widget .close-btn { + cursor: pointer; + font-weight: bold; + font-size: 18px; + line-height: 1; + padding: 4px; + border-radius: 4px; + transition: all 0.2s ease; + color: #aaa; +} + +.mirotalk-support-widget.light-theme .close-btn { + color: #666; +} + +.mirotalk-support-widget .close-btn:hover { + background: rgba(255, 255, 255, 0.1); + color: #fff; + transform: scale(1.1); +} + +.mirotalk-support-widget.light-theme .close-btn:hover { + background: rgba(0, 0, 0, 0.1); + color: #333; +} + +/* Content Elements */ +.mirotalk-support-widget .main-heading { + font-size: 24px; + font-weight: 700; + margin-bottom: 12px; + background: linear-gradient(135deg, #fff 0%, #e0e0e0 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; + animation: fadeInUp 0.6s ease 0.1s both; +} + +.mirotalk-support-widget.light-theme .main-heading { + background: linear-gradient(135deg, #333 0%, #555 100%); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +.mirotalk-support-widget .subheading { + font-size: 16px; + line-height: 1.5; + margin-bottom: 24px; + color: #e0e0e0; + animation: fadeInUp 0.6s ease 0.2s both; +} + +.mirotalk-support-widget.light-theme .subheading { + color: #666; +} + +.mirotalk-support-widget .expert-images { + display: flex; + justify-content: center; + margin-bottom: 12px; + animation: fadeInUp 0.6s ease 0.3s both; +} + +.mirotalk-support-widget .expert-img { + width: 44px; + height: 44px; + border-radius: 50%; + border: 3px solid #333; + margin: 0 6px; + transition: all 0.3s ease; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.mirotalk-support-widget.light-theme .expert-img { + border: 3px solid #e0e0e0; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.mirotalk-support-widget .connect-text { + text-align: center; + font-size: 14px; + margin-bottom: 24px; + color: #bbb; + animation: fadeInUp 0.6s ease 0.4s both; +} + +.mirotalk-support-widget.light-theme .connect-text { + color: #777; +} + +/* Buttons */ +.mirotalk-support-widget .btn { + display: flex; + align-items: center; + width: 100%; + background: linear-gradient(135deg, #333 0%, #444 100%); + color: white; + border: none; + border-radius: 12px; + padding: 14px 16px; + margin-bottom: 12px; + cursor: pointer; + transition: all 0.3s ease; + font-size: 16px; + font-weight: 500; + position: relative; + overflow: hidden; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.mirotalk-support-widget.light-theme .btn { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + color: #333; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); +} + +.mirotalk-support-widget .btn:hover { + background: linear-gradient(135deg, #444 0%, #555 100%); + transform: translateY(-1px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3); +} + +.mirotalk-support-widget.light-theme .btn:hover { + background: linear-gradient(135deg, #e9ecef 0%, #dee2e6 100%); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1); +} + +.mirotalk-support-widget .btn:active { + transform: translateY(0); +} + +.mirotalk-support-widget .btn-icon { + background: linear-gradient(135deg, #00e676 0%, #00c853 100%); + border-radius: 50%; + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + box-shadow: 0 4px 12px rgba(0, 230, 118, 0.3); + transition: all 0.3s ease; + flex-shrink: 0; +} + +.mirotalk-support-widget .btn-text { + flex: 1; + text-align: center; + margin-left: -32px; +} + +.mirotalk-support-widget .btn:hover .btn-icon { + transform: scale(1.1); + box-shadow: 0 6px 16px rgba(0, 230, 118, 0.4); +} + +/* Footer */ +.mirotalk-support-widget .footer-text { + text-align: center; + font-size: 12px; + color: #888; + margin-top: 24px; + animation: fadeInUp 0.6s ease 0.5s both; +} + +.mirotalk-support-widget.light-theme .footer-text { + color: #999; +} + +.mirotalk-support-widget .footer-link { + color: #00e676; + text-decoration: none; + transition: color 0.2s ease; +} + +.mirotalk-support-widget .footer-link:hover { + color: #00c853; +} + +.mirotalk-support-widget .mirotalk-powered-by { + color: #00e676; + font-weight: bold; +} + +.mirotalk-support-widget.light-theme .mirotalk-powered-by { + color: #00c853; +} + +/* Widget States */ +.mirotalk-support-widget.minimized { + display: none; +} + +/* Minimized Button */ +.mirotalk-minimized-btn { + position: fixed; + background: linear-gradient(135deg, #1f1f2e 0%, #2a2a3e 100%); + color: #fff; + padding: 12px 16px; + border-radius: 25px; + cursor: pointer; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.3); + transition: all 0.3s ease; + z-index: 9998; + border: 1px solid rgba(255, 255, 255, 0.1); +} + +.mirotalk-minimized-btn.light-theme { + background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); + color: #333; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15); +} + +.mirotalk-minimized-btn:hover { + transform: translateY(-2px); + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.4); +} + +.mirotalk-minimized-btn.light-theme:hover { + box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2); +} + +.mirotalk-minimized-btn .minimized-content { + display: flex; + align-items: center; + gap: 8px; + font-weight: 600; + font-size: 14px; +} + +/* Reopener Button - Fully Rounded */ +.mirotalk-reopener-btn { + position: fixed; + background: linear-gradient(135deg, #23233a 0%, #2a2a3e 100%); + color: #fff; + padding: 0; + width: 80px; + height: 80px; + border-radius: 50%; + cursor: pointer; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1); + z-index: 9998; + display: flex; + align-items: center; + justify-content: center; + border: 2px solid rgba(255, 255, 255, 0.15); + font-weight: 600; + font-size: 16px; + letter-spacing: 0.02em; + user-select: none; +} + +.mirotalk-reopener-btn.light-theme { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); + color: #222; + border: 2px solid rgba(0, 0, 0, 0.13); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12); +} + +.mirotalk-reopener-btn:hover { + transform: translateY(-4px) scale(1.07); + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.6); + background: linear-gradient(135deg, #2a2a3e 0%, #23233a 100%); + color: #00e676; + border-color: #00e676; +} + +.mirotalk-reopener-btn.light-theme:hover { + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.18); + background: linear-gradient(135deg, #e9ecef 0%, #f8f9fa 100%); + color: #00c853; + border-color: #00c853; +} + +.mirotalk-reopener-btn .reopener-content { + display: flex; + flex-direction: column; + align-items: center; + gap: 2px; +} + +.mirotalk-reopener-btn .reopener-content span { + font-size: 11px; + font-weight: 600; + text-align: center; + line-height: 1.1; +} + +/* Responsive Design */ +@media (max-width: 1200px) { + .mirotalk-support-widget { + width: 300px; + padding: 22px; + } +} + +@media (max-width: 992px) { + .mirotalk-support-widget { + width: 280px; + padding: 20px; + bottom: 15px; + right: 15px; + } + + .mirotalk-support-widget .main-heading { + font-size: 22px; + } + + .mirotalk-support-widget .subheading { + font-size: 15px; + margin-bottom: 20px; + } + + .mirotalk-support-widget .expert-img { + width: 40px; + height: 40px; + margin: 0 4px; + } + + .mirotalk-support-widget .btn { + padding: 12px 14px; + font-size: 15px; + margin-bottom: 10px; + } + + .mirotalk-support-widget .btn-icon { + width: 28px; + height: 28px; + } + + .mirotalk-support-widget .btn-text { + margin-left: -28px; + } +} + +@media (max-width: 768px) { + .mirotalk-support-widget { + width: 260px; + padding: 18px; + bottom: 12px; + right: 12px; + border-radius: 16px; + } + + .mirotalk-support-widget.bottom-left, + .mirotalk-support-widget.top-left { + left: 12px; + } + + .mirotalk-support-widget.top-right, + .mirotalk-support-widget.top-left { + top: 12px; + } + + .mirotalk-support-widget .main-heading { + font-size: 20px; + margin-bottom: 10px; + } + + .mirotalk-support-widget .subheading { + font-size: 14px; + margin-bottom: 18px; + line-height: 1.4; + } + + .mirotalk-support-widget .expert-images { + margin-bottom: 10px; + } + + .mirotalk-support-widget .expert-img { + width: 36px; + height: 36px; + margin: 0 3px; + border-width: 2px; + } + + .mirotalk-support-widget .connect-text { + font-size: 13px; + margin-bottom: 18px; + } + + .mirotalk-support-widget .btn { + padding: 11px 12px; + font-size: 14px; + margin-bottom: 8px; + border-radius: 10px; + } + + .mirotalk-support-widget .btn-icon { + width: 26px; + height: 26px; + } + + .mirotalk-support-widget .btn-text { + margin-left: -26px; + font-size: 14px; + } + + .mirotalk-reopener-btn.bottom-right { + bottom: 12px; + right: 12px; + } + + .mirotalk-reopener-btn.bottom-left { + bottom: 12px; + left: 12px; + } + + .mirotalk-reopener-btn.top-right { + top: 12px; + right: 12px; + } + + .mirotalk-reopener-btn.top-left { + top: 12px; + left: 12px; + } +} + +@media (max-width: 480px) { + .mirotalk-support-widget { + width: 240px; + padding: 16px; + bottom: 10px; + right: 10px; + border-radius: 14px; + } + + .mirotalk-support-widget.bottom-left, + .mirotalk-support-widget.top-left { + left: 10px; + } + + .mirotalk-support-widget.top-right, + .mirotalk-support-widget.top-left { + top: 10px; + } + + .mirotalk-support-widget .online-indicator { + margin-bottom: 12px; + } + + .mirotalk-minimized-btn .status-dot .mirotalk-support-widget .status-dot { + width: 10px; + height: 10px; + } + + .mirotalk-support-widget .online-text, + .mirotalk-support-widget .offline-text { + font-size: 13px; + } + + .mirotalk-support-widget .close-btn { + font-size: 16px; + padding: 2px; + } + + .mirotalk-support-widget .main-heading { + font-size: 18px; + margin-bottom: 8px; + } + + .mirotalk-support-widget .subheading { + font-size: 13px; + margin-bottom: 16px; + } + + .mirotalk-support-widget .expert-images { + margin-bottom: 8px; + } + + .mirotalk-support-widget .expert-img { + width: 32px; + height: 32px; + margin: 0 2px; + } + + .mirotalk-support-widget .connect-text { + font-size: 12px; + margin-bottom: 16px; + } + + .mirotalk-support-widget .btn { + padding: 10px; + font-size: 13px; + margin-bottom: 6px; + border-radius: 8px; + } + + .mirotalk-support-widget .btn-icon { + width: 24px; + height: 24px; + } + + .mirotalk-support-widget .btn-icon svg { + width: 14px; + height: 14px; + } + + .mirotalk-support-widget .btn-text { + margin-left: -24px; + font-size: 13px; + } + + .mirotalk-support-widget .footer-text { + margin-top: 16px; + font-size: 10px; + } + + .mirotalk-reopener-btn.bottom-right { + bottom: 10px; + right: 10px; + } + + .mirotalk-reopener-btn.bottom-left { + bottom: 10px; + left: 10px; + } + + .mirotalk-reopener-btn.top-right { + top: 10px; + right: 10px; + } + + .mirotalk-reopener-btn.top-left { + top: 10px; + left: 10px; + } +} + +@media (max-width: 360px) { + .mirotalk-support-widget { + width: 220px; + padding: 14px; + bottom: 8px; + right: 8px; + } + + .mirotalk-support-widget.bottom-left, + .mirotalk-support-widget.top-left { + left: 8px; + } + + .mirotalk-support-widget.top-right, + .mirotalk-support-widget.top-left { + top: 8px; + } + + .mirotalk-support-widget .main-heading { + font-size: 16px; + } + + .mirotalk-support-widget .subheading { + font-size: 12px; + } + + .mirotalk-support-widget .expert-img { + width: 28px; + height: 28px; + } + + .mirotalk-support-widget .btn { + padding: 8px; + font-size: 12px; + } + + .mirotalk-support-widget .btn-icon { + width: 22px; + height: 22px; + } + + .mirotalk-support-widget .btn-icon svg { + width: 12px; + height: 12px; + } + + .mirotalk-support-widget .btn-text { + margin-left: -22px; + font-size: 12px; + } +} + +/* Landscape Orientation */ +@media (max-height: 600px) and (orientation: landscape) { + .mirotalk-support-widget { + padding: 12px; + width: 280px; + max-height: 90vh; + overflow-y: auto; + } + + .mirotalk-support-widget .main-heading { + font-size: 18px; + margin-bottom: 6px; + } + + .mirotalk-support-widget .subheading { + font-size: 13px; + margin-bottom: 12px; + } + + .mirotalk-support-widget .expert-images { + margin-bottom: 6px; + } + + .mirotalk-support-widget .connect-text { + margin-bottom: 12px; + } + + .mirotalk-support-widget .btn { + padding: 8px 10px; + margin-bottom: 4px; + } + + .mirotalk-support-widget .footer-text { + margin-top: 12px; + } +} + +/* High DPI Displays */ +@media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { + .mirotalk-support-widget { + border-width: 0.5px; + } + + .mirotalk-support-widget .btn { + border-width: 0.5px; + } + + .mirotalk-support-widget .expert-img { + border-width: 1.5px; + } +} + +/* Accessibility - Reduced Motion */ +@media (prefers-reduced-motion: reduce) { + .mirotalk-support-widget, + .mirotalk-support-widget *, + .mirotalk-minimized-btn, + .mirotalk-reopener-btn { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } + + .mirotalk-minimized-btn .status-dot.online, + .mirotalk-support-widget .status-dot.online { + animation: none; + } +} + +/* Focus States for Accessibility */ +.mirotalk-support-widget .btn:focus, +.mirotalk-support-widget .minimize-btn:focus, +.mirotalk-support-widget .close-btn:focus, +.mirotalk-minimized-btn:focus, +.mirotalk-reopener-btn:focus { + outline: 2px solid #00e676; + outline-offset: 2px; +} + +/* Print Styles */ +@media print { + .mirotalk-support-widget, + .mirotalk-minimized-btn, + .mirotalk-reopener-btn { + display: none !important; + } +} diff --git a/public/js/Brand.js b/public/js/Brand.js index eadd478e..75f67eb6 100644 --- a/public/js/Brand.js +++ b/public/js/Brand.js @@ -76,7 +76,7 @@ let BRAND = { }, about: { imageUrl: '../images/mirotalk-logo.gif', - title: 'WebRTC SFU v1.9.21', + title: 'WebRTC SFU v1.9.22', html: ` +
×
+ + +

${customMessages.heading}

+

${customMessages.subheading}

+
+ ${expertImages + .map( + (img, i) => ` + Expert consultant ${i + 1} + ` + ) + .join('')} +
+
${customMessages.connectText}
+ ${this.createActionButtons()} + + `; + } + + createActionButtons() { + const buttons = [ + { action: 'startAudioCall', icon: this.getAudioIcon(), text: 'Start Audio Call' }, + { action: 'startVideoCall', icon: this.getVideoIcon(), text: 'Start Video Call' }, + { action: 'startScreenShare', icon: this.getScreenIcon(), text: 'Start Screen Share' }, + { action: 'joinRoom', icon: this.getJoinIcon(), text: 'Join Room' }, + ]; + + return buttons + .map( + (btn) => ` + + ` + ) + .join(''); + } + + // ============================================================================ + // STATE MANAGEMENT METHODS + // ============================================================================ + + minimizeWidget() { + const widget = document.querySelector('.mirotalk-support-widget'); + if (!widget) { + console.warn('Widget not found for minimizing'); + return; + } + + widget.classList.add('minimized'); + this.widgetState = 'minimized'; + this.createMinimizedButton(); + console.log('Widget minimized'); + } + + restoreWidget() { + const widget = document.querySelector('.mirotalk-support-widget'); + const minimizedBtn = document.querySelector('.mirotalk-minimized-btn'); + + if (widget) { + widget.classList.remove('minimized'); + this.widgetState = 'normal'; + } + if (minimizedBtn) { + minimizedBtn.remove(); + } + console.log('Widget restored'); + } + + closeWidget() { + this.removeAllWidgetElements(); + this.widgetState = 'closed'; + this.createReopenerButton(); + console.log('Widget closed'); + } + + reopenWidget() { + const reopenerBtn = document.querySelector('.mirotalk-reopener-btn'); + if (reopenerBtn) reopenerBtn.remove(); + this.createWidget(); + console.log('Widget reopened'); + } + + // ============================================================================ + // BUTTON CREATION METHODS + // ============================================================================ + + createMinimizedButton() { + this.removeExistingElement('.mirotalk-minimized-btn'); + + if (!this.options.supportWidget?.position) { + console.error('Support widget position not defined'); + return; + } + + const minimizedBtn = this.createElement('div', { + className: this.buildClassNames([ + 'mirotalk-minimized-btn', + this.options.supportWidget.position, + this.options.theme === 'light' ? 'light-theme' : '', + ]), + }); + + const widgetId = this.generateWidgetId('minimized'); + this.registerWidget(widgetId, minimizedBtn); + + const content = this.createMinimizedContent(); + minimizedBtn.appendChild(content); + minimizedBtn.addEventListener('click', () => this.restoreWidget()); + + document.body.appendChild(minimizedBtn); + console.log('Minimized button created'); + } + + createMinimizedContent() { + const contentDiv = this.createElement('div', { className: 'minimized-content' }); + const statusDot = this.createElement('div', { + className: `status-dot ${this.isOnline ? 'online' : 'offline'}`, + }); + const textSpan = this.createElement('span', { textContent: 'Support' }); + + contentDiv.appendChild(statusDot); + contentDiv.appendChild(textSpan); + return contentDiv; + } + + createReopenerButton() { + this.removeExistingElement('.mirotalk-reopener-btn'); + + if (!this.options.supportWidget?.position) { + console.error('Support widget position not defined'); + return; + } + + const reopenerBtn = this.createElement('div', { + className: this.buildClassNames([ + 'mirotalk-reopener-btn', + this.options.supportWidget.position, + this.options.theme === 'light' ? 'light-theme' : 'dark-theme', + ]), + }); + + const widgetId = this.generateWidgetId('reopener'); + this.registerWidget(widgetId, reopenerBtn); + + reopenerBtn.innerHTML = ` +
+ + Support +
+ `; + + reopenerBtn.addEventListener('click', () => this.reopenWidget()); + document.body.appendChild(reopenerBtn); + console.log('Reopener button created'); + } + + // ============================================================================ + // STATUS MANAGEMENT METHODS + // ============================================================================ + + async checkOnlineStatus() { + try { + const response = await fetch(`${this.protocol}://${this.domain}/isRoomActive`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ roomId: this.roomId }), + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + const online = data.message && data.message !== 'Unauthorized'; + this.updateOnlineStatus(online); + } catch (error) { + console.warn('Failed to check room status:', error.message); + this.updateOnlineStatus(false); + } + } + + updateOnlineStatus(online) { + this.isOnline = online; + + const elementsToUpdate = ['.mirotalk-support-widget', '.mirotalk-minimized-btn']; + + elementsToUpdate.forEach((selector) => { + const element = document.querySelector(selector); + if (element) { + this.updateStatusInElement(element, online); + } + }); + + console.log('Online status updated:', online); + } + + updateStatusInElement(element, online) { + const statusDot = element.querySelector('.status-dot'); + const onlineText = element.querySelector('.online-text'); + const offlineText = element.querySelector('.offline-text'); + + if (statusDot) { + statusDot.classList.toggle('online', online); + statusDot.classList.toggle('offline', !online); + } + + if (onlineText && offlineText) { + onlineText.style.display = online ? 'inline' : 'none'; + offlineText.style.display = online ? 'none' : 'inline'; + } + } + + // ============================================================================ + // ACTION METHODS + // ============================================================================ + + startAudioCall() { + if (this.isOnline) { + console.log('Starting audio call...'); + this.openMeetingWindow({ audio: 1, video: 0, screen: 0 }); + } else { + this.supportOffline(); + } + } + + startVideoCall() { + if (this.isOnline) { + console.log('Starting video call...'); + this.openMeetingWindow({ audio: 0, video: 1, screen: 0 }); + } else { + this.supportOffline(); + } + } + + startScreenShare() { + if (this.isOnline) { + console.log('Starting screen share...'); + this.openMeetingWindow({ audio: 0, video: 0, screen: 1 }); + } else { + this.supportOffline(); + } + } + + joinRoom() { + if (this.isOnline) { + console.log('Joining room...'); + window.open(`${this.protocol}://${this.domain}/join?room=${this.roomId}`, '_blank'); + } else { + this.supportOffline(); + } + } + + openMiroTalk() { + window.open(`https://${this.domain}`, '_blank'); + } + + openMeetingWindow(params) { + const queryParams = new URLSearchParams({ + room: this.roomId, + name: this.userName, + ...params, + }); + window.open(`${this.protocol}://${this.domain}/join?${queryParams}`, '_blank'); + } + + supportOffline() { + alert('Sorry, support is currently offline.'); + } + + // ============================================================================ + // UTILITY METHODS + // ============================================================================ + + async injectExternalCSS(url, id) { + if (document.getElementById(id)) return Promise.resolve(); + + return new Promise((resolve, reject) => { + const link = document.createElement('link'); + link.id = id; + link.rel = 'stylesheet'; + link.href = url; + link.onload = () => { + console.log(`CSS loaded successfully: ${url}`); + resolve(); + }; + link.onerror = () => { + console.error(`Failed to load CSS: ${url}`); + reject(new Error(`Failed to load CSS: ${url}`)); + }; + document.head.appendChild(link); + }); + } + + createElement(tag, properties = {}) { + const element = document.createElement(tag); + Object.assign(element, properties); + return element; + } + + generateWidgetId(prefix = 'widget') { + return `${prefix}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; + } + + registerWidget(widgetId, element) { + window.miroTalkWidgets.set(widgetId, this); + element.setAttribute('data-widget-id', widgetId); + } + + buildClassNames(classes) { + return classes.filter(Boolean).join(' '); + } + + removeExistingElement(selector) { + const existingElement = document.querySelector(selector); + if (existingElement) existingElement.remove(); + } + + removeAllWidgetElements() { + const selectors = ['.mirotalk-support-widget', '.mirotalk-minimized-btn', '.mirotalk-reopener-btn']; + selectors.forEach((selector) => { + document.querySelectorAll(selector).forEach((element) => element.remove()); + }); + } + + getParentNode() { + return document.querySelector('#mirotalk-widget') || document.body; + } + + clearParentNode(parentNode) { + parentNode.innerHTML = ''; + } + + getWidgetFromElement(element) { + const widget = element.closest('.mirotalk-support-widget, .mirotalk-minimized-btn, .mirotalk-reopener-btn'); + if (widget) { + const widgetId = widget.getAttribute('data-widget-id'); + return window.miroTalkWidgets ? window.miroTalkWidgets.get(widgetId) : this; + } + return this; + } + + // ============================================================================ + // ICON METHODS + // ============================================================================ + + getAudioIcon() { + return ` + + `; + } + + getVideoIcon() { + return ` + + `; + } + + getScreenIcon() { + return ` + + + `; + } + + getJoinIcon() { + return ` + + `; + } + + // ============================================================================ + // PUBLIC API METHODS + // ============================================================================ + + join() { + if (!this.getParentNode()) { + this.createWidget(); + } + } + + destroy() { + this.removeAllWidgetElements(); + + const parentNode = this.getParentNode(); + if (parentNode && parentNode !== document.body) { + this.clearParentNode(parentNode); + } + + if (window.miroTalkWidgets) { + for (const [key, widget] of window.miroTalkWidgets.entries()) { + if (widget === this) { + window.miroTalkWidgets.delete(key); + break; + } + } + } + + console.log('Widget destroyed'); + } + + updateRoom(newRoomId) { + this.roomId = newRoomId; + this.createWidget(); + } + + updateUser(newUserName) { + this.userName = newUserName; + this.createWidget(); + } + + getState() { + return this.widgetState; + } + + isVisible() { + return this.widgetState === 'normal'; + } +} + +// ============================================================================ +// GLOBAL ACTION HANDLER +// ============================================================================ + +window.miroTalkWidgetAction = function (action, element) { + try { + const widgetElement = element.closest( + '.mirotalk-support-widget, .mirotalk-minimized-btn, .mirotalk-reopener-btn' + ); + + if (!widgetElement) { + console.error('Widget element not found'); + return; + } + + const widgetId = widgetElement.getAttribute('data-widget-id'); + const widget = window.miroTalkWidgets?.get(widgetId); + + if (!widget) { + console.error('Widget instance not found'); + return; + } + + const actions = { + minimize: () => widget.minimizeWidget(), + close: () => widget.closeWidget(), + restore: () => widget.restoreWidget(), + reopen: () => widget.reopenWidget(), + startAudioCall: () => widget.startAudioCall(), + startVideoCall: () => widget.startVideoCall(), + startScreenShare: () => widget.startScreenShare(), + joinRoom: () => widget.joinRoom(), + }; + + const actionHandler = actions[action]; + if (actionHandler) { + actionHandler(); + } else { + console.warn('Unknown action:', action); + } + } catch (error) { + console.error('Error executing widget action:', error); + } +}; + +// ============================================================================ +// AUTO-INITIALIZATION +// ============================================================================ + +document.addEventListener('DOMContentLoaded', function () { + const autoInit = document.querySelector('[data-mirotalk-auto]'); + if (!autoInit) return; + + try { + const config = { + domain: autoInit.getAttribute('data-domain'), + roomId: autoInit.getAttribute('data-room') || 'support-room', + userName: autoInit.getAttribute('data-user') || `guest-${Math.floor(Math.random() * 10000)}`, + theme: autoInit.getAttribute('data-theme') || MiroTalkWidget.DEFAULT_OPTIONS.theme, + widgetState: autoInit.getAttribute('data-widget-state') || MiroTalkWidget.DEFAULT_OPTIONS.widgetState, + position: autoInit.getAttribute('data-position') || MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.position, + checkOnline: autoInit.getAttribute('data-check-online') === 'true', + customMessages: { + heading: + autoInit.getAttribute('data-heading') || + MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.customMessages.heading, + subheading: + autoInit.getAttribute('data-subheading') || + MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.customMessages.subheading, + connectText: + autoInit.getAttribute('data-connect-text') || + MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.customMessages.connectText, + onlineText: + autoInit.getAttribute('data-online-text') || + MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.customMessages.onlineText, + offlineText: + autoInit.getAttribute('data-offline-text') || + MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.customMessages.offlineText, + poweredBy: + autoInit.getAttribute('data-powered-by') || + MiroTalkWidget.DEFAULT_OPTIONS.supportWidget.customMessages.poweredBy, + }, + }; + + if (config.domain) { + new MiroTalkWidget(config.domain, config.roomId, config.userName, { + widgetState: config.widgetState, + theme: config.theme, + supportWidget: { + ...MiroTalkWidget.DEFAULT_OPTIONS.supportWidget, + position: config.position, + checkOnlineStatus: config.checkOnline, + customMessages: config.customMessages, + }, + }); + } + } catch (error) { + console.error('Failed to auto-initialize MiroTalk Widget:', error); + } +}); diff --git a/widgets/example-0.html b/widgets/example-0.html new file mode 100644 index 00000000..10b55e10 --- /dev/null +++ b/widgets/example-0.html @@ -0,0 +1,19 @@ + + + + + + +
+ + diff --git a/widgets/example-1.html b/widgets/example-1.html index 7133f485..68216bee 100644 --- a/widgets/example-1.html +++ b/widgets/example-1.html @@ -1,738 +1,25 @@ - + - - - MiroTalk SFU - Support Widget - + -
- -
- -
We are online
-
We are offline
-
- × -
-
- - -

Need a hand?

- - -

- Hop on a Free 1:1 or Group Consultation with a MiroTalk Expert - right now! -

- - -
- Expert consultant 1 - Expert consultant 2 - Expert consultant 3 -
- -
connect in < 10 seconds
- - - - - - - - - - - -
- - +
diff --git a/widgets/example-2.html b/widgets/example-2.html index 791b4ead..da73774d 100644 --- a/widgets/example-2.html +++ b/widgets/example-2.html @@ -1,17 +1,44 @@ - - - - MiroTalk SFU - Simple Iframe Example + - + diff --git a/widgets/example-3.html b/widgets/example-3.html index c315cd61..fc08536b 100644 --- a/widgets/example-3.html +++ b/widgets/example-3.html @@ -3,34 +3,819 @@ - MiroTalk SFU - Embedded Meeting Widget + MiroTalk SFU - Custom Support Widget + -
+ +
+ +
+
+
We are online
+
We are offline
+
+ + +
+
+ + +

Need a hand?

+ + +

+ Hop on a Free 1:1 or Group Consultation with a MiroTalk Expert + right now! +

+ + +
+ Expert consultant 1 + Expert consultant 2 + Expert consultant 3 +
+ +
connect in < 10 seconds
+ + + + + + + + + + + +
+ + +
+
+
+ Support +
+
+ + +
+
+ + + + Support +
+
+ + diff --git a/widgets/example-4.html b/widgets/example-4.html new file mode 100644 index 00000000..791b4ead --- /dev/null +++ b/widgets/example-4.html @@ -0,0 +1,17 @@ + + + + + + + MiroTalk SFU - Simple Iframe Example + + + + + diff --git a/widgets/example-5.html b/widgets/example-5.html new file mode 100644 index 00000000..c315cd61 --- /dev/null +++ b/widgets/example-5.html @@ -0,0 +1,36 @@ + + + + + + MiroTalk SFU - Embedded Meeting Widget + + + + + + +
+ + diff --git a/widgets/maker.html b/widgets/maker.html new file mode 100644 index 00000000..5c070a0a --- /dev/null +++ b/widgets/maker.html @@ -0,0 +1,702 @@ + + + + + + MiroTalk Widget Maker + + + + + + +
+
+

MiroTalk Widget Maker

+

Create custom embeddable widgets for your website in seconds

+
+ +
+ +
+

Widget Configuration

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+
+ + +
+
+
+ + +
+

Custom Messages

+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+
+ + +
+

Generated Code

+
+
+ HTML + +
+ +
+ +
+ + +
+
+
+
+ + + +