"name": "Nextcloud",
"href": "https://cloud.zndr.dk",
"desc": "Files, calendars, contacts.",
- "tag": "LAN/SSL"
+ "tag": "Public"
},
{
- "name": "Webmail",
+ "name": "Mail",
"href": "https://mail.zndr.dk",
- "desc": "Postfix \u00b7 Dovecot \u00b7 Roundcube.",
- "tag": "IMAP/SMTP"
+ "desc": "Webmail.",
+ "tag": "Public"
},
{
"name": "Pi-hole",
"href": "https://dns.zndr.dk/admin/",
"desc": "DNS-level ad/tracker blocking.",
- "tag": "LAN-only"
+ "tag": "LAN",
+ "lan": true
},
{
"name": "Home Assistant",
"href": "https://ha.zndr.dk",
"desc": "Automation & dashboards.",
- "tag": "Home"
+ "tag": "Home",
+ "lan": true
},
{
- "name": "Gitolite",
+ "name": "Git",
"href": "https://git.zndr.dk",
"desc": "Private repositories.",
"tag": "Git"
"desc": "Media server - movies, show, music.",
"tag": "Media"
},
+ {
+ "name": "Router",
+ "href": "https://router.zndr.dk",
+ "desc": "Router admin interface.",
+ "tag": "LAN",
+ "lan": true
+ },
+ {
+ "name": "phpMyAdmin",
+ "href": "https://db.zndr.dk/phpmyadmin/",
+ "desc": "Database management (MySQL/MariaDB).",
+ "tag": "LAN",
+ "lan": true
+ },
{
"name": "Notes / Blog",
"href": "https://zndr.dk/blog/",
outline-offset: 2px;
border-radius: 10px;
}
+.card.is-lan {
+ opacity: 0.8;
+ position: relative;
+}
+.card.is-lan::after {
+ content: '';
+ position: absolute; inset: 0;
+ pointer-events: none;
+ background: repeating-linear-gradient(
+ 45deg,
+ transparent 0 6px,
+ rgba(255,255,255,0.04) 6px 12px
+ );
+ border-radius: 14px;
+}
+@media (prefers-color-scheme: light) {
+ .card.is-lan::after {
+ background: repeating-linear-gradient(
+ 45deg,
+ transparent 0 6px,
+ rgba(0,0,0,0.03) 6px 12px
+ );
+ }
+}
+
-/* --- Optional light-mode fallback (in case your OS/browser is in light mode) --- */
@media (prefers-color-scheme: light) {
:root {
--bg: #f6f7fb;
---
layout: layouts/base.njk
-title: zndr.dk — links
+title: zndr.dk — Services
---
-<div class="search" role="search">
- <input id="filter" placeholder="Filter services… (press / to focus)" autocomplete="off" aria-label="Filter services" />
-</div>
+<h2 style="margin:0 0 .5rem 0;">Services</h2>
-<main class="grid" id="grid" aria-live="polite">
+<main class="grid" id="grid">
{% for s in services %}
- <a class="card" href="{{ s.href }}" rel="noopener">
+ <a class="card{% if s.lan %} is-lan{% endif %}"
+ href="{{ s.href }}"
+ rel="noopener noreferrer">
{% if s.tag %}<span class="chip">{{ s.tag }}</span>{% endif %}
<h3>{{ s.name }}</h3>
<p>{{ s.desc }}</p>
{% endfor %}
</main>
-<script>
- (function(){
- const f = document.getElementById('filter');
- const cards = Array.from(document.querySelectorAll('.card'));
- function apply(){
- const q = f.value.toLowerCase().trim();
- cards.forEach(c => { c.style.display = c.innerText.toLowerCase().includes(q) ? '' : 'none'; });
- }
- f.addEventListener('input', apply);
- })();
-</script>