"packages": {
"": {
"name": "zndr-11ty",
+ "dependencies": {
+ "@grimlink/eleventy-plugin-lucide-icons": "^2.1.8"
+ },
"devDependencies": {
"@11ty/eleventy": "^2.0.0",
"@voxpelli/generate-favicon": "^1.1.1",
"tslib": "^2.4.0"
}
},
+ "node_modules/@grimlink/eleventy-plugin-lucide-icons": {
+ "version": "2.1.8",
+ "resolved": "https://registry.npmjs.org/@grimlink/eleventy-plugin-lucide-icons/-/eleventy-plugin-lucide-icons-2.1.8.tgz",
+ "integrity": "sha512-MaVeKcqc99RKr144z2m9bT9PZrR+Q1H3rgQUF9dlykdPOaAEAAiEGJzxJX7xyecXlx826vD8WOSh7ju5wx+jfA==",
+ "dependencies": {
+ "lucide-static": "^0.535.0"
+ }
+ },
"node_modules/@iarna/toml": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz",
"integrity": "sha512-m/M1U1f3ddMCs6Hq2tAsYThTBDaAKFDX3dwDo97GEYzamXi9SqUpjWi/Rrj/gf3X2n8ktwgZrlP1z6E3v/IExQ==",
"dev": true
},
+ "node_modules/lucide-static": {
+ "version": "0.535.0",
+ "resolved": "https://registry.npmjs.org/lucide-static/-/lucide-static-0.535.0.tgz",
+ "integrity": "sha512-wlYTSPpeyMjLjQ5jgSAENQwVfURVf2XHV5TDp8YPCJBEyWz+FJGuGB5LYBgOFvWIDOMW+AIoiA8sNd8My/nxlw=="
+ },
"node_modules/luxon": {
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.7.2.tgz",
"@11ty/eleventy": "^2.0.0",
"@voxpelli/generate-favicon": "^1.1.1",
"favicons": "^7.2.0"
+ },
+ "dependencies": {
+ "@grimlink/eleventy-plugin-lucide-icons": "^2.1.8"
}
}
"name": "Nextcloud",
"href": "https://cloud.zndr.dk",
"desc": "Files, calendars, contacts.",
- "tag": "Public"
+ "tag": "Public",
+ "icon": "cloud"
},
{
"name": "Mail",
"href": "https://mail.zndr.dk",
"desc": "Webmail.",
- "tag": "Public"
+ "tag": "Public",
+ "icon": "cloud"
},
{
"name": "Vaultwarden",
"href": "https://vault.zndr.dk",
"desc": "Password manager.",
- "tag": "Public"
+ "tag": "Public",
+ "icon": "cloud"
},
{
"name": "Home Assistant",
"href": "https://ha.zndr.dk",
"desc": "Automation & dashboards.",
- "tag": "Home"
+ "tag": "Home",
+ "icon": "cloud"
},
{
"name": "Grafana",
"href": "https://grafana.zndr.dk",
"desc": "Visualization of data.",
- "tag": "LAN"
+ "tag": "LAN",
+ "icon": "cloud"
},
{
"name": "Jellyfin",
"href": "https://play.zndr.dk",
"desc": "Media server.",
- "tag": "Media"
+ "tag": "Media",
+ "icon": "cloud"
},
{
"name": "Git",
"href": "https://git.zndr.dk",
"desc": "Private repositories.",
- "tag": "Git"
+ "tag": "Git",
+ "icon": "cloud"
},
{
"name": "Pi-hole",
"href": "https://dns.zndr.dk",
"desc": "DNS-level ad/tracker blocking.",
"tag": "LAN",
+ "icon": "cloud",
"lan": true
},
{
"href": "https://router.zndr.dk",
"desc": "Router admin interface.",
"tag": "LAN",
+ "icon": "cloud",
"lan": true
},
{
"href": "https://db.zndr.dk",
"desc": "Database management.",
"tag": "LAN",
+ "icon": "cloud",
"lan": true
},
{
"href": "https://influx.zndr.dk",
"desc": "Time-series data.",
"tag": "LAN",
+ "icon": "cloud",
"lan": true
},
{
"name": "Notes / Blog",
"href": "/blog/",
"desc": "Occasional write-ups.",
- "tag": "Notes"
+ "tag": "Notes",
+ "icon": "cloud"
},
{
"name": "Contact",
"href": "/contact/",
"desc": "How to reach me.",
- "tag": "Info"
+ "tag": "Info",
+ "icon": "cloud"
}
]
=========================== */
:root{
/* Palette */
+ --scale: 1.0;
--bg: #1a1b1e; /* page background */
--panel: #2a2b32; /* cards / inputs */
--fg: #e6e6e6; /* primary text */
--accent-strong: #059669; /* green hover */
--accent-alt: #ef4444; /* brand red */
--shadow: rgba(0,0,0,.5);
+ --tile-h: calc(100px * var(--scale));
+ --font-size: calc(20px * var(--scale));
/* Logo proportions (match favicon visual weight) */
--logo-size: 36px;
margin: 0;
font: 16px/1.6 system-ui, -apple-system, "Segoe UI", Roboto, Ubuntu, Cantarell,
"Noto Sans", Helvetica, Arial, "Apple Color Emoji", "Segoe UI Emoji";
+ font-size: var(--font-size);
background: var(--bg);
color: var(--fg);
}
/* ==========================
Grid + Cards
========================== */
-.grid{
+.grid {
display: grid;
- grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
- gap: 14px;
+ grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); /* was 240px */
+ gap: 16px; /* a bit more space */
}
+/* Lichess-like plate + glyph left, text right */
.card{
position: relative;
- border-radius: 10px;
+ display: flex;
+ align-items: center; /* center icon + text vertically */
+ gap: calc(14px * var(--scale));
+ padding: calc(12px * var(--scale)) calc(16px * var(--scale));
+ height: var(--tile-h);
+ text-align: left;
+
+ border-radius: calc(10px * var(--scale));
background: var(--panel);
border: 1px solid var(--ring);
- padding: 16px 14px 14px;
text-decoration: none;
color: inherit;
box-shadow: none;
transition: transform .12s ease, box-shadow .12s ease, border-color .12s ease;
+ overflow: hidden; /* clip overflow if text is long */
}
+/* Hover accent (optional) */
.card:hover{
transform: translateY(-1px);
border-color: var(--accent);
color: var(--muted);
}
-/* ==========================
- Chip (badge)
- - Default: green
- - LAN-only / away: red (.is-lan applied in HTML; JS removes it at home)
- - Hidden until LAN check completes: .chip--pending
- ========================== */
-.chip{
- position: absolute;
- top: 10px; right: 10px;
- font-size: .75rem;
- padding: .12rem .5rem;
- border-radius: 999px;
- font-weight: 500;
- background: var(--accent); /* solid green */
- color: #fff;
+/* Icon box with no plate */
+.tile-icon{
+ flex: 0 0 auto;
+ height: 100%; /* match card height */
+ aspect-ratio: 1 / 1; /* keep square footprint */
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: none; /* no grey plate */
}
-.card.is-lan .chip{
- background: var(--accent-alt); /* solid red */
+/* SVG scales inside, same color as text */
+.tile-glyph{
+ height: 100%; /* size relative to tile; tweak 58–70% */
+ width: auto;
+ stroke-width: calc(2.4 * var(--scale));
+ color: inherit; /* follow text color */
}
-/* Hide chips until the LAN check decides (prevents color flash) */
-.chip--pending { visibility: hidden; }
+.tile-body h3 {
+ margin: 0 0 .15rem 0;
+ font-size: calc(1rem * var(--scale)); /* slightly smaller */
+ font-weight: 600; /* was 700 */
+ color: var(--fg);
+ line-height: 1.3;
+}
+
+.tile-body p {
+ margin: 0;
+ font-size: calc(0.95rem * var(--scale));
+ color: var(--muted);
+ opacity: .9;
+}
/* =================
Footer
margin: 12px auto;
}
-
<main class="grid" id="grid">
{% for s in services %}
- <a
- class="card{% if s.lan %} is-lan{% endif %}"
- href="{{ s.href }}"
- rel="noopener noreferrer"
- {% if s.lan %} data-lan="true"{% endif %}
- >
- {% if s.tag %}<span class="chip chip--pending">{{ s.tag }}</span>{% endif %}
- <h3>{{ s.name }}</h3>
- <p>{{ s.desc }}</p>
+ <a class="card{% if s.lan %} is-lan{% endif %}" href="{{ s.href }}" rel="noopener noreferrer"{% if s.lan %} data-lan="true"{% endif %}>
+ {% if s.icon %}<div class="tile-icon">{% lucide s.icon, class="tile-glyph" %}</div>{% endif %}
+ <div class="tile-body">
+ <h3>{{ s.name }}</h3>
+ <p>{{ s.desc }}</p>
+ </div>
</a>
{% endfor %}
</main>