Add companion planting section to species detail page and redesign home page

Species detail now shows a "Companion Plants" card (left column, after
Ecology) with beneficial/antagonistic sub-lists. Each entry links to
the companion species and shows the mechanism.

Home page gains stats cards, quick-filter buttons, and a hero section.
Species list supports URL query params for quick-filter links.
New /api/v1/stats endpoint provides database counts.

i18n keys added for DE/EN: card.companion_plants, companions.beneficial_for,
companions.antagonistic_for, stat.*, filter.*, home.*.
This commit is contained in:
2026-03-16 11:18:10 +01:00
parent 0ef902cc91
commit 00e26b3a84
9 changed files with 518 additions and 10 deletions
+206
View File
@@ -904,6 +904,148 @@ tr:hover td {
font-weight: 500;
}
/* Hero section */
.hero {
text-align: center;
padding: 2rem 0 1.5rem;
}
.hero-title {
font-size: 2.5rem;
font-weight: 700;
color: var(--accent);
margin-bottom: 0.25rem;
}
.hero-subtitle {
font-size: 1.1rem;
color: var(--text-muted);
margin-bottom: 0;
}
/* Stats cards */
.stats-row {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 1rem;
margin: 1.5rem 0;
}
.stat-card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1rem;
text-align: center;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
align-items: center;
gap: 0.25rem;
transition: box-shadow 0.15s, transform 0.15s;
}
.stat-card:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
transform: translateY(-1px);
}
.stat-card-loading {
opacity: 0.4;
}
.stat-icon {
font-size: 1.5rem;
line-height: 1;
}
.stat-value {
font-size: 1.8rem;
font-weight: 700;
color: var(--accent);
line-height: 1.2;
}
.stat-label {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-muted);
font-weight: 500;
}
/* Quick filters */
.quick-filters {
display: flex;
flex-wrap: wrap;
gap: 0.75rem;
margin-bottom: 2rem;
}
.quick-filter-btn {
display: inline-flex;
align-items: center;
gap: 0.5rem;
padding: 0.6rem 1.1rem;
border: 1px solid var(--border);
border-radius: var(--radius);
background: var(--bg-card);
color: var(--text);
font-size: 0.9rem;
font-weight: 500;
text-decoration: none;
box-shadow: var(--shadow);
transition: all 0.15s;
cursor: pointer;
}
.quick-filter-btn:hover {
border-color: var(--accent);
background: var(--accent-light);
color: var(--accent);
text-decoration: none;
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.qf-icon {
font-size: 1.1rem;
line-height: 1;
}
.qf-nitrogen { border-left: 3px solid #4caf50; }
.qf-bee { border-left: 3px solid #ffc107; }
.qf-ground { border-left: 3px solid #8bc34a; }
.qf-tree { border-left: 3px solid #795548; }
@media (max-width: 768px) {
.hero-title {
font-size: 1.8rem;
}
.stats-row {
grid-template-columns: repeat(3, 1fr);
}
.quick-filters {
gap: 0.5rem;
}
.quick-filter-btn {
padding: 0.5rem 0.8rem;
font-size: 0.8rem;
}
}
@media (max-width: 480px) {
.stats-row {
grid-template-columns: repeat(2, 1fr);
}
}
/* 404 */
.not-found {
@@ -1429,3 +1571,67 @@ td.placeholder {
align-self: center;
}
}
/* Companion planting on species detail page */
.companion-detail-body {
padding: 0.75rem 1rem 1rem;
}
.companion-sub {
font-size: 0.95rem;
font-weight: 600;
margin: 0.75rem 0 0.35rem;
padding-bottom: 0.25rem;
border-bottom: 2px solid;
}
.companion-sub:first-child {
margin-top: 0;
}
.companion-sub.beneficial {
color: var(--green, #2e7d32);
border-color: var(--green, #2e7d32);
}
.companion-sub.antagonistic {
color: var(--red, #c62828);
border-color: var(--red, #c62828);
}
.companion-list {
list-style: none;
padding: 0;
margin: 0 0 0.5rem;
}
.companion-list li {
padding: 0.3rem 0;
line-height: 1.45;
}
.companion-icon {
font-weight: 700;
}
.companion-icon.beneficial {
color: var(--green, #2e7d32);
}
.companion-icon.antagonistic {
color: var(--red, #c62828);
}
.companion-detail-link {
color: var(--link, #1565c0);
text-decoration: none;
}
.companion-detail-link:hover {
text-decoration: underline;
}
.companion-mechanism-inline {
color: var(--text-muted, #666);
font-size: 0.9em;
}