Simplify dashboard service layout
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 12s
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 12s
This commit is contained in:
53
app.js
53
app.js
@@ -17,6 +17,7 @@ let cards = [];
|
|||||||
let sections = [];
|
let sections = [];
|
||||||
let config = null;
|
let config = null;
|
||||||
let activeFilter = 'all';
|
let activeFilter = 'all';
|
||||||
|
let categoryById = new Map();
|
||||||
|
|
||||||
const searchInput = document.querySelector('#serviceSearch');
|
const searchInput = document.querySelector('#serviceSearch');
|
||||||
const segments = [...document.querySelectorAll('.segment')];
|
const segments = [...document.querySelectorAll('.segment')];
|
||||||
@@ -56,6 +57,7 @@ function serviceSearchText(service) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createServiceCard(service) {
|
function createServiceCard(service) {
|
||||||
|
const category = categoryById.get(service.category);
|
||||||
const card = document.createElement('a');
|
const card = document.createElement('a');
|
||||||
card.href = service.url;
|
card.href = service.url;
|
||||||
card.target = '_blank';
|
card.target = '_blank';
|
||||||
@@ -72,6 +74,7 @@ function createServiceCard(service) {
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
|
<span class="card-category">${category?.label || 'Dienst'}</span>
|
||||||
<h3>${service.name}</h3>
|
<h3>${service.name}</h3>
|
||||||
<p>${service.description}</p>
|
<p>${service.description}</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -83,32 +86,41 @@ function createServiceCard(service) {
|
|||||||
function renderDashboard(nextConfig) {
|
function renderDashboard(nextConfig) {
|
||||||
dashboardSections.innerHTML = '';
|
dashboardSections.innerHTML = '';
|
||||||
serviceCount.textContent = String(nextConfig.services.length);
|
serviceCount.textContent = String(nextConfig.services.length);
|
||||||
|
categoryById = new Map(nextConfig.categories.map((category) => [category.id, category]));
|
||||||
|
|
||||||
nextConfig.categories.forEach((category) => {
|
const section = document.createElement('section');
|
||||||
const services = nextConfig.services.filter((service) => service.category === category.id);
|
section.className = 'section service-overview';
|
||||||
if (!services.length) return;
|
section.innerHTML = `
|
||||||
|
<div class="section-heading">
|
||||||
const section = document.createElement('section');
|
<div>
|
||||||
section.className = 'section';
|
<p class="section-kicker" id="overviewKicker">Dashboard</p>
|
||||||
section.dataset.category = category.id;
|
<h2 id="overviewTitle">Alle Dienste</h2>
|
||||||
section.innerHTML = `
|
|
||||||
<div class="section-heading">
|
|
||||||
<div>
|
|
||||||
<p class="section-kicker">${category.label}</p>
|
|
||||||
<h2>${category.title}</h2>
|
|
||||||
</div>
|
|
||||||
<span class="section-count">${services.length} ${services.length === 1 ? 'Dienst' : 'Dienste'}</span>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="grid"></div>
|
<span class="section-count" id="overviewCount">${nextConfig.services.length} Dienste</span>
|
||||||
`;
|
</div>
|
||||||
|
<div class="grid"></div>
|
||||||
|
`;
|
||||||
|
|
||||||
const grid = section.querySelector('.grid');
|
const grid = section.querySelector('.grid');
|
||||||
services.forEach((service) => grid.appendChild(createServiceCard(service)));
|
nextConfig.services.forEach((service) => grid.appendChild(createServiceCard(service)));
|
||||||
dashboardSections.appendChild(section);
|
dashboardSections.appendChild(section);
|
||||||
});
|
|
||||||
|
|
||||||
cards = [...document.querySelectorAll('.service-card')];
|
cards = [...document.querySelectorAll('.service-card')];
|
||||||
sections = [...document.querySelectorAll('.section')];
|
sections = [...document.querySelectorAll('.section')];
|
||||||
|
updateOverviewHeading(nextConfig.services.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateOverviewHeading(visibleCards) {
|
||||||
|
const activeCategory = categoryById.get(activeFilter);
|
||||||
|
const term = normalize(searchInput.value);
|
||||||
|
const kicker = document.querySelector('#overviewKicker');
|
||||||
|
const title = document.querySelector('#overviewTitle');
|
||||||
|
const count = document.querySelector('#overviewCount');
|
||||||
|
if (!kicker || !title || !count) return;
|
||||||
|
|
||||||
|
kicker.textContent = activeCategory ? activeCategory.label : 'Dashboard';
|
||||||
|
title.textContent = activeCategory ? activeCategory.title : 'Alle Dienste';
|
||||||
|
count.textContent = `${visibleCards} ${visibleCards === 1 ? 'Dienst' : 'Dienste'}${term ? ' gefunden' : ''}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateVisibility() {
|
function updateVisibility() {
|
||||||
@@ -128,6 +140,7 @@ function updateVisibility() {
|
|||||||
section.hidden = !hasVisibleCards;
|
section.hidden = !hasVisibleCards;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
updateOverviewHeading(visibleCards);
|
||||||
emptyState.hidden = visibleCards !== 0;
|
emptyState.hidden = visibleCards !== 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,7 @@
|
|||||||
<link rel="apple-touch-icon" href="/icons/apple-touch-icon-v2.png">
|
<link rel="apple-touch-icon" href="/icons/apple-touch-icon-v2.png">
|
||||||
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png">
|
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png">
|
||||||
<link rel="icon" type="image/png" sizes="512x512" href="/icons/icon-512.png">
|
<link rel="icon" type="image/png" sizes="512x512" href="/icons/icon-512.png">
|
||||||
<link rel="stylesheet" href="style.css?v=13">
|
<link rel="stylesheet" href="style.css?v=18">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header class="shell hero">
|
<header class="shell hero">
|
||||||
@@ -73,6 +73,6 @@
|
|||||||
<span id="lastChecked">Status wird im Hintergrund geprueft.</span>
|
<span id="lastChecked">Status wird im Hintergrund geprueft.</span>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<script src="/app.js?v=3" defer></script>
|
<script src="/app.js?v=4" defer></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
16
style.css
16
style.css
@@ -217,6 +217,10 @@ main {
|
|||||||
margin-top: 18px;
|
margin-top: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.service-overview {
|
||||||
|
margin-top: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
.section[hidden],
|
.section[hidden],
|
||||||
.service-card[hidden] {
|
.service-card[hidden] {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -342,6 +346,18 @@ main {
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.card-category {
|
||||||
|
display: inline-flex;
|
||||||
|
width: max-content;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
color: var(--dim);
|
||||||
|
font-size: 0.68rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
.card-content h3 {
|
.card-content h3 {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-size: 1.04rem;
|
font-size: 1.04rem;
|
||||||
|
|||||||
Reference in New Issue
Block a user