196 lines
8.3 KiB
HTML
196 lines
8.3 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>Dynamic Glassmorphism Tile Panel</title>
|
|||
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|||
|
|
<style>
|
|||
|
|
.glass {
|
|||
|
|
background: rgba(31, 41, 55, 0.2);
|
|||
|
|
backdrop-filter: blur(10px);
|
|||
|
|
-webkit-backdrop-filter: blur(10px);
|
|||
|
|
border: 1px solid rgba(147, 51, 234, 0.3);
|
|||
|
|
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1), 0 1px 3px rgba(0, 0, 0, 0.08);
|
|||
|
|
transition: all 0.3s ease;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.glass:hover {
|
|||
|
|
background: rgba(147, 51, 234, 0.2);
|
|||
|
|
border-color: rgba(147, 51, 234, 0.7);
|
|||
|
|
box-shadow: 0 6px 12px rgba(147, 51, 234, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.glass_enabled {
|
|||
|
|
background: rgba(30, 240, 135, 0.2);
|
|||
|
|
border-color: rgba(51, 234, 127, 0.7);
|
|||
|
|
box-shadow: 0 6px 12px rgba(30, 240, 135, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gauge {
|
|||
|
|
width: 64px;
|
|||
|
|
height: 64px;
|
|||
|
|
background: conic-gradient(#a758f1 0deg, #7f0bfa var(--value), #4b5563 0);
|
|||
|
|
box-shadow: 0 6px 12px rgba(147, 51, 234, 0.3);
|
|||
|
|
border-radius: 50%;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: center;
|
|||
|
|
position: relative;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gauge::before {
|
|||
|
|
content: '';
|
|||
|
|
width: 48px;
|
|||
|
|
height: 48px;
|
|||
|
|
background: rgba(31, 41, 55, 0.9);
|
|||
|
|
border-radius: 50%;
|
|||
|
|
position: absolute;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gauge span {
|
|||
|
|
color: #d8b4fe;
|
|||
|
|
font-size: 12px;
|
|||
|
|
font-weight: bold;
|
|||
|
|
z-index: 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.clock,
|
|||
|
|
.number {
|
|||
|
|
font-size: 3rem;
|
|||
|
|
color: #d8b4fe;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
input[type="range"] {
|
|||
|
|
accent-color: #9333ea;
|
|||
|
|
box-shadow: 0 6px 12px rgba(147, 51, 234, 0.3);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.tile-content {
|
|||
|
|
min-height: 12rem;
|
|||
|
|
display: flex;
|
|||
|
|
flex-direction: column;
|
|||
|
|
justify-content: center;
|
|||
|
|
align-items: center;
|
|||
|
|
padding: 1rem;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
.gauge-tile-content {
|
|||
|
|
justify-content: flex-start;
|
|||
|
|
align-items: flex-start;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
|
|||
|
|
<body class="bg-gray-900 min-h-screen p-4" >
|
|||
|
|
<div class="container mx-auto">
|
|||
|
|
<div id="tileContainer" class="flex flex-wrap gap-4"></div>
|
|||
|
|
</div>
|
|||
|
|
<script>
|
|||
|
|
const tiles = [
|
|||
|
|
{ id: 6, type: "clock" },
|
|||
|
|
|
|||
|
|
{ id: 2, type: "gauge", gauges: [{ value: 3.60 * 10, label: "Загрузка CPU" }, { value: 3.60 * 80, label: "Занято RAM" }] },
|
|||
|
|
|
|||
|
|
{ id: 10, type: "number", value: 250, label: "Скорость сети" },
|
|||
|
|
{ id: 7, type: "slider", label: "Настройки", sliders: [{ value: 50, label: "Яроксть экрана", action: "screen.chenge_brightness" }, { value: 75, label: "Громкость звука", action: "media.set_volume" }] },
|
|||
|
|
|
|||
|
|
{ id: 10, type: "break" },
|
|||
|
|
|
|||
|
|
{ id: 3, type: "image", imageUrl: "/static/icons/steam-svgrepo-com.svg", label: "Steam" },
|
|||
|
|
{ id: 4, type: "image", imageUrl: "/static/icons/telegram-logo-svgrepo-com.svg", label: "Telegram" },
|
|||
|
|
{ id: 5, type: "image", imageUrl: "/static/icons/cloud.png", label: "Cloud" },
|
|||
|
|
|
|||
|
|
|
|||
|
|
{ id: 8, type: "image", imageUrl: "/static/icons/vpn.png", label: "VPN", enabled: true },
|
|||
|
|
|
|||
|
|
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
function createTile(tile) {
|
|||
|
|
const tileDiv = document.createElement("div");
|
|||
|
|
if (tile.type == "break") {
|
|||
|
|
tileDiv.className = "basis-full";
|
|||
|
|
document.getElementById("tileContainer").appendChild(tileDiv);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
tileDiv.id = "tile_"+tile.id;
|
|||
|
|
tileDiv.className = `glass ${tile.enabled ? "glass_enabled" : ""} rounded-lg ${tile.type === "gauge" || tile.type === "slider" || tile.type === "clock" ? "w-96 h-48" : "w-48 h-48"} ${tile.type === "image" || tile.type === "text" ? "cursor-pointer" : ""}`;
|
|||
|
|
const contentDiv = document.createElement("div");
|
|||
|
|
contentDiv.className = `tile-content ${tile.type === "gauge" ? "gauge-tile-content" : ""}`;
|
|||
|
|
|
|||
|
|
switch (tile.type) {
|
|||
|
|
case "text":
|
|||
|
|
contentDiv.innerHTML = `<span class="text-purple-400 text-lg font-semibold">${tile.label}</span>`;
|
|||
|
|
break;
|
|||
|
|
case "image":
|
|||
|
|
contentDiv.innerHTML = `<img src="${tile.imageUrl}" class="rounded-lg w-[6.3rem] h-[6.3rem] object-cover" alt="${tile.label}"><span class="mt-2 text-purple-400 text-lg font-semibold">${tile.label}</span>`;
|
|||
|
|
break;
|
|||
|
|
case "clock":
|
|||
|
|
contentDiv.innerHTML = `<span id="clock-${tile.id}" class="clock"></span><span id="date-${tile.id}" class="text-purple-400 text-lg font-semibold"></span>`;
|
|||
|
|
break;
|
|||
|
|
case "gauge":
|
|||
|
|
const gaugeContent = tile.gauges.map(g => `
|
|||
|
|
<div class="flex items-center gap-4">
|
|||
|
|
<div class="gauge" style="--value: ${g.value}deg;">
|
|||
|
|
<span>${Math.round((g.value / 360) * 100)}%</span>
|
|||
|
|
</div>
|
|||
|
|
<span class="text-purple-400 text-lg font-semibold">${g.label}</span>
|
|||
|
|
</div>
|
|||
|
|
`).join("");
|
|||
|
|
contentDiv.innerHTML = `<div class="flex flex-col gap-4">${gaugeContent}</div>`;
|
|||
|
|
break;
|
|||
|
|
case "slider":
|
|||
|
|
const sliderContent = tile.sliders.map((s, index) => `
|
|||
|
|
<div class="flex flex-col items-start">
|
|||
|
|
<div class="flex items-center gap-2">
|
|||
|
|
<span class="text-purple-400 text-sm font-semibold">${s.label}</span>
|
|||
|
|
<span id="slider-value-${tile.id}-${index}" class="text-purple-300 text-sm font-normal">${s.value}</span>
|
|||
|
|
</div>
|
|||
|
|
<input type="range" min="0" max="100" value="${s.value}" class="w-full" data-tile-id="${tile.id}" data-slider-index="${index}">
|
|||
|
|
</div>
|
|||
|
|
`).join("");
|
|||
|
|
contentDiv.innerHTML = `<span class="text-purple-400 text-lg font-semibold mb-2">${tile.label}</span><div class="flex flex-col w-full gap-4">${sliderContent}</div>`;
|
|||
|
|
break;
|
|||
|
|
case "number":
|
|||
|
|
contentDiv.innerHTML = `<span class="number">${tile.value}</span><span class="text-purple-400 text-lg font-semibold">${tile.label}</span>`;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tileDiv.appendChild(contentDiv);
|
|||
|
|
document.getElementById("tileContainer").appendChild(tileDiv);
|
|||
|
|
|
|||
|
|
if (tile.type === "clock") {
|
|||
|
|
function updateClock() {
|
|||
|
|
const now = new Date();
|
|||
|
|
const time = now.toLocaleTimeString('ru-RU', { hour12: false });
|
|||
|
|
const options = { weekday: 'short', day: 'numeric', month: 'long', year: 'numeric' };
|
|||
|
|
const date = now.toLocaleDateString('ru-RU', options)
|
|||
|
|
.replace(/,/, '')
|
|||
|
|
.replace(/(\d+)\s(\S+)/, '$1 $2')
|
|||
|
|
.replace(/г\./, '');
|
|||
|
|
document.getElementById(`clock-${tile.id}`).textContent = time;
|
|||
|
|
document.getElementById(`date-${tile.id}`).textContent = date.charAt(0).toUpperCase() + date.slice(1);
|
|||
|
|
}
|
|||
|
|
updateClock();
|
|||
|
|
setInterval(updateClock, 1000);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (tile.type === "slider") {
|
|||
|
|
tile.sliders.forEach((_, index) => {
|
|||
|
|
const slider = contentDiv.querySelector(`input[data-tile-id="${tile.id}"][data-slider-index="${index}"]`);
|
|||
|
|
const valueSpan = document.getElementById(`slider-value-${tile.id}-${index}`);
|
|||
|
|
slider.addEventListener("input", (e) => {
|
|||
|
|
valueSpan.textContent = e.target.value;
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tiles.forEach(createTile);
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
|
|||
|
|
</html>
|