add custom css support and fix push bugs

This commit is contained in:
murdle 2025-12-12 20:09:03 +02:00
parent f3fc612c99
commit 3273362bd5
6 changed files with 305 additions and 51 deletions

View File

@ -3,21 +3,46 @@ function checkServiceWorkerSupport() {
throw new Error("Your browser does not have Service Worker support")
}
async function isPushRegistered() {
checkServiceWorkerSupport();
try {
const registrations = await navigator.serviceWorker.getRegistrations();
if (!registrations?.length) return false;
return await Promise.any(
registrations.map(async (reg) => !!(await reg.pushManager.getSubscription()))
).catch(() => false);
} catch {
return false;
}
}
async function unregisterPush() {
checkServiceWorkerSupport();
try {
const registrations = await navigator.serviceWorker.getRegistrations();
if (!registrations?.length) return;
const registrations = await navigator.serviceWorker.getRegistrations();
for (const reg of registrations) {
const sub = await reg.pushManager.getSubscription();
if (sub) await sub.unsubscribe();
await reg.unregister();
await Promise.all(
registrations.map(async (reg) => {
const sub = await reg.pushManager.getSubscription();
if (sub) await sub.unsubscribe();
await reg.unregister();
})
);
} catch (err) {
console.error("Failed to unregister push:", err);
}
}
async function registerPush(publicKey) {
checkServiceWorkerSupport();
const permission = await Notification.requestPermission();
if (permission !== "granted") {
throw new Error("Notification permission not granted");
}
const registration = await navigator.serviceWorker.register("/assets/custom/serviceWorker.js");
console.log("Service Worker registered");
@ -36,7 +61,7 @@ async function registerPush(publicKey) {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": getToken()
"Authorization": window.AUTH_TOKEN
},
body: JSON.stringify({
provider: "webpush",
@ -50,20 +75,4 @@ async function registerPush(publicKey) {
const text = await response.text();
throw new Error("Failed to register: ", text)
}
}
async function isPushRegistered() {
checkServiceWorkerSupport();
const registrations = await navigator.serviceWorker.getRegistrations();
if (!registrations || registrations.length === 0) {
return false;
}
for (const reg of registrations) {
const sub = await reg.pushManager.getSubscription();
if (sub) return true;
}
return false;
}

View File

@ -1,9 +1,3 @@
let authToken = null;
function getToken() {
return authToken;
}
function urlBase64ToUint8Array(base64String) {
const padding = "=".repeat((4 - (base64String.length % 4)) % 4);
const base64 = (base64String + padding)
@ -23,7 +17,33 @@ function urlBase64ToUint8Array(base64String) {
let proxied = window.XMLHttpRequest.prototype.setRequestHeader;
window.XMLHttpRequest.prototype.setRequestHeader = function() {
if (arguments[0] === "Authorization") {
authToken = arguments[1];
window.AUTH_TOKEN = arguments[1];
}
return proxied.apply(this, [].slice.call(arguments));
};
};
window.CSS_CLASSES = {
container: "container-1zDvAE",
labelRow: "labelRow-2jl9gK",
label: "title-2dsDLn",
control: "control-1fl03-",
switchControl: "container-2nx-BQ",
switchControlChecked: "checked-25WXMf",
input: "input-2XRLou",
slider: "slider-32CRPX",
note: "note-2C4pGr",
description: "colorStandard-1Xxp1s size14-k_3Hy4 description-30xx7u formText-2ngGjI modeDefault-2fEh7a",
divider: "divider-_0um2u dividerDefault-3C2-ws",
tabItem: "item-3XjbnG",
selected: "selected-g-kMVV",
contentColumn: "contentColumn-1C7as6",
settingsRegion: "sidebarRegion-1VBisG",
contentRegion: "contentRegion-3HkfJJ",
settingsSidebar: "standardSidebarView-E9Pc3j",
title: "colorStandard-1Xxp1s size14-k_3Hy4 h1-34Txb0 title-3hptVQ defaultColor-2cKwKo defaultMarginh1-EURXsm",
hidden: "hidden-27eifz",
hamburger: "btnHamburger-3GF0_5",
};
window.AUTH_TOKEN = null;
window.localStorage_ = localStorage;

View File

@ -2,18 +2,35 @@
const BUTTON_ID = "rscord-settings-btn";
const CONTENT_CONTAINER_ID = "custom-content";
const SWITCH_CONTAINER_ID = "switch-container";
const CUSTOM_CSS_ID = "custom-css";
const CUSTOM_CSS_STORAGE = "custom_css";
const CUSTOM_CSS_INPUT_ID = "custom-css-input";
const CSS_CLASSES = {
tabItem: "item-3XjbnG",
selected: "selected-g-kMVV",
contentColumn: "contentColumn-1C7as6",
settingsRegion: "sidebarRegion-1VBisG",
contentRegion: "contentRegion-3HkfJJ",
settingsSidebar: "standardSidebarView-E9Pc3j",
title: "colorStandard-1Xxp1s size14-k_3Hy4 h1-34Txb0 title-3hptVQ defaultColor-2cKwKo defaultMarginh1-EURXsm"
title: "colorStandard-1Xxp1s size14-k_3Hy4 h1-34Txb0 title-3hptVQ defaultColor-2cKwKo defaultMarginh1-EURXsm",
miniTitle: "colorStandard-1Xxp1s size14-k_3Hy4 h5-2RwDNl title-3hptVQ title-1HgbhV",
hidden: "hidden-27eifz",
hamburger: "btnHamburger-3GF0_5",
textInput: "inputDefault-3FGxgL input-2g-os5"
};
const IS_MOBILE = window
.matchMedia("(pointer: coarse)")
.matches;
const TAB_CONTENT = `
<h2 class="${CSS_CLASSES.title}">RSCord Settings</h2>
<h5 class="${CSS_CLASSES.miniTitle}" style="margin-bottom: 10px">Options</h5>
<div id="${SWITCH_CONTAINER_ID}"></div>
<h5 class="${CSS_CLASSES.miniTitle}" style="margin-bottom: 10px">Custom CSS</h5>
<textarea id="${CUSTOM_CSS_INPUT_ID}" class="${CSS_CLASSES.textInput}" placeholder="CSS goes here" type="text" name="" style="resize: vertical;height: 400px;"></textarea>
`;
async function addSwitches(container) {
@ -39,6 +56,33 @@
));
}
function applySavedCSS() {
let css = localStorage_.getItem(CUSTOM_CSS_STORAGE) || "";
let style = document.getElementById(CUSTOM_CSS_ID);
if (!style) {
style = document.createElement("style");
style.id = CUSTOM_CSS_ID;
document.head.appendChild(style);
}
style.textContent = css;
}
function loadCustomCSS(textarea) {
if (!textarea) return;
textarea.value = localStorage_.getItem(CUSTOM_CSS_STORAGE) || "";
let style = document.getElementById(CUSTOM_CSS_ID);
if (!style) return;
textarea.addEventListener("input", () => {
const css = textarea.value;
style.textContent = css;
localStorage_.setItem(CUSTOM_CSS_STORAGE, css);
});
}
function addSettingsTab() {
const advancedTab = document.querySelector(`.${CSS_CLASSES.tabItem}[aria-controls='advanced-tab']`);
if (!advancedTab) return;
@ -69,6 +113,9 @@
addSwitches(switchContainer);
document.querySelector(`.${CSS_CLASSES.contentColumn}`).appendChild(customContent);
const cssInput = document.getElementById(CUSTOM_CSS_INPUT_ID);
loadCustomCSS(cssInput);
}
const contentColumn = document.querySelector(`.${CSS_CLASSES.contentColumn}`);
@ -91,8 +138,18 @@
}
startObserver();
applySavedCSS();
document.body.addEventListener("click", (e) => {
const clickedHamburger = e.target.closest(`.${CSS_CLASSES.hamburger}`)
if (clickedHamburger && IS_MOBILE) {
const settingsRegion = document.querySelector(`.${CSS_CLASSES.settingsRegion}`)
settingsRegion.classList.remove(CSS_CLASSES.hidden);
const contentRegion = document.querySelector(`.${CSS_CLASSES.contentRegion}`)
contentRegion.classList.add(CSS_CLASSES.hidden);
}
const clickedTab = e.target.closest('[role="tab"]');
if (!clickedTab) return;
@ -107,8 +164,19 @@
if (clickedTab.id === BUTTON_ID) {
Array.from(contentColumn.children).forEach(child => {
if (child.id === CONTENT_CONTAINER_ID) child.style.display = "block";
else child.style.display = "none";
if (child.id === CONTENT_CONTAINER_ID) {
child.style.display = "block";
} else {
child.style.display = "none";
}
if (IS_MOBILE) {
const settingsRegion = document.querySelector(`.${CSS_CLASSES.settingsRegion}`)
settingsRegion.classList.add(CSS_CLASSES.hidden);
const contentRegion = document.querySelector(`.${CSS_CLASSES.contentRegion}`)
contentRegion.classList.remove(CSS_CLASSES.hidden);
}
});
} else {
Array.from(contentColumn.children).forEach(child => {

View File

@ -1,17 +1,3 @@
const CSS_CLASSES = {
container: "container-1zDvAE",
labelRow: "labelRow-2jl9gK",
label: "title-2dsDLn",
control: "control-1fl03-",
switchControl: "container-2nx-BQ",
switchControlChecked: "checked-25WXMf",
input: "input-2XRLou",
slider: "slider-32CRPX",
note: "note-2C4pGr",
description: "colorStandard-1Xxp1s size14-k_3Hy4 description-30xx7u formText-2ngGjI modeDefault-2fEh7a",
divider: "divider-_0um2u dividerDefault-3C2-ws"
};
const ICON_PATHS = {
checked: [
"M7.89561 14.8538L6.30462 13.2629L14.3099 5.25755L15.9009 6.84854L7.89561 14.8538Z",
@ -33,6 +19,8 @@ function createSwitch(
defaultChecked = false,
onToggle = null
) {
let isToggling = false;
const container = document.createElement("div");
container.className = CSS_CLASSES.container;
@ -93,16 +81,29 @@ function createSwitch(
};
const handleToggle = async () => {
if (isToggling) return;
isToggling = true;
const prev = !checkbox.checked;
if (typeof onToggle === "function") {
const ret = await onToggle(checkbox.checked);
if (ret === false) checkbox.checked = prev;
try {
const ret = await onToggle(checkbox.checked);
if (ret === false) checkbox.checked = prev;
} finally {
isToggling = false;
}
} else {
isToggling = false;
}
updateSwitch(checkbox.checked);
};
switchControl.addEventListener("click", (e) => {
if (isToggling) return;
if (e.target === checkbox) return;
e.preventDefault();
e.stopPropagation();
checkbox.checked = !checkbox.checked;
@ -110,7 +111,11 @@ function createSwitch(
});
checkbox.addEventListener("click", (e) => {
e.stopPropagation();
if (isToggling) {
e.stopPropagation();
e.preventDefault();
return;
}
});
checkbox.addEventListener("change", handleToggle);

View File

@ -16,6 +16,12 @@
<link rel="icon" href="/assets/07dca80a102d4149e9736d4b162cff6f.ico">
<link rel="manifest" href="/assets/manifest.json">
<title>Discord</title>
<link rel="preload" as="script" href="/assets/custom/utils.js">
<link rel="preload" as="script" href="/assets/custom/pushMessages.js">
<link rel="preload" as="script" href="/assets/custom/rtcPatcher.js">
<link rel="preload" as="script" href="/assets/custom/web/switch.js">
<link rel="preload" as="script" href="/assets/custom/web/main.js">
<link rel="preload" as="script" href="/assets/053574d0f6edc579c71e.js">
<link rel="preload" as="script" href="/assets/771dcd97bfd5f9b77ef6.js">

View File

@ -0,0 +1,146 @@
<svg width="64" height="64" viewBox="0 0 64 64" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="8" height="8" fill="#29CC7A"/>
<rect x="56" y="56" width="8" height="8" fill="#29CC7A"/>
<rect x="28" y="21.6453" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="30.6667" y="21.6453" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28" y="18.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.3335" y="18.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="30.6667" y="18.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28" y="16.3119" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.3335" y="16.3119" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.6667" y="16.3119" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="30.6667" y="16.3119" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28" y="13.6453" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.3335" y="13.6453" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.6667" y="13.6453" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="30.6667" y="13.6453" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28" y="10.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.3335" y="10.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.6667" y="10.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect opacity="0.2" x="30.6667" y="10.9785" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28" y="8.31189" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.3335" y="8.31189" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 36 21.6453)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 36 18.9785)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.6667 18.9785)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 36 16.3119)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.6667 16.3119)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 41.3335 16.3119)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 36 13.6453)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.6667 13.6453)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 41.3335 13.6453)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 36 10.9785)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.6667 10.9785)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 41.3335 10.9785)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 36 8.31189)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.6667 8.31189)" fill="#29CC7A"/>
<rect x="30.6667" y="24.3119" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="30.6394" y="47.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="30.6394" y="45.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28.0273" y="45.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="17.5796" y="34.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28.0273" y="42.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="17.5796" y="31.6882" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28.0273" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="17.5796" y="29.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28.0273" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="17.5796" y="26.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.4155" y="45.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="14.9675" y="34.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.4155" y="42.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="14.9675" y="31.6882" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.4155" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="14.9675" y="29.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.4155" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="14.9675" y="26.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.8035" y="45.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="12.3555" y="34.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.8035" y="42.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="12.3555" y="31.6882" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.8035" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="12.3555" y="29.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.8035" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="12.3555" y="26.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="20.1914" y="45.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="9.74365" y="34.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="20.1914" y="42.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="9.74365" y="31.6882" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="20.1914" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="9.74365" y="29.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="20.1914" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="9.74365" y="26.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="17.5796" y="45.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="7.13159" y="34.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="17.5796" y="42.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="7.13159" y="31.6882" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="14.9128" y="42.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.9128" y="31.6882" width="2.66667" height="2.66667" transform="rotate(-180 22.9128 31.6882)" fill="#29CC7A"/>
<rect x="17.5796" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="7.13159" y="29.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="14.9128" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="22.9128" y="34.3549" width="2.66667" height="2.66667" transform="rotate(-180 22.9128 34.3549)" fill="#29CC7A"/>
<rect x="12.2461" y="39.6882" width="2.66667" height="2.66666" fill="#29CC7A"/>
<rect x="25.5796" y="34.3549" width="2.66667" height="2.66667" transform="rotate(-180 25.5796 34.3549)" fill="#29CC7A"/>
<rect x="17.5796" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="7.13159" y="26.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="14.9128" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="22.9128" y="37.0215" width="2.66667" height="2.66667" transform="rotate(-180 22.9128 37.0215)" fill="#29CC7A"/>
<rect x="12.2461" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="25.5796" y="37.0215" width="2.66667" height="2.66667" transform="rotate(-180 25.5796 37.0215)" fill="#29CC7A"/>
<rect x="9.57959" y="37.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="28.2461" y="37.0215" width="2.66667" height="2.66667" transform="rotate(-180 28.2461 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 35.9727 45.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 34.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 35.9727 42.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 31.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66666" transform="matrix(-1 0 0 1 35.9727 39.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 29.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 35.9727 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 26.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.5847 45.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 49.0327 34.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.5847 42.3549)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 49.0327 31.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66666" transform="matrix(-1 0 0 1 38.5847 39.6882)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 49.0327 29.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 38.5847 37.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 49.0327 26.3549)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 41.1968 45.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 51.6445 34.3549)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 41.1968 42.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 51.6445 31.6882)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66666" transform="matrix(-1 0 0 1 41.1968 39.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 51.6445 29.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 41.1968 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 51.6445 26.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 43.8086 45.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 54.2566 34.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 43.8086 42.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 54.2566 31.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66666" transform="matrix(-1 0 0 1 43.8086 39.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 54.2566 29.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 43.8086 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 54.2566 26.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 45.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 56.8687 34.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 42.3549)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 56.8687 31.6882)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 49.0874 42.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(1 0 0 -1 41.0874 31.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66666" transform="matrix(-1 0 0 1 46.4207 39.6882)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 56.8687 29.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66666" transform="matrix(-1 0 0 1 49.0874 39.6882)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(1 0 0 -1 41.0874 34.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66666" transform="matrix(-1 0 0 1 51.7539 39.6882)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(1 0 0 -1 38.4207 34.3549)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 46.4207 37.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 56.8687 26.3549)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(-1 0 0 1 49.0874 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(1 0 0 -1 41.0874 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 51.7539 37.0215)" fill="#29CC7A"/>
<rect width="2.66666" height="2.66667" transform="matrix(1 0 0 -1 38.4207 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(-1 0 0 1 54.4207 37.0215)" fill="#29CC7A"/>
<rect width="2.66667" height="2.66667" transform="matrix(1 0 0 -1 35.7539 37.0215)" fill="#29CC7A"/>
<rect x="30.6394" y="50.3549" width="2.66667" height="2.66667" fill="#29CC7A"/>
<rect x="30.6394" y="53.0215" width="2.66667" height="2.66667" fill="#29CC7A"/>
</svg>

After

Width:  |  Height:  |  Size: 13 KiB