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:
@@ -6,6 +6,7 @@ mod health;
|
||||
mod images;
|
||||
mod search;
|
||||
mod species;
|
||||
mod stats;
|
||||
mod suppliers;
|
||||
|
||||
use axum::http::{header, HeaderValue, StatusCode};
|
||||
@@ -44,6 +45,8 @@ pub fn router(state: AppState) -> Router {
|
||||
.route("/api/v1/images/{id}", delete(images::remove))
|
||||
// Image file serving (S3 proxy)
|
||||
.route("/img/{*path}", get(images::serve_image))
|
||||
// Stats
|
||||
.route("/api/v1/stats", get(stats::get_stats))
|
||||
// Search
|
||||
.route("/api/v1/search", get(search::search))
|
||||
// API docs
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
use axum::extract::State;
|
||||
use axum::Json;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::error::Result;
|
||||
use crate::state::AppState;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct DbStats {
|
||||
pub families: i64,
|
||||
pub species: i64,
|
||||
pub cultivars: i64,
|
||||
pub suppliers: i64,
|
||||
pub companions: i64,
|
||||
pub images: i64,
|
||||
}
|
||||
|
||||
pub async fn get_stats(State(state): State<AppState>) -> Result<Json<DbStats>> {
|
||||
let (families,): (i64,) =
|
||||
sqlx::query_as("SELECT COUNT(*) FROM families")
|
||||
.fetch_one(&state.pool)
|
||||
.await?;
|
||||
let (species,): (i64,) =
|
||||
sqlx::query_as("SELECT COUNT(*) FROM species")
|
||||
.fetch_one(&state.pool)
|
||||
.await?;
|
||||
let (cultivars,): (i64,) =
|
||||
sqlx::query_as("SELECT COUNT(*) FROM cultivars")
|
||||
.fetch_one(&state.pool)
|
||||
.await?;
|
||||
let (suppliers,): (i64,) =
|
||||
sqlx::query_as("SELECT COUNT(*) FROM suppliers")
|
||||
.fetch_one(&state.pool)
|
||||
.await?;
|
||||
let (companions,): (i64,) =
|
||||
sqlx::query_as("SELECT COUNT(*) FROM companion_relationships")
|
||||
.fetch_one(&state.pool)
|
||||
.await?;
|
||||
let (images,): (i64,) =
|
||||
sqlx::query_as("SELECT COUNT(*) FROM images")
|
||||
.fetch_one(&state.pool)
|
||||
.await?;
|
||||
|
||||
Ok(Json(DbStats {
|
||||
families,
|
||||
species,
|
||||
cultivars,
|
||||
suppliers,
|
||||
companions,
|
||||
images,
|
||||
}))
|
||||
}
|
||||
Reference in New Issue
Block a user