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 config = null;
|
||||
let activeFilter = 'all';
|
||||
let categoryById = new Map();
|
||||
|
||||
const searchInput = document.querySelector('#serviceSearch');
|
||||
const segments = [...document.querySelectorAll('.segment')];
|
||||
@@ -56,6 +57,7 @@ function serviceSearchText(service) {
|
||||
}
|
||||
|
||||
function createServiceCard(service) {
|
||||
const category = categoryById.get(service.category);
|
||||
const card = document.createElement('a');
|
||||
card.href = service.url;
|
||||
card.target = '_blank';
|
||||
@@ -72,6 +74,7 @@ function createServiceCard(service) {
|
||||
</svg>
|
||||
</div>
|
||||
<div class="card-content">
|
||||
<span class="card-category">${category?.label || 'Dienst'}</span>
|
||||
<h3>${service.name}</h3>
|
||||
<p>${service.description}</p>
|
||||
</div>
|
||||
@@ -83,32 +86,41 @@ function createServiceCard(service) {
|
||||
function renderDashboard(nextConfig) {
|
||||
dashboardSections.innerHTML = '';
|
||||
serviceCount.textContent = String(nextConfig.services.length);
|
||||
categoryById = new Map(nextConfig.categories.map((category) => [category.id, category]));
|
||||
|
||||
nextConfig.categories.forEach((category) => {
|
||||
const services = nextConfig.services.filter((service) => service.category === category.id);
|
||||
if (!services.length) return;
|
||||
|
||||
const section = document.createElement('section');
|
||||
section.className = 'section';
|
||||
section.dataset.category = category.id;
|
||||
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>
|
||||
const section = document.createElement('section');
|
||||
section.className = 'section service-overview';
|
||||
section.innerHTML = `
|
||||
<div class="section-heading">
|
||||
<div>
|
||||
<p class="section-kicker" id="overviewKicker">Dashboard</p>
|
||||
<h2 id="overviewTitle">Alle Dienste</h2>
|
||||
</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');
|
||||
services.forEach((service) => grid.appendChild(createServiceCard(service)));
|
||||
dashboardSections.appendChild(section);
|
||||
});
|
||||
const grid = section.querySelector('.grid');
|
||||
nextConfig.services.forEach((service) => grid.appendChild(createServiceCard(service)));
|
||||
dashboardSections.appendChild(section);
|
||||
|
||||
cards = [...document.querySelectorAll('.service-card')];
|
||||
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() {
|
||||
@@ -128,6 +140,7 @@ function updateVisibility() {
|
||||
section.hidden = !hasVisibleCards;
|
||||
});
|
||||
|
||||
updateOverviewHeading(visibleCards);
|
||||
emptyState.hidden = visibleCards !== 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
<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="512x512" href="/icons/icon-512.png">
|
||||
<link rel="stylesheet" href="style.css?v=13">
|
||||
<link rel="stylesheet" href="style.css?v=18">
|
||||
</head>
|
||||
<body>
|
||||
<header class="shell hero">
|
||||
@@ -73,6 +73,6 @@
|
||||
<span id="lastChecked">Status wird im Hintergrund geprueft.</span>
|
||||
</footer>
|
||||
|
||||
<script src="/app.js?v=3" defer></script>
|
||||
<script src="/app.js?v=4" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
16
style.css
16
style.css
@@ -217,6 +217,10 @@ main {
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.service-overview {
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.section[hidden],
|
||||
.service-card[hidden] {
|
||||
display: none;
|
||||
@@ -342,6 +346,18 @@ main {
|
||||
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 {
|
||||
color: #fff;
|
||||
font-size: 1.04rem;
|
||||
|
||||
Reference in New Issue
Block a user