Add launcher shape setting

This commit is contained in:
rajchales-monito
2026-07-30 16:52:31 +02:00
parent 480a2b3395
commit 0f3c608d86
4 changed files with 61 additions and 17 deletions
+8 -1
View File
@@ -162,10 +162,17 @@
<label>Mobil offset px <input name="mobileOffset" type="number"></label> <label>Mobil offset px <input name="mobileOffset" type="number"></label>
<fieldset class="effect-settings"> <fieldset class="effect-settings">
<legend>Online efekt tlacitka</legend> <legend>Online efekt tlacitka</legend>
<label class="full-row">Tvar tlacitka
<select name="launcherShape">
<option value="bubble">Bublina</option>
<option value="circle">Kolecko</option>
<option value="messenger">Messenger</option>
<option value="whatsapp">WhatsApp</option>
</select>
</label>
<label><input name="launcherBreathe" type="checkbox"> jemne dychani</label> <label><input name="launcherBreathe" type="checkbox"> jemne dychani</label>
<label><input name="launcherRing" type="checkbox"> svetelny prstenec</label> <label><input name="launcherRing" type="checkbox"> svetelny prstenec</label>
<label><input name="launcherHoverLabel" type="checkbox"> napis pri najeti</label> <label><input name="launcherHoverLabel" type="checkbox"> napis pri najeti</label>
<label><input name="launcherAvatar" type="checkbox"> mini avatar styl</label>
</fieldset> </fieldset>
<fieldset class="effect-settings"> <fieldset class="effect-settings">
<legend>Efekt pri nove zprave</legend> <legend>Efekt pri nove zprave</legend>
+3 -3
View File
@@ -205,10 +205,10 @@ $("#settingsForm").addEventListener("submit", async (event) => {
settings.mobile.bottomPx = Number(form.get("mobileBottom")); settings.mobile.bottomPx = Number(form.get("mobileBottom"));
settings.mobile.sideOffsetPx = Number(form.get("mobileOffset")); settings.mobile.sideOffsetPx = Number(form.get("mobileOffset"));
settings.launcherEffects = { settings.launcherEffects = {
shape: form.get("launcherShape") || "bubble",
breathe: form.get("launcherBreathe") === "on", breathe: form.get("launcherBreathe") === "on",
ring: form.get("launcherRing") === "on", ring: form.get("launcherRing") === "on",
hoverLabel: form.get("launcherHoverLabel") === "on", hoverLabel: form.get("launcherHoverLabel") === "on"
avatar: form.get("launcherAvatar") === "on"
}; };
settings.notifications = settings.notifications || {}; settings.notifications = settings.notifications || {};
settings.notifications.pulseOnAdminReply = form.get("messagePulse") === "on"; settings.notifications.pulseOnAdminReply = form.get("messagePulse") === "on";
@@ -515,10 +515,10 @@ function renderSite() {
form.mobileSide.value = s.mobile.side || "right"; form.mobileSide.value = s.mobile.side || "right";
form.mobileBottom.value = s.mobile.bottomPx || 14; form.mobileBottom.value = s.mobile.bottomPx || 14;
form.mobileOffset.value = s.mobile.sideOffsetPx || 12; form.mobileOffset.value = s.mobile.sideOffsetPx || 12;
form.launcherShape.value = s.launcherEffects?.shape || "bubble";
form.launcherBreathe.checked = s.launcherEffects?.breathe !== false; form.launcherBreathe.checked = s.launcherEffects?.breathe !== false;
form.launcherRing.checked = s.launcherEffects?.ring !== false; form.launcherRing.checked = s.launcherEffects?.ring !== false;
form.launcherHoverLabel.checked = s.launcherEffects?.hoverLabel !== false; form.launcherHoverLabel.checked = s.launcherEffects?.hoverLabel !== false;
form.launcherAvatar.checked = s.launcherEffects?.avatar !== false;
form.messagePulse.checked = s.notifications?.pulseOnAdminReply !== false; form.messagePulse.checked = s.notifications?.pulseOnAdminReply !== false;
form.messageBadge.checked = s.notifications?.badgeOnAdminReply !== false; form.messageBadge.checked = s.notifications?.badgeOnAdminReply !== false;
form.messageLabel.checked = s.notifications?.labelOnAdminReply !== false; form.messageLabel.checked = s.notifications?.labelOnAdminReply !== false;
+43 -12
View File
@@ -538,17 +538,22 @@
} }
function launcherEffectClasses(settings, isOnline) { function launcherEffectClasses(settings, isOnline) {
if (!isOnline) return "mf-offline";
const effects = settings.launcherEffects || {}; const effects = settings.launcherEffects || {};
const shape = launcherShape(effects.shape);
return [ return [
"mf-online", `mf-shape-${shape}`,
effects.breathe ? "mf-effect-breathe" : "", !isOnline ? "mf-offline" : "",
effects.ring ? "mf-effect-ring" : "", isOnline ? "mf-online" : "",
isOnline && effects.breathe ? "mf-effect-breathe" : "",
isOnline && effects.ring ? "mf-effect-ring" : "",
effects.hoverLabel ? "mf-effect-hover-label" : "", effects.hoverLabel ? "mf-effect-hover-label" : "",
effects.avatar ? "mf-effect-avatar" : ""
].filter(Boolean).join(" "); ].filter(Boolean).join(" ");
} }
function launcherShape(value) {
return ["circle", "bubble", "messenger", "whatsapp"].includes(value) ? value : "bubble";
}
function applyAdminReplyEffects(launcher, settings, unreadCount) { function applyAdminReplyEffects(launcher, settings, unreadCount) {
const notifications = settings.notifications || {}; const notifications = settings.notifications || {};
if (notifications.pulseOnAdminReply !== false) { if (notifications.pulseOnAdminReply !== false) {
@@ -598,10 +603,39 @@
width: 58px; height: 58px; border: 0; border-radius: 50%; background: ${c.brand}; color: ${c.brandText}; width: 58px; height: 58px; border: 0; border-radius: 50%; background: ${c.brand}; color: ${c.brandText};
box-shadow: 0 12px 30px rgb(0 0 0 / 22%); cursor: pointer; overflow: visible; box-shadow: 0 12px 30px rgb(0 0 0 / 22%); cursor: pointer; overflow: visible;
} }
.mf-launcher-icon, .mf-launcher-icon:before, .mf-launcher-icon:after { display: block; background: ${c.brandText}; height: 3px; border-radius: 4px; content: ""; } .mf-launcher-icon, .mf-launcher-icon:before, .mf-launcher-icon:after { display: block; content: ""; }
.mf-launcher-icon { width: 26px; margin: 0 auto; } .mf-launcher-icon { position: relative; margin: 0 auto; color: ${c.brandText}; }
.mf-launcher-icon:before { transform: translateY(-8px); } .mf-shape-circle .mf-launcher-icon, .mf-shape-circle .mf-launcher-icon:before, .mf-shape-circle .mf-launcher-icon:after { height: 3px; border-radius: 4px; background: ${c.brandText}; }
.mf-launcher-icon:after { transform: translateY(5px); width: 18px; } .mf-shape-circle .mf-launcher-icon { width: 26px; }
.mf-shape-circle .mf-launcher-icon:before { transform: translateY(-8px); }
.mf-shape-circle .mf-launcher-icon:after { transform: translateY(5px); width: 18px; }
.mf-shape-bubble .mf-launcher-icon {
width: 30px; height: 23px; border: 3px solid ${c.brandText}; border-radius: 13px; background: transparent;
}
.mf-shape-bubble .mf-launcher-icon:before {
position: absolute; left: 5px; top: 7px; width: 4px; height: 4px; border-radius: 50%; background: ${c.brandText}; box-shadow: 8px 0 0 ${c.brandText}, 16px 0 0 ${c.brandText};
}
.mf-shape-bubble .mf-launcher-icon:after {
position: absolute; right: 2px; bottom: -8px; width: 10px; height: 10px; border-left: 3px solid ${c.brandText}; border-bottom: 3px solid ${c.brandText}; border-bottom-left-radius: 8px; transform: rotate(-18deg); background: transparent;
}
.mf-shape-messenger .mf-launcher-icon {
width: 32px; height: 32px; border-radius: 50%; background: ${c.brandText};
}
.mf-shape-messenger .mf-launcher-icon:before {
position: absolute; left: 8px; top: 8px; width: 16px; height: 16px; background: ${c.brand}; clip-path: polygon(0 56%, 42% 56%, 58% 22%, 100% 22%, 58% 78%, 42% 78%);
}
.mf-shape-messenger .mf-launcher-icon:after {
position: absolute; right: 5px; bottom: 1px; width: 8px; height: 8px; border-radius: 0 0 8px 0; background: ${c.brandText}; transform: rotate(25deg);
}
.mf-shape-whatsapp .mf-launcher-icon {
width: 32px; height: 32px; border: 3px solid ${c.brandText}; border-radius: 50%; background: transparent;
}
.mf-shape-whatsapp .mf-launcher-icon:before {
position: absolute; left: 8px; top: 7px; width: 12px; height: 15px; border: 3px solid ${c.brandText}; border-left-color: transparent; border-top-color: transparent; border-radius: 0 0 12px 0; transform: rotate(-35deg);
}
.mf-shape-whatsapp .mf-launcher-icon:after {
position: absolute; left: 1px; bottom: -4px; width: 10px; height: 10px; border-left: 3px solid ${c.brandText}; border-bottom: 3px solid ${c.brandText}; transform: rotate(12deg); background: transparent;
}
.mf-launcher-label { position: absolute; ${labelOffset} top: 50%; transform: translateY(-50%) translateX(8px); opacity: 0; pointer-events: none; white-space: nowrap; border-radius: 999px; padding: 7px 10px; background: ${c.text}; color: white; font-size: 12px; box-shadow: 0 10px 24px rgb(0 0 0 / 18%); transition: opacity .18s ease, transform .18s ease; } .mf-launcher-label { position: absolute; ${labelOffset} top: 50%; transform: translateY(-50%) translateX(8px); opacity: 0; pointer-events: none; white-space: nowrap; border-radius: 999px; padding: 7px 10px; background: ${c.text}; color: white; font-size: 12px; box-shadow: 0 10px 24px rgb(0 0 0 / 18%); transition: opacity .18s ease, transform .18s ease; }
.mf-online.mf-effect-hover-label:hover .mf-launcher-label { opacity: 1; transform: translateY(-50%) translateX(0); } .mf-online.mf-effect-hover-label:hover .mf-launcher-label { opacity: 1; transform: translateY(-50%) translateX(0); }
.mf-message-label { position: absolute; ${labelOffset} top: 50%; transform: translateY(-50%) translateX(8px); opacity: 0; pointer-events: none; white-space: nowrap; border-radius: 999px; padding: 7px 10px; background: ${c.text}; color: white; font-size: 12px; font-weight: 700; box-shadow: 0 10px 24px rgb(0 0 0 / 18%); transition: opacity .18s ease, transform .18s ease; } .mf-message-label { position: absolute; ${labelOffset} top: 50%; transform: translateY(-50%) translateX(8px); opacity: 0; pointer-events: none; white-space: nowrap; border-radius: 999px; padding: 7px 10px; background: ${c.text}; color: white; font-size: 12px; font-weight: 700; box-shadow: 0 10px 24px rgb(0 0 0 / 18%); transition: opacity .18s ease, transform .18s ease; }
@@ -611,9 +645,6 @@
.mf-reply-pulse { position: absolute; inset: 0; border-radius: 50%; pointer-events: none; opacity: 0; } .mf-reply-pulse { position: absolute; inset: 0; border-radius: 50%; pointer-events: none; opacity: 0; }
.mf-online.mf-effect-breathe { animation: mfBreathe 2.8s ease-in-out infinite; } .mf-online.mf-effect-breathe { animation: mfBreathe 2.8s ease-in-out infinite; }
.mf-online.mf-effect-ring:before { position: absolute; inset: -5px; border: 2px solid ${c.brand}; border-radius: 50%; opacity: .62; content: ""; animation: mfRing 2.2s ease-out infinite; } .mf-online.mf-effect-ring:before { position: absolute; inset: -5px; border: 2px solid ${c.brand}; border-radius: 50%; opacity: .62; content: ""; animation: mfRing 2.2s ease-out infinite; }
.mf-online.mf-effect-avatar .mf-launcher-icon { width: 26px; height: 20px; border-radius: 12px 12px 10px 10px; background: rgb(255 255 255 / 24%); border: 2px solid ${c.brandText}; position: relative; }
.mf-online.mf-effect-avatar .mf-launcher-icon:before { position: absolute; left: 6px; top: 6px; width: 4px; height: 4px; border-radius: 50%; background: ${c.brandText}; transform: none; box-shadow: 10px 0 0 ${c.brandText}; }
.mf-online.mf-effect-avatar .mf-launcher-icon:after { position: absolute; left: 7px; top: 13px; width: 12px; height: 2px; border-radius: 999px; background: ${c.brandText}; transform: none; opacity: .88; }
.mf-offline { filter: grayscale(.2) saturate(.72); opacity: .86; } .mf-offline { filter: grayscale(.2) saturate(.72); opacity: .86; }
.mf-notify .mf-reply-pulse { animation: mfPulse 1.15s ease-out infinite; } .mf-notify .mf-reply-pulse { animation: mfPulse 1.15s ease-out infinite; }
.mf-wiggle .mf-launcher-icon { animation: mfWiggle .62s ease-in-out 2; } .mf-wiggle .mf-launcher-icon { animation: mfWiggle .62s ease-in-out 2; }
+7 -1
View File
@@ -337,10 +337,11 @@ function defaultSettings() {
desktop: { side: "right", bottomPx: 22, sideOffsetPx: 22, widthPx: 370 }, desktop: { side: "right", bottomPx: 22, sideOffsetPx: 22, widthPx: 370 },
mobile: { side: "right", bottomPx: 14, sideOffsetPx: 12, widthPx: 340 }, mobile: { side: "right", bottomPx: 14, sideOffsetPx: 12, widthPx: 340 },
launcherEffects: { launcherEffects: {
shape: "bubble",
breathe: true, breathe: true,
ring: true, ring: true,
hoverLabel: true, hoverLabel: true,
avatar: true avatar: false
}, },
notifications: { notifications: {
pulseOnAdminReply: true, pulseOnAdminReply: true,
@@ -2051,6 +2052,7 @@ function formatSite(site) {
const settings = parseJson(site.settings_json, defaultSettings()); const settings = parseJson(site.settings_json, defaultSettings());
settings.notifications = { ...defaultSettings().notifications, ...(settings.notifications || {}) }; settings.notifications = { ...defaultSettings().notifications, ...(settings.notifications || {}) };
settings.launcherEffects = { ...defaultSettings().launcherEffects, ...(settings.launcherEffects || {}) }; settings.launcherEffects = { ...defaultSettings().launcherEffects, ...(settings.launcherEffects || {}) };
settings.launcherEffects.shape = normalizeLauncherShape(settings.launcherEffects.shape);
settings.widgetLanguage = normalizeWidgetLanguageSettings(settings.widgetLanguage); settings.widgetLanguage = normalizeWidgetLanguageSettings(settings.widgetLanguage);
settings.widgetCopy = normalizeWidgetCopy(settings.widgetCopy || {}, settings); settings.widgetCopy = normalizeWidgetCopy(settings.widgetCopy || {}, settings);
syncLegacyWidgetCopy(settings); syncLegacyWidgetCopy(settings);
@@ -2077,6 +2079,10 @@ function formatSite(site) {
}; };
} }
function normalizeLauncherShape(value) {
return ["circle", "bubble", "messenger", "whatsapp"].includes(value) ? value : "bubble";
}
function snippetFor(site) { function snippetFor(site) {
const settings = parseJson(site.settings_json, defaultSettings()); const settings = parseJson(site.settings_json, defaultSettings());
const languageSettings = normalizeWidgetLanguageSettings(settings.widgetLanguage); const languageSettings = normalizeWidgetLanguageSettings(settings.widgetLanguage);