[mirotalksfu] - improve widget

هذا الالتزام موجود في:
Miroslav Pejic
2025-08-10 22:27:22 +02:00
الأصل 0894d86fb6
التزام 998ae4e91c
11 ملفات معدلة مع 260 إضافات و63 حذوفات

عرض الملف

@@ -15,6 +15,7 @@
data-position="bottom-right"
data-check-online="false"
data-expert-images="https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar.cc/40?img=3"
data-buttons="audio,video,screen,chat,join"
data-heading="Need Help?"
data-subheading="Get instant support from our expert team!"
data-connect-text="connect in < 5 seconds"

عرض الملف

@@ -346,6 +346,63 @@
display: none;
}
.button-toggle-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: 10px 14px;
margin-top: 8px;
}
.toggle {
position: relative;
display: flex;
align-items: center;
gap: 8px;
font-size: 13px;
font-weight: 600;
background: #eef1f4;
border: 1px solid #d5dade;
padding: 8px 10px 8px 40px;
border-radius: 8px;
cursor: pointer;
user-select: none;
transition:
background 0.25s,
border-color 0.25s;
}
.toggle input {
position: absolute;
opacity: 0;
pointer-events: none;
}
.toggle::before {
content: '';
position: absolute;
left: 10px;
width: 20px;
height: 20px;
border-radius: 6px;
background: linear-gradient(135deg, #9aa0a6, #7e858c);
box-shadow: inset 0 0 0 2px rgba(255, 255, 255, 0.5);
transition: background 0.25s;
}
.toggle.checked {
background: #e5faf0;
border-color: #00c853;
color: #116d3d;
}
.toggle.checked::before {
background: linear-gradient(135deg, #00e676, #00c853);
}
.toggle:active {
transform: scale(0.97);
}
@media (max-width: 768px) {
.content {
grid-template-columns: 1fr;
@@ -453,6 +510,30 @@
<label for="check-online">Check Online Status <span class="feature-badge">PRO</span></label>
</div>
</div>
<!-- Action Buttons -->
<div class="form-group">
<label class="tooltip" data-tooltip="Select which action buttons to include">
Action Buttons
</label>
<div id="action-buttons" class="button-toggle-grid">
<label class="toggle" data-btn="audio"
><input type="checkbox" id="btn-audio" checked />Audio</label
>
<label class="toggle" data-btn="video"
><input type="checkbox" id="btn-video" checked />Video</label
>
<label class="toggle" data-btn="screen"
><input type="checkbox" id="btn-screen" checked />Screen</label
>
<label class="toggle" data-btn="chat"
><input type="checkbox" id="btn-chat" checked />Chat</label
>
<label class="toggle" data-btn="join"
><input type="checkbox" id="btn-join" checked />Join</label
>
</div>
</div>
</div>
<!-- Customization Form -->
@@ -555,6 +636,11 @@ https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar
offlineText: document.getElementById('offline-text'),
poweredBy: document.getElementById('powered-by'),
expertImages: document.getElementById('expert-images'),
btnAudio: document.getElementById('btn-audio'),
btnVideo: document.getElementById('btn-video'),
btnScreen: document.getElementById('btn-screen'),
btnChat: document.getElementById('btn-chat'),
btnJoin: document.getElementById('btn-join'),
};
const generatedCode = document.getElementById('generated-code');
@@ -579,36 +665,45 @@ https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar
'https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar.cc/40?img=3',
};
const buttonsSelected = [];
if (form.btnAudio.checked) buttonsSelected.push('audio');
if (form.btnVideo.checked) buttonsSelected.push('video');
if (form.btnScreen.checked) buttonsSelected.push('screen');
if (form.btnChat.checked) buttonsSelected.push('chat');
if (form.btnJoin.checked) buttonsSelected.push('join');
const buttonsAttr = buttonsSelected.join(',');
const html = `<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>MiroTalk Widget</title>
<script src="https://${config.domain}/js/Widget.js"><\/script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>MiroTalk Widget</title>
<script src="https://${config.domain}/js/Widget.js"><\/script>
</head>
<body>
<div
id="mirotalk-widget"
data-mirotalk-auto
data-domain="${config.domain}"
data-room="${config.room}"
data-theme="${config.theme}"
data-widget-type="support"
data-position="${config.position}"
data-widget-state="${config.widgetState}"
data-check-online="${config.checkOnline}"
data-expert-images="${escapeHtml(config.expertImages)}"
data-heading="${escapeHtml(config.heading)}"
data-subheading="${escapeHtml(config.subheading)}"
data-connect-text="${escapeHtml(config.connectText)}"
data-online-text="${escapeHtml(config.onlineText)}"
data-offline-text="${escapeHtml(config.offlineText)}"
data-powered-by="${escapeHtml(config.poweredBy)}"
></div>
<div
id="mirotalk-widget"
data-mirotalk-auto
data-domain="${config.domain}"
data-room="${config.room}"
data-theme="${config.theme}"
data-widget-type="support"
data-position="${config.position}"
data-widget-state="${config.widgetState}"
data-buttons="${buttonsAttr}"
data-check-online="${config.checkOnline}"
data-expert-images="${escapeHtml(config.expertImages)}"
data-heading="${escapeHtml(config.heading)}"
data-subheading="${escapeHtml(config.subheading)}"
data-connect-text="${escapeHtml(config.connectText)}"
data-online-text="${escapeHtml(config.onlineText)}"
data-offline-text="${escapeHtml(config.offlineText)}"
data-powered-by="${escapeHtml(config.poweredBy)}"
></div>
</body>
</html>`;
generatedCode.value = html;
}
@@ -668,19 +763,25 @@ https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar
form.poweredBy.value = 'Powered by MiroTalk';
form.expertImages.value =
'https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar.cc/40?img=3';
form.btnAudio.checked =
form.btnVideo.checked =
form.btnScreen.checked =
form.btnChat.checked =
form.btnJoin.checked =
true;
toggleLabels.forEach(syncToggleVisual);
generateCode();
saveFormData();
}
// Auto-save form data to localStorage
function saveFormData() {
const data = {};
Object.keys(form).forEach((key) => {
if (form[key].type === 'checkbox') {
data[key] = form[key].checked;
} else {
data[key] = form[key].value;
}
if (!form[key]) return;
if (form[key].type === 'checkbox') data[key] = form[key].checked;
else data[key] = form[key].value;
});
localStorage.setItem('mirotalk-widget-maker', JSON.stringify(data));
}
@@ -691,27 +792,68 @@ https://i.pravatar.cc/40?img=1,https://i.pravatar.cc/40?img=2,https://i.pravatar
const data = JSON.parse(localStorage.getItem('mirotalk-widget-maker'));
if (data) {
Object.keys(data).forEach((key) => {
if (form[key]) {
if (form[key].type === 'checkbox') {
form[key].checked = data[key];
} else {
form[key].value = data[key];
}
}
if (!form[key]) return;
if (form[key].type === 'checkbox') form[key].checked = data[key];
else form[key].value = data[key];
});
generateCode();
} else {
// No saved data -> default all action buttons checked
setAllActionButtons(true);
}
} catch (err) {
// If somehow all buttons ended up unchecked, enforce default all on first load
if (
![form.btnAudio, form.btnVideo, form.btnScreen, form.btnChat, form.btnJoin].some(
(b) => b.checked
)
) {
setAllActionButtons(true);
}
toggleLabels.forEach(syncToggleVisual);
generateCode();
} catch (e) {
console.warn('Failed to load saved form data');
setAllActionButtons(true);
toggleLabels.forEach(syncToggleVisual);
generateCode();
}
}
function setAllActionButtons(state) {
form.btnAudio.checked =
form.btnVideo.checked =
form.btnScreen.checked =
form.btnChat.checked =
form.btnJoin.checked =
state;
}
// toggle handling (must be before loadFormData())
const toggleLabels = Array.from(document.querySelectorAll('#action-buttons .toggle'));
function syncToggleVisual(label) {
const cb = label.querySelector('input[type=checkbox]');
label.classList.toggle('checked', cb.checked);
}
// Attach handlers
toggleLabels.forEach((label) => {
const cb = label.querySelector('input[type=checkbox]');
const onChange = () => {
syncToggleVisual(label);
generateCode();
saveFormData();
};
cb.addEventListener('change', onChange);
// Initial state
syncToggleVisual(label);
});
// Add event listeners to all form elements
Object.values(form).forEach((element) => {
element.addEventListener('input', generateCode);
element.addEventListener('change', generateCode);
element.addEventListener('input', saveFormData);
element.addEventListener('change', saveFormData);
Object.values(form).forEach((el) => {
el.addEventListener('input', generateCode);
el.addEventListener('change', generateCode);
el.addEventListener('input', saveFormData);
el.addEventListener('change', saveFormData);
});
// Add event listeners for buttons