diff --git a/app/src/server.js b/app/src/server.js
index 1dcc7dca..3e3a6aa0 100755
--- a/app/src/server.js
+++ b/app/src/server.js
@@ -38,7 +38,7 @@ dependencies: {
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.2.83
+ * @version 1.2.84
*
*/
diff --git a/package.json b/package.json
index 825d5b34..2519f582 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "mirotalk",
- "version": "1.2.83",
+ "version": "1.2.84",
"description": "A free WebRTC browser-based video call",
"main": "server.js",
"scripts": {
@@ -37,8 +37,8 @@
"license": "AGPL-3.0",
"homepage": "https://github.com/miroslavpejic85/mirotalk",
"dependencies": {
- "@sentry/integrations": "^7.99.0",
- "@sentry/node": "^7.99.0",
+ "@sentry/integrations": "^7.100.1",
+ "@sentry/node": "^7.100.1",
"axios": "^1.6.7",
"body-parser": "^1.20.2",
"colors": "^1.4.0",
@@ -48,7 +48,7 @@
"dotenv": "^16.4.1",
"express": "^4.18.2",
"ngrok": "^4.3.3",
- "openai": "^4.26.0",
+ "openai": "^4.26.1",
"qs": "^6.11.2",
"socket.io": "^4.7.4",
"swagger-ui-express": "^5.0.0",
diff --git a/public/css/client.css b/public/css/client.css
index 16739ad2..95ed8406 100755
--- a/public/css/client.css
+++ b/public/css/client.css
@@ -35,7 +35,7 @@
--hover-color: grey;
/* video elem border color */
- --elem-border-color: none; /* 1px solid rgb(255 255 255 / 32%) */
+ --elem-border-color: none;
--tab-btn-active: rgb(30 29 29);
@@ -126,6 +126,7 @@ body {
text-align: center;
border-radius: 10px;
background: rgba(0, 0, 0, 0.7);
+ box-shadow: var(--box-shadow);
}
#loadingDiv h1 {
font-size: 60px;
@@ -949,6 +950,32 @@ button:hover {
/* font-weight: bold; */
}
+.inline-check-box {
+ margin-bottom: 20px;
+ display: inline-flex;
+ justify-content: center; /* Vertical centering */
+ align-items: center; /* Horizontal centering */
+ text-align: left;
+ color: white;
+}
+
+#themeColorPicker {
+ z-index: 6;
+ padding: 10px;
+ margin-top: 10px;
+ margin-bottom: 20px;
+ width: 130px;
+ border: var(--border);
+ border-radius: 5px;
+ background: var(--select-bg);
+ color: white;
+ cursor: pointer;
+}
+
+#keepCustomTheme {
+ margin-bottom: 10px;
+}
+
.buttons {
padding: 10px;
float: left;
@@ -1785,6 +1812,7 @@ button {
/*
z-index
+6 theme custom picker
7 video avatar img
8 video nav bar
8 peer name
diff --git a/public/css/videoGrid.css b/public/css/videoGrid.css
index 33d95a33..a99fb3d0 100644
--- a/public/css/videoGrid.css
+++ b/public/css/videoGrid.css
@@ -41,6 +41,7 @@
display: inline-block;
background: var(--body-bg);
border: var(--elem-border-color);
+ box-shadow: var(--box-shadow);
border-radius: 10px;
animation: show 0.4s ease;
}
diff --git a/public/js/client.js b/public/js/client.js
index 89ed5cac..f66aa4ba 100644
--- a/public/js/client.js
+++ b/public/js/client.js
@@ -15,7 +15,7 @@
* @license For commercial use or closed source, contact us at license.mirotalk@gmail.com or purchase directly from CodeCanyon
* @license CodeCanyon: https://codecanyon.net/item/mirotalk-p2p-webrtc-realtime-video-conferences/38376661
* @author Miroslav Pejic - miroslav.pejic.85@gmail.com
- * @version 1.2.83
+ * @version 1.2.84
*
*/
@@ -98,6 +98,7 @@ const icons = {
fileSend: '',
fileReceive: '',
codecs: '',
+ theme: '',
};
// Whiteboard and fileSharing
@@ -502,6 +503,55 @@ const useAvatarSvg = true; // if false the cam-Off avatar = images.avatar
const ZOOM_CENTER_MODE = false;
const ZOOM_IN_OUT_ENABLED = true; // Video Zoom in/out default (true)
+// Color Picker:
+
+const themeCustom = {
+ input: getId('themeColorPicker'),
+ check: getId('keepCustomTheme'),
+ color: lsSettings.theme_color ? lsSettings.theme_color : '#000000',
+ keep: lsSettings.theme_custom ? lsSettings.theme_custom : false,
+};
+
+const pickr = Pickr.create({
+ el: themeCustom.input,
+ theme: 'classic', // or 'monolith', or 'nano'
+ default: themeCustom.color,
+ useAsButton: true,
+ swatches: [
+ 'rgba(244, 67, 54, 1)',
+ 'rgba(233, 30, 99, 0.95)',
+ 'rgba(156, 39, 176, 0.9)',
+ 'rgba(103, 58, 183, 0.85)',
+ 'rgba(63, 81, 181, 0.8)',
+ 'rgba(33, 150, 243, 0.75)',
+ 'rgba(3, 169, 244, 0.7)',
+ 'rgba(0, 188, 212, 0.7)',
+ 'rgba(0, 150, 136, 0.75)',
+ 'rgba(76, 175, 80, 0.8)',
+ 'rgba(139, 195, 74, 0.85)',
+ 'rgba(205, 220, 57, 0.9)',
+ 'rgba(255, 235, 59, 0.95)',
+ 'rgba(255, 193, 7, 1)',
+ ],
+ components: {
+ preview: true,
+ opacity: true,
+ hue: true,
+ },
+})
+ .on('init', (pickr) => {
+ themeCustom.input.value = pickr.getSelectedColor().toHEXA().toString(0);
+ })
+ .on('change', (color) => {
+ themeCustom.color = color.toHEXA().toString();
+ themeCustom.input.value = themeCustom.color;
+ setCustomTheme();
+ })
+ .on('changestop', () => {
+ lsSettings.theme_color = themeCustom.color;
+ lS.setSettings(lsSettings);
+ });
+
// misc
let swBg = 'rgba(0, 0, 0, 0.7)'; // swAlert background color
let callElapsedTime; // count time
@@ -2173,11 +2223,35 @@ function handleRemovePeer(config) {
console.log('ALL PEERS', allPeers);
}
+/**
+ * Set custom theme
+ */
+function setCustomTheme() {
+ const color = themeCustom.color;
+ swBg = `radial-gradient(${color}, ${color})`;
+ setSP('--body-bg', `radial-gradient(${color}, ${color})`);
+ setSP('--msger-bg', `radial-gradient(${color}, ${color})`);
+ setSP('--msger-private-bg', `radial-gradient(${color}, ${color})`);
+ setSP('--wb-bg', `radial-gradient(${color}, ${color})`);
+ setSP('--elem-border-color', '0.5px solid rgb(255 255 255 / 32%)');
+ setSP('--navbar-bg', 'rgba(0, 0, 0, 0.2)');
+ setSP('--select-bg', `${color}`);
+ setSP('--tab-btn-active', `${color}`);
+ setSP('--box-shadow', '0px 8px 16px 0px rgba(0, 0, 0, 0.2)');
+ setSP('--left-msg-bg', '#252d31');
+ setSP('--right-msg-bg', `${color}`);
+ setSP('--private-msg-bg', '#6b1226');
+ setSP('--btn-bar-bg-color', '#FFFFFF');
+ setSP('--btn-bar-color', '#000000');
+ document.body.style.background = `radial-gradient(${color}, ${color})`;
+}
+
/**
* Set mirotalk theme | dark | grey | ...
- * @param {string} theme type
*/
function setTheme() {
+ if (themeCustom.keep) return setCustomTheme();
+
mirotalkTheme.selectedIndex = lsSettings.theme;
const theme = mirotalkTheme.value;
switch (theme) {
@@ -2188,6 +2262,7 @@ function setTheme() {
setSP('--msger-bg', 'radial-gradient(#393939, #000000)');
setSP('--msger-private-bg', 'radial-gradient(#393939, #000000)');
setSP('--wb-bg', 'radial-gradient(#393939, #000000)');
+ setSP('--elem-border-color', 'none');
setSP('--navbar-bg', 'rgba(0, 0, 0, 0.2)');
setSP('--select-bg', '#2c2c2c');
setSP('--tab-btn-active', 'rgb(30 29 29)');
@@ -2206,6 +2281,7 @@ function setTheme() {
setSP('--body-bg', 'radial-gradient(#666, #333)');
setSP('--msger-bg', 'radial-gradient(#666, #333)');
setSP('--wb-bg', 'radial-gradient(#797979, #000)');
+ setSP('--elem-border-color', 'none');
setSP('--navbar-bg', 'rgba(0, 0, 0, 0.2)');
setSP('--select-bg', '#2c2c2c');
setSP('--tab-btn-active', 'rgb(30 29 29)');
@@ -2225,6 +2301,7 @@ function setTheme() {
setSP('--body-bg', 'radial-gradient(#003934, #001E1A)');
setSP('--msger-bg', 'radial-gradient(#003934, #001E1A)');
setSP('--wb-bg', 'radial-gradient(#003934, #001E1A)');
+ setSP('--elem-border-color', 'none');
setSP('--navbar-bg', 'rgba(0, 0, 0, 0.2)');
setSP('--select-bg', '#001E1A');
setSP('--tab-btn-active', '#003934');
@@ -2244,6 +2321,7 @@ function setTheme() {
setSP('--body-bg', 'radial-gradient(#306bac, #141B41)');
setSP('--msger-bg', 'radial-gradient(#306bac, #141B41)');
setSP('--wb-bg', 'radial-gradient(#306bac, #141B41)');
+ setSP('--elem-border-color', 'none');
setSP('--navbar-bg', 'rgba(0, 0, 0, 0.2)');
setSP('--select-bg', '#141B41');
setSP('--tab-btn-active', '#306bac');
@@ -4626,6 +4704,18 @@ function setMySettingsBtn() {
resumeRecBtn.addEventListener('click', (e) => {
resumeRecording();
});
+ // Styles
+ themeCustom.check.onchange = (e) => {
+ themeCustom.keep = e.currentTarget.checked;
+ themeSelect.disabled = themeCustom.keep;
+ lsSettings.theme_custom = themeCustom.keep;
+ lsSettings.theme_color = themeCustom.color;
+ lS.setSettings(lsSettings);
+ setTheme();
+ userLog('toast', `${icons.theme} Custom theme keep ` + (themeCustom.keep ? 'ON' : 'OFF'));
+ playSound('switch');
+ e.target.blur();
+ };
}
/**
@@ -4876,6 +4966,10 @@ function loadSettingsFromLocalStorage() {
switchAudioPitchBar.checked = isAudioPitchBar;
switchH264Recording.checked = recPrioritizeH264;
+ themeCustom.check.checked = themeCustom.keep;
+ themeSelect.disabled = themeCustom.keep;
+ themeCustom.input.value = themeCustom.color;
+
switchAutoGainControl.checked = lsSettings.mic_auto_gain_control;
switchEchoCancellation.checked = lsSettings.mic_echo_cancellations;
switchNoiseSuppression.checked = lsSettings.mic_noise_suppression;
diff --git a/public/js/localStorage.js b/public/js/localStorage.js
index 748fd7b8..63bc0097 100644
--- a/public/js/localStorage.js
+++ b/public/js/localStorage.js
@@ -31,6 +31,8 @@ class LocalStorage {
sounds: true,
video_obj_fit: 2, // cover
theme: 0, // dark
+ theme_color: '#000000', // custom theme color
+ theme_custom: false, // keep custom theme
buttons_bar: 0, // vertical
pin_grid: 0, // vertical
};
diff --git a/public/views/client.html b/public/views/client.html
index f301d2e5..0b682ff3 100755
--- a/public/views/client.html
+++ b/public/views/client.html
@@ -52,6 +52,15 @@
+
+
+
+
+
+
+
+
+
@@ -712,6 +721,23 @@ access to use this app.
+
Custom theme
+Keep custom
+Buttons bar
@@ -889,6 +915,8 @@ access to use this app. - https://www.jsdelivr.com/package/npm/crypto-js (https://github.com/brix/crypto-js/) - https://www.npmjs.com/package/tippy.js (https://github.com/atomiks/tippyjs) - https://flatpickr.js.org/ (https://github.com/flatpickr/flatpickr) + - https://simonwep.github.io/pickr/ (https://github.com/simonwep/pickr) + --> @@ -904,6 +932,8 @@ access to use this app. + +