mirror of
https://github.com/skoelle/moonweb-site.git
synced 2026-09-17 17:00:25 +00:00
code.moonweb.org repo updates
This commit is contained in:
@@ -11,7 +11,7 @@ Monorepo für 5 statische Websites unter moonweb.org + stefankoelle.de, basieren
|
|||||||
| hub | hub.moonweb.org | Zentrale Indexseite, verlinkt alles | Fertig |
|
| hub | hub.moonweb.org | Zentrale Indexseite, verlinkt alles | Fertig |
|
||||||
| infra | infra.moonweb.org | Infrastruktur-Übersicht (Proxmox, Synology, Netzwerk) | Übersicht + 3 Detailseiten |
|
| infra | infra.moonweb.org | Infrastruktur-Übersicht (Proxmox, Synology, Netzwerk) | Übersicht + 3 Detailseiten |
|
||||||
| smarthome | smarthome.moonweb.org | Smart Home Projekte und Dashboards | Übersicht + 6 Detailseiten |
|
| smarthome | smarthome.moonweb.org | Smart Home Projekte und Dashboards | Übersicht + 6 Detailseiten |
|
||||||
| code | code.moonweb.org | GitHub-Projekte (aggregiert via .moonweb.yml) | Fertig (10 Repos) |
|
| code | code.moonweb.org | GitHub-Projekte (aggregiert via .moonweb.yml) | Fertig (14 Repos) |
|
||||||
| retro | retro.moonweb.org | Physische Retro-Hardware | Nur Übersicht (WIP) |
|
| retro | retro.moonweb.org | Physische Retro-Hardware | Nur Übersicht (WIP) |
|
||||||
|
|
||||||
### Externe Sites (SFTP-Deployment)
|
### Externe Sites (SFTP-Deployment)
|
||||||
@@ -153,3 +153,44 @@ Benötigte Secrets:
|
|||||||
- retro/ ist bewusst rudimentär gehalten
|
- retro/ ist bewusst rudimentär gehalten
|
||||||
- Querverlinkungen stefankoelle.de <-> smarthome (zukuenftig)
|
- Querverlinkungen stefankoelle.de <-> smarthome (zukuenftig)
|
||||||
- Ledmatrix ggf. nach smarthome verschieben (when ready)
|
- Ledmatrix ggf. nach smarthome verschieben (when ready)
|
||||||
|
|
||||||
|
## GitHub Aggregator
|
||||||
|
|
||||||
|
Das Skript `scripts/github-aggregator/aggregate.py` liest aus jedem public Repo unter `skoelle` die `.moonweb.yml` und generiert `code/_data/repos.json`.
|
||||||
|
|
||||||
|
### .moonweb.yml Format
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
title: "Projektname" # Pflicht
|
||||||
|
emoji: "🚀" # Pflicht
|
||||||
|
category: code # Pflicht (Filter)
|
||||||
|
subcategory: "Web Projects" # Pflicht
|
||||||
|
status: active # Optional
|
||||||
|
stack: [Python, FastAPI] # Optional
|
||||||
|
summary: "Kurzbeschreibung" # Optional (Fallback: GitHub description)
|
||||||
|
repo_url: auto # Auto (GitHub html_url)
|
||||||
|
repo: auto # Auto (GitHub name)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Valid Subcategories
|
||||||
|
|
||||||
|
- Web Projects
|
||||||
|
- Smart Home Apps
|
||||||
|
- Infra Tools
|
||||||
|
- Dev Tools
|
||||||
|
- Retro
|
||||||
|
- Maker Firmware
|
||||||
|
|
||||||
|
### Aggregator ausfuehren
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python3 -m venv .venv
|
||||||
|
.venv/bin/pip install pyyaml
|
||||||
|
.venv/bin/python scripts/github-aggregator/aggregate.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Python / pip
|
||||||
|
|
||||||
|
- Niemals `pip install` direkt ausführen
|
||||||
|
- Immer ein virtuelles Umfeld (`.venv`) anlegen und darin arbeiten
|
||||||
|
- `python3 -m venv .venv` im Projektverzeichnis
|
||||||
|
|||||||
+189
-85
@@ -1,127 +1,231 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"title": "Calendar Sync",
|
"title": "PeopleCostCounter",
|
||||||
"repo": "calender_sync",
|
"emoji": "💰",
|
||||||
"subcategory": "Automation & Sync",
|
"category": "code",
|
||||||
|
"subcategory": "Dev Tools",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"stack": [
|
"stack": [
|
||||||
"Python",
|
"HTML",
|
||||||
"FastAPI",
|
"CSS",
|
||||||
"MariaDB"
|
"JavaScript"
|
||||||
],
|
],
|
||||||
"summary": "Syncs a private Google Calendar (ICS) into MariaDB, with recurring-event expansion, soft-delete tracking, and a FastAPI web UI/REST API.",
|
"repo": "PeopleCostCounter",
|
||||||
"repo_url": "https://github.com/skoelle/calender_sync"
|
"repo_url": "https://github.com/skoelle/PeopleCostCounter",
|
||||||
},
|
"summary": "A vanilla JS single-page tool that shows in real time how much a meeting is costing, based on team size and average salary, with English and German UIs."
|
||||||
{
|
|
||||||
"title": "iCloud Contacts Sync",
|
|
||||||
"repo": "icloud-contacts-sync",
|
|
||||||
"subcategory": "Automation & Sync",
|
|
||||||
"status": "active",
|
|
||||||
"stack": [
|
|
||||||
"Python",
|
|
||||||
"MariaDB",
|
|
||||||
"CardDAV"
|
|
||||||
],
|
|
||||||
"summary": "Automated iCloud contacts sync to MariaDB via CardDAV delta sync, multi-user account mapping, birthday email digest, and a read-only API/web view behind Authelia.",
|
|
||||||
"repo_url": "https://github.com/skoelle/icloud-contacts-sync"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "DynDNS Updater",
|
|
||||||
"repo": "dyndns-updater",
|
|
||||||
"subcategory": "Automation & Sync",
|
|
||||||
"status": "active",
|
|
||||||
"stack": [
|
|
||||||
"Python",
|
|
||||||
"Docker"
|
|
||||||
],
|
|
||||||
"summary": "Cloudflare + FreeDNS DynDNS updater for FritzBox (TR-064), packaged as a Docker container.",
|
|
||||||
"repo_url": "https://github.com/skoelle/dyndns-updater"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "kctl-tui",
|
"title": "kctl-tui",
|
||||||
"repo": "kctl-tui",
|
"emoji": "🐳",
|
||||||
|
"category": "code",
|
||||||
"subcategory": "Dev Tools",
|
"subcategory": "Dev Tools",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"stack": [
|
"stack": [
|
||||||
"Go",
|
"Go",
|
||||||
"Bubble Tea"
|
"Bubbletea",
|
||||||
|
"Bubbles",
|
||||||
|
"Lipgloss",
|
||||||
|
"YAML"
|
||||||
],
|
],
|
||||||
"summary": "A terminal entry point for everyday Kubernetes work: guided context/team/namespace selection, a 3-pane k9s-style status view, guided rollout restarts, and an AWS Secrets Manager <-> Kubernetes Secret diff/sync workflow.",
|
"repo": "kctl-tui",
|
||||||
"repo_url": "https://github.com/skoelle/kctl-tui"
|
"repo_url": "https://github.com/skoelle/kctl-tui",
|
||||||
|
"summary": "A small terminal entry point (Go + Bubble Tea) for everyday Kubernetes work: guided context/team/namespace selection, a 3-pane k9s status view, guided rollout restarts, and an AWS Secrets Manager <-> Kubernetes Secret diff/force-sync workflow."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "FocusApp",
|
"title": "DynDns Updater",
|
||||||
"repo": "focusapp",
|
"emoji": "📡",
|
||||||
"subcategory": "Web Apps",
|
"category": "code",
|
||||||
"status": "active",
|
"subcategory": "Infra Tools",
|
||||||
"stack": [
|
|
||||||
"React",
|
|
||||||
"TypeScript",
|
|
||||||
"ASP.NET Core",
|
|
||||||
"MariaDB"
|
|
||||||
],
|
|
||||||
"summary": "A clean, modern todo application with drag & drop reordering. Responsive design, MariaDB persistence, Docker deployment.",
|
|
||||||
"repo_url": "https://github.com/skoelle/focusapp"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "PeopleCostCounter",
|
|
||||||
"repo": "PeopleCostCounter",
|
|
||||||
"subcategory": "Web Apps",
|
|
||||||
"status": "active",
|
|
||||||
"stack": [
|
|
||||||
"Vanilla JS"
|
|
||||||
],
|
|
||||||
"summary": "A single-page tool that shows in real time how much a meeting is costing, based on team size and average salary, with English and German UIs.",
|
|
||||||
"repo_url": "https://github.com/skoelle/PeopleCostCounter"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "MVG Departures",
|
|
||||||
"repo": "mvg-departures",
|
|
||||||
"subcategory": "Web Apps",
|
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"stack": [
|
"stack": [
|
||||||
"Python",
|
"Python",
|
||||||
"FastAPI"
|
"Flask",
|
||||||
|
"Requests",
|
||||||
|
"fritzconnection",
|
||||||
|
"APScheduler"
|
||||||
],
|
],
|
||||||
"summary": "Compact MVG/S-Bahn departure monitor with configurable stations, direction filters, and a mobile-friendly HTML/JSON view.",
|
"repo": "dyndns-updater",
|
||||||
"repo_url": "https://github.com/skoelle/mvg-departures"
|
"repo_url": "https://github.com/skoelle/dyndns-updater",
|
||||||
|
"summary": "Cloudflare + FreeDNS DynDNS-Updater for FritzBox (TR-064) as Docker Container"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "M5Stack Dashboard",
|
"title": "M5Stack Dashboard",
|
||||||
"repo": "m5stack-dashboard",
|
"emoji": "🌡️",
|
||||||
"subcategory": "Firmware & Hardware",
|
"category": "code",
|
||||||
|
"subcategory": "Maker Firmware",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"stack": [
|
"stack": [
|
||||||
"C++",
|
"C++",
|
||||||
|
"Arduino",
|
||||||
|
"ESP32",
|
||||||
"PlatformIO",
|
"PlatformIO",
|
||||||
"ESP32"
|
"ArduinoJson"
|
||||||
],
|
],
|
||||||
"summary": "M5Stack Core dashboard showing live weather, calendar events, and MVG departures. Navigate with 3 physical buttons, dark iOS-style UI.",
|
"repo": "m5stack-dashboard",
|
||||||
"repo_url": "https://github.com/skoelle/m5stack-dashboard"
|
"repo_url": "https://github.com/skoelle/m5stack-dashboard",
|
||||||
|
"summary": "M5Stack Core dashboard (ESP32) showing live weather, calendar events, and MVG (Munich transit) departures. Navigate with 3 physical buttons, dark iOS-style UI with colorful procedural icons, built with PlatformIO."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "WT32-SC01 Dashboard",
|
"title": "wt32sc01 Dashboard",
|
||||||
"repo": "wt32sc01-dashboard",
|
"emoji": "📱",
|
||||||
"subcategory": "Firmware & Hardware",
|
"category": "code",
|
||||||
|
"subcategory": "Maker Firmware",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"stack": [
|
"stack": [
|
||||||
"C++",
|
|
||||||
"PlatformIO",
|
"PlatformIO",
|
||||||
|
"Arduino",
|
||||||
"LovyanGFX",
|
"LovyanGFX",
|
||||||
"LVGL"
|
"LVGL 9",
|
||||||
|
"ArduinoJson"
|
||||||
],
|
],
|
||||||
"summary": "Touch dashboard for the WT32-SC01 Plus (ESP32-S3, compact display) showing weather, calendar events and MVG departures from local APIs.",
|
"repo": "wt32sc01-dashboard",
|
||||||
"repo_url": "https://github.com/skoelle/wt32sc01-dashboard"
|
"repo_url": "https://github.com/skoelle/wt32sc01-dashboard",
|
||||||
|
"summary": "Touch dashboard for the WT32-SC01 Plus (ESP32-S3, 3.5\" display) showing weather, calendar events and MVG departures from local APIs. Built with PlatformIO, LovyanGFX and LVGL."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"title": "Marcer GameDVD Launcher",
|
"title": "Marcer GameDVD Launcher",
|
||||||
"repo": "marcer-gamedvd-launcher",
|
"emoji": "🕹️",
|
||||||
"subcategory": "Misc",
|
"category": "code",
|
||||||
|
"subcategory": "Retro",
|
||||||
"status": "active",
|
"status": "active",
|
||||||
"stack": [
|
"stack": [
|
||||||
"C#"
|
"C#",
|
||||||
|
".NET",
|
||||||
|
"Console"
|
||||||
],
|
],
|
||||||
"summary": "Console launcher for a Atari ST/Falcon GameDVD USB stick — browse, compare, and launch games from the terminal with overlay/patch mode.",
|
"repo": "marcer-gamedvd-launcher",
|
||||||
"repo_url": "https://github.com/skoelle/marcer-gamedvd-launcher"
|
"repo_url": "https://github.com/skoelle/marcer-gamedvd-launcher",
|
||||||
|
"summary": "Console launcher for Marcer's Atari ST/Falcon GameDVD USB stick — browse, compare, and launch games from the terminal with overlay/patch mode."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Phobia Welcome Intro",
|
||||||
|
"emoji": "💾",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Retro",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"Turbo Pascal",
|
||||||
|
"DOS",
|
||||||
|
"VGA",
|
||||||
|
"SoundBlaster",
|
||||||
|
"X-LIB"
|
||||||
|
],
|
||||||
|
"repo": "dos-phobia-welcome-intro",
|
||||||
|
"repo_url": "https://github.com/skoelle/dos-phobia-welcome-intro",
|
||||||
|
"summary": "This Pascal program is an intro demo from 1994. It displays text messages and graphics using VGA graphics mode. The program handles palette changes, writes text to the screen, and manages sound through devices like PC Speaker and SoundBlaster. The main loop updates the screen and handles user input to control the demo."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "TranceMission Intros",
|
||||||
|
"emoji": "📺",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Retro",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"Turbo Pascal",
|
||||||
|
"Assembler",
|
||||||
|
"DOS",
|
||||||
|
"VGA"
|
||||||
|
],
|
||||||
|
"repo": "dos-tcm-intros",
|
||||||
|
"repo_url": "https://github.com/skoelle/dos-tcm-intros",
|
||||||
|
"summary": "These demos often showcased advanced graphics, sound, and programming techniques using Turbo Pascal and assembler."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Turbo Pascal X-LIB UNiT V0.3",
|
||||||
|
"emoji": "🎮",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Retro",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"Turbo Pascal",
|
||||||
|
"VGA Graphics",
|
||||||
|
"MS-DOS",
|
||||||
|
"X-LIB"
|
||||||
|
],
|
||||||
|
"repo": "turbopascal-xlib-unit",
|
||||||
|
"repo_url": "https://github.com/skoelle/turbopascal-xlib-unit",
|
||||||
|
"summary": "This Pascal unit, xlibunit, is a graphics library designed for use in Turbo Pascal programs. It provides various procedures for initializing and manipulating VGA graphics modes, handling color palettes, and drawing on the screen. It's particularly useful for creating graphic demos."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Focus App",
|
||||||
|
"emoji": "🎯",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Smart Home Apps",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"C#",
|
||||||
|
".NET",
|
||||||
|
"React",
|
||||||
|
"TypeScript",
|
||||||
|
"Entity Framework Core",
|
||||||
|
"MariaDB",
|
||||||
|
"Docker"
|
||||||
|
],
|
||||||
|
"repo": "focusapp",
|
||||||
|
"repo_url": "https://github.com/skoelle/focusapp",
|
||||||
|
"summary": "A clean, modern todo application with drag & drop reordering. Built with React, TypeScript, and ASP.NET Core. Features responsive design, MariaDB persistence, and Docker deployment."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Google Calender Sync",
|
||||||
|
"emoji": "📅",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Smart Home Apps",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"Python",
|
||||||
|
"FastAPI",
|
||||||
|
"Uvicorn",
|
||||||
|
"Jinja2"
|
||||||
|
],
|
||||||
|
"repo": "calender_sync",
|
||||||
|
"repo_url": "https://github.com/skoelle/calender_sync",
|
||||||
|
"summary": "Syncs a private Google Calendar (ICS) into MariaDB, with recurring-event expansion, soft-delete tracking, and a FastAPI web UI/REST API"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "MVG Departures",
|
||||||
|
"emoji": "🚇",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Smart Home Apps",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"Python",
|
||||||
|
"FastAPI",
|
||||||
|
"Uvicorn",
|
||||||
|
"Jinja2"
|
||||||
|
],
|
||||||
|
"repo": "mvg-departures",
|
||||||
|
"repo_url": "https://github.com/skoelle/mvg-departures",
|
||||||
|
"summary": "Compact MVG/S‑Bahn departure monitor (FastAPI) with configurable stations, direction filters, and a mobile‑friendly HTML and JSON view"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "iCloud Contacts Sync",
|
||||||
|
"emoji": "🔄",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Smart Home Apps",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"Python",
|
||||||
|
"FastAPI",
|
||||||
|
"Uvicorn",
|
||||||
|
"Jinja2"
|
||||||
|
],
|
||||||
|
"repo": "icloud-contacts-sync",
|
||||||
|
"repo_url": "https://github.com/skoelle/icloud-contacts-sync",
|
||||||
|
"summary": "Automated iCloud contacts sync to MariaDB via CardDAV delta sync, with a multi-user account mapping, birthday email digest, and an internal read-only API/web view behind Authelia."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "moonweb-site",
|
||||||
|
"emoji": "🌐",
|
||||||
|
"category": "code",
|
||||||
|
"subcategory": "Web Projects",
|
||||||
|
"status": "active",
|
||||||
|
"stack": [
|
||||||
|
"JavaScript",
|
||||||
|
"Eleventy",
|
||||||
|
"Nunjucks"
|
||||||
|
],
|
||||||
|
"repo": "moonweb-site",
|
||||||
|
"repo_url": "https://github.com/skoelle/moonweb-site",
|
||||||
|
"summary": "Monorepo for moonweb.org — my personal homelab hub. Five static sites (Eleventy) covering infrastructure, smart home, code, and retro hardware. Deployed to Cloudflare Pages."
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
+6
-4
@@ -4,11 +4,12 @@ section: "code"
|
|||||||
description: "Curated catalog of my public GitHub projects — automation, dev tools, web apps, and firmware."
|
description: "Curated catalog of my public GitHub projects — automation, dev tools, web apps, and firmware."
|
||||||
layout: base.njk
|
layout: base.njk
|
||||||
subcategories:
|
subcategories:
|
||||||
- "Automation & Sync"
|
- "Web Projects"
|
||||||
|
- "Smart Home Apps"
|
||||||
|
- "Infra Tools"
|
||||||
- "Dev Tools"
|
- "Dev Tools"
|
||||||
- "Web Apps"
|
- "Retro"
|
||||||
- "Firmware & Hardware"
|
- "Maker Firmware"
|
||||||
- "Misc"
|
|
||||||
---
|
---
|
||||||
<p>A curated, sorted catalog of my public GitHub projects. Each card links
|
<p>A curated, sorted catalog of my public GitHub projects. Each card links
|
||||||
directly to its repository.</p>
|
directly to its repository.</p>
|
||||||
@@ -20,6 +21,7 @@ directly to its repository.</p>
|
|||||||
{% for repo in repos %}
|
{% for repo in repos %}
|
||||||
{% if repo.subcategory == subcat %}
|
{% if repo.subcategory == subcat %}
|
||||||
<a class="card" href="{{ repo.repo_url }}">
|
<a class="card" href="{{ repo.repo_url }}">
|
||||||
|
{% if repo.emoji %}<span class="card-emoji">{{ repo.emoji }}</span>{% endif %}
|
||||||
<h3>{{ repo.title }}</h3>
|
<h3>{{ repo.title }}</h3>
|
||||||
<p>{{ repo.summary }}</p>
|
<p>{{ repo.summary }}</p>
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -59,6 +59,9 @@ def main():
|
|||||||
meta = fetch_moonweb_yml(repo["name"])
|
meta = fetch_moonweb_yml(repo["name"])
|
||||||
if not meta or meta.get("category") != "code":
|
if not meta or meta.get("category") != "code":
|
||||||
continue
|
continue
|
||||||
|
meta.setdefault("repo", repo["name"])
|
||||||
|
meta.setdefault("repo_url", repo["html_url"])
|
||||||
|
meta.setdefault("summary", repo.get("description", ""))
|
||||||
entries.append(meta)
|
entries.append(meta)
|
||||||
|
|
||||||
entries.sort(key=lambda e: (e.get("subcategory", ""), e.get("title", "")))
|
entries.sort(key=lambda e: (e.get("subcategory", ""), e.get("title", "")))
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
title: "MVG Departures"
|
title: "MVG Departures"
|
||||||
|
emoji: "🚆"
|
||||||
category: code
|
category: code
|
||||||
subcategory: "Web Apps"
|
subcategory: "Smart Home Apps"
|
||||||
status: active
|
status: active
|
||||||
stack: [Python, FastAPI]
|
stack: [Python, FastAPI]
|
||||||
hosted_on: "Docker Host Debian (PVE)"
|
|
||||||
summary: "Compact MVG/S-Bahn departure monitor with configurable stations."
|
|
||||||
repo_url: "https://github.com/skoelle/mvg-departures"
|
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ main { max-width: 1100px; margin: 0 auto; padding: 2rem; }
|
|||||||
transition: box-shadow 0.15s ease, transform 0.15s ease;
|
transition: box-shadow 0.15s ease, transform 0.15s ease;
|
||||||
}
|
}
|
||||||
.card:hover { box-shadow: 0 2px 10px rgba(0,0,0,0.08); transform: translateY(-1px); }
|
.card:hover { box-shadow: 0 2px 10px rgba(0,0,0,0.08); transform: translateY(-1px); }
|
||||||
|
.card-emoji { font-size: 1.3rem; margin-right: 0.3rem; vertical-align: middle; }
|
||||||
.card h3 { margin: 0 0 0.4rem; font-size: 1.05rem; color: var(--accent); }
|
.card h3 { margin: 0 0 0.4rem; font-size: 1.05rem; color: var(--accent); }
|
||||||
.card p { margin: 0; font-size: 0.9rem; color: #555; }
|
.card p { margin: 0; font-size: 0.9rem; color: #555; }
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user