the customization code bellow is based on these threads:
@import url("https://fonts.googleapis.com/css2?family=Raleway:wght@700;800&display=swap");
#app {
background-position: right;
}
#app #sortable,
#app main {
padding: 20px;
}
#config-buttons {
bottom: 50%;
transform: translateY(50%);
border-top-left-radius: 10px;
border-bottom-left-radius: 10px;
box-shadow: rgba(255, 255, 255, 0.1) -1px 1px 1px 0, rgba(255, 255, 255, 0.1) 0 -1px 1px 0, rgba(0, 0, 0, 0.1) -1px 0 20px 5px;
background-color: rgba(110, 111, 110, 0.4);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
#config-buttons a {
background: none;
}
#config-buttons a svg {
transition: all 0.1s ease-in-out;
color: rgba(255, 255, 255, 0.5);
}
#config-buttons a:hover svg {
transform: scale(1.1);
color: rgba(192, 195, 193, 0.95);
}
.black {
color: white !important;
}
.item {
box-shadow: rgba(0, 0, 0, 0.05) -1px -1px 5px 0, rgba(0, 0, 0, 0.15) 0px 20px 25px -5px, rgba(0, 0, 0, 0.04) 0px 10px 10px -5px !important;
border-radius: 12px;
background-image: none;
border: none;
outline: none;
height: 100px;
width: 300px;
margin: 1.25rem;
padding: 1rem 55px 1rem 1rem;
transition: all 0.25s ease-in-out;
transition-property: transform, box-shadow, background-color;
background-color: rgba(110, 111, 110, 0.4) !important;
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.item:after {
height: 100px;
opacity: 0.2;
}
.item:hover {
transform: scale(1.1);
background-color: rgba(110, 111, 110, 0.4) !important;
box-shadow: rgba(0, 0, 0, 0.1) 0px 60px 40px -7px !important;
}
.item .svg-inline--fa {
height: 100px;
vertical-align: middle;
opacity: 0.2;
}
@media only screen and (max-width: 750px) {
.item {
padding-top: 2rem;
padding-bottom: 2rem;
}
#config-buttons {
display: none;
}
}
.details * {
color: white !important;
}
.details {
padding: 0 0.5rem;
}
.app-icon {
filter: drop-shadow(1px 1px 2px rgba(10, 0, 20, 0.1));
}
.livestats-container {
margin-top: 0.5rem;
}
.livestats-container .livestats .title {
margin-bottom: 3px;
}
.livestats-container .livestats li {
padding-right: 1rem;
}
.livestats-container strong {
font-weight: 500 !important;
padding: 0 2px;
}
.details>.title {
font-weight: 800;
font-size: 1.3rem !important;
letter-spacing: 1px;
font-family: "Raleway", sans-serif;
text-shadow: rgba(10, 0, 60, 0.25) 1px 0 5px;
text-shadow: -1px -1px 1px rgba(255, 255, 255, 0.1), 1px 1px 2px rgba(10, 0, 60, 0.25);
transition: all 0.25s ease-in-out;
}
.item:hover .details>.title {
text-shadow: -1px -1px 1px rgba(255, 255, 255, 0.1), 1px 1px 5px rgba(10, 0, 60, 0.2);
}
.item-container .tooltip {
z-index: -1;
}
#sortable {
display: flex;
flex-wrap: wrap;
align-items: start !important;
gap: 1rem;
opacity: 0;
}
.tags-container-parent{
background-color: rgb(255 255 255 / 26%);
border-radius: 10px;
}
.tags-container {
flex: 1;
display: grid;
grid-template-columns: repeat(2, 50%);
}
.tags-title {
color: #fff;
font-weight: 800;
font-size: 1.3rem !important;
letter-spacing: 1px;
font-family: "Raleway", sans-serif;
text-shadow: rgba(10, 0, 60, 0.25) 1px 0 5px;
text-shadow: -1px -1px 1px rgba(255, 255, 255, 0.1), 1px 1px 2px rgba(10, 0, 60, 0.25);
transition: all 0.25s ease-in-out;
text-transform: capitalize;
margin: 20px;
margin-block-end: 0;
}
$(document).ready(function () {
const base = (document.querySelector("base") || {}).href;
const container = $("#sortable");
const liveStats = () => {
let hidden, visibilityChange;
if (typeof document.hidden !== "undefined") {
// Opera 12.10 and Firefox 18 and later support
hidden = "hidden";
visibilityChange = "visibilitychange";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
}
const livestatsRefreshTimeouts = [];
const livestatsFuncs = [];
const livestatsContainers = $(".livestats-container");
function stopLivestatsRefresh() {
for (
let _i = 0, _livestatsRefreshTime = livestatsRefreshTimeouts;
_i < _livestatsRefreshTime.length;
_i++
) {
const timeoutId = _livestatsRefreshTime[_i];
window.clearTimeout(timeoutId);
}
}
function startLivestatsRefresh() {
for (
let _i2 = 0, _livestatsFuncs = livestatsFuncs;
_i2 < _livestatsFuncs.length;
_i2++
) {
const fun = _livestatsFuncs[_i2];
fun();
}
}
if (livestatsContainers.length > 0) {
if (
typeof document.addEventListener === "undefined" ||
hidden === undefined
) {
console.log("This browser does not support visibilityChange");
} else {
document.addEventListener(
visibilityChange,
function () {
if (document[hidden]) {
stopLivestatsRefresh();
} else {
startLivestatsRefresh();
}
},
false
);
}
livestatsContainers.each(function (index) {
const id = $(this).data("id");
const dataonly = $(this).data("dataonly");
const increaseby = dataonly == 1 ? 20000 : 1000;
const container = $(this);
const max_timer = 30000;
let timer = 5000;
const fun = function worker() {
$.ajax({
url: base + "get_stats/" + id,
dataType: "json",
success: function success(data) {
container.html(data.html);
if (data.status == "active") timer = increaseby;
else {
if (timer < max_timer) timer += 2000;
}
},
complete: function complete() {
// Schedule the next request when the current one's complete
livestatsRefreshTimeouts[index] = window.setTimeout(
worker,
timer
);
},
});
};
livestatsFuncs[index] = fun;
fun();
});
}
};
const customMain = () => {
if (window.location.pathname !== "/") return;
container.html("");
container.css("opacity", "1");
$.get(base + "tags", function (data) {
const tagArr = Array.from($("tbody tr td a", data));
tags = tagArr
.filter((_d, idx) => idx % 2 === 0)
.map((node) => node.href.split("/").pop());
const tagPromises = tags.map((tag) => $.get(base + "tag/" + tag));
if (tags.length === 0) return;
Promise.all(tagPromises)
.then((tagsHtml) => {
const tagsNodes = tagsHtml.map((html, idx) => {
const inner = $("#sortable", html).html();
const wrapper1 = document.createElement("div");
const wrapper2 = document.createElement("div");
wrapper1.classList.add("tags-container-parent");
wrapper2.classList.add("tags-container");
wrapper2.innerHTML = inner;
const tagTitle = document.createElement("h4");
tagTitle.classList.add("tags-title");
tagTitle.textContent = tags[idx].replaceAll("-", " ");
wrapper1.append(tagTitle);
wrapper1.append(wrapper2);
return wrapper1;
});
container.append(tagsNodes);
})
.finally(() => liveStats());
});
};
customMain();
});