use chrono::NaiveDate; use serde::{Deserialize, Serialize}; use std::collections::HashMap; #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)] #[serde(rename_all = "lowercase")] pub enum SiteMode { Blog, Atelier, } impl Default for SiteMode { fn default() -> Self { Self::Atelier } } #[derive(Serialize, Deserialize, Clone)] pub struct ContactLink { pub kind: String, pub label: String, pub value: String, } #[derive(Serialize, Deserialize, Clone)] pub struct SiteConfig { pub title: String, pub subtitle: String, pub welcome_title: String, pub welcome_subtitle: String, pub footer: String, pub favicon: String, pub theme: String, pub custom_css: String, #[serde(default)] pub contact_intro: String, #[serde(default)] pub contact_links: Vec, } impl Default for SiteConfig { fn default() -> Self { Self { title: "Ela's Atelier".to_string(), subtitle: "Works on paper, canvas, and elsewhere".to_string(), welcome_title: "Works on view".to_string(), welcome_subtitle: "An ongoing arrangement of pieces, sketches, and stray observations." .to_string(), footer: "Hand-arranged with care".to_string(), favicon: "/favicon.svg".to_string(), theme: "salon".to_string(), custom_css: "".to_string(), contact_intro: "".to_string(), contact_links: Vec::new(), } } } #[derive(Deserialize, Default)] pub struct SiteConfigPatch { #[serde(default)] pub title: Option, #[serde(default)] pub subtitle: Option, #[serde(default)] pub welcome_title: Option, #[serde(default)] pub welcome_subtitle: Option, #[serde(default)] pub footer: Option, #[serde(default)] pub favicon: Option, #[serde(default)] pub theme: Option, #[serde(default)] pub custom_css: Option, #[serde(default)] pub contact_intro: Option, #[serde(default)] pub contact_links: Option>, } #[derive(Serialize, Deserialize, Clone, Default)] pub struct PostMeta { pub date: NaiveDate, #[serde(default, skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub summary: Option, #[serde(default, skip_serializing_if = "Vec::is_empty")] pub tags: Vec, #[serde(default)] pub draft: bool, } #[derive(Serialize, Clone, Copy)] pub struct ImageDim { pub w: u32, pub h: u32, } #[derive(Serialize, Clone)] pub struct CoverImage { pub url: String, pub alt: String, #[serde(skip_serializing_if = "Option::is_none")] pub w: Option, #[serde(skip_serializing_if = "Option::is_none")] pub h: Option, } #[derive(Serialize, Clone)] pub struct PostInfo { pub slug: String, pub date: NaiveDate, #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(skip_serializing_if = "Option::is_none")] pub summary: Option, pub tags: Vec, pub draft: bool, pub reading_time: u32, pub excerpt: String, #[serde(skip_serializing_if = "Option::is_none")] pub cover_image: Option, pub image_count: u32, } #[derive(Serialize, Clone)] pub struct PostNeighbor { pub slug: String, #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, } #[derive(Serialize)] pub struct PostDetail { pub slug: String, pub date: NaiveDate, #[serde(skip_serializing_if = "Option::is_none")] pub title: Option, #[serde(skip_serializing_if = "Option::is_none")] pub summary: Option, pub tags: Vec, pub draft: bool, pub reading_time: u32, pub content: String, #[serde(skip_serializing_if = "Option::is_none")] pub cover_image: Option, pub image_count: u32, #[serde(skip_serializing_if = "Option::is_none")] pub prev: Option, #[serde(skip_serializing_if = "Option::is_none")] pub next: Option, #[serde(skip_serializing_if = "HashMap::is_empty")] pub dimensions: HashMap, } #[derive(Deserialize)] pub struct CreatePostRequest { pub slug: String, #[serde(default)] pub old_slug: Option, #[serde(default)] pub title: Option, #[serde(default)] pub date: Option, #[serde(default)] pub summary: Option, #[serde(default)] pub tags: Vec, #[serde(default)] pub draft: bool, pub content: String, } #[derive(Deserialize)] pub struct ContactSubmission { #[serde(default)] pub name: Option, #[serde(default)] pub email: Option, #[serde(default)] pub subject: Option, pub message: String, #[serde(default)] pub website: Option, pub started_at: i64, } #[derive(Serialize, Deserialize, Clone)] pub struct Message { pub id: String, #[serde(default, skip_serializing_if = "Option::is_none")] pub name: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub email: Option, #[serde(default, skip_serializing_if = "Option::is_none")] pub subject: Option, pub body: String, pub received_at: i64, #[serde(default, skip_serializing_if = "Option::is_none")] pub ip_hash: Option, } #[derive(Serialize)] pub struct ContactResponse { pub ok: bool, } #[derive(Serialize)] pub struct ErrorResponse { pub error: String, } #[derive(Serialize)] pub struct UploadResponse { pub url: String, } #[derive(Serialize)] pub struct FileInfo { pub name: String, pub url: String, }