Added SEO keywords. Added medua upload indicator. Added Khabarovsk default
Build and Publish / Build and Publish Docker Image (push) Successful in 1m17s

This commit is contained in:
Ultradesu
2026-05-18 14:47:04 +03:00
parent 3a084a9d79
commit 77f6b5c5e2
10 changed files with 319 additions and 40 deletions
+5 -1
View File
@@ -796,6 +796,7 @@ struct SettingsForm {
pricing_info: String,
timezone: String,
site_domain: String,
seo_keywords: String,
}
async fn save_settings(request: Request, session: Session, db: Database) -> cot::Result<Response> {
@@ -811,6 +812,7 @@ async fn save_settings(request: Request, session: Session, db: Database) -> cot:
("pricing_info", form.pricing_info),
("timezone", form.timezone),
("site_domain", form.site_domain),
("seo_keywords", form.seo_keywords),
] {
let k = key.to_string();
let existing = query!(Setting, $key == k).get(&db).await?;
@@ -1172,7 +1174,7 @@ async fn schedule_events(
.unwrap_or("?");
let (bg_color, text_color) = match v.status.as_str() {
"cancelled" => ("#ccc".to_string(), "#666"),
"cancelled" => ("#ffb3b3".to_string(), "#a00"),
"completed" => (format!("{}88", client_color), "#fff"),
_ => (client_color.to_string(), "#fff"),
};
@@ -1641,8 +1643,10 @@ async fn media_delete(
.and_then(|v| v.to_str().ok())
.map(|s| s.to_string());
if let Some(mut m) = query!(Media, $id == media_id).get(&db).await? {
let file_path = m.file_path.clone();
m.status = "archived".to_string();
m.save(&db).await?;
let _ = tokio::fs::remove_file(&file_path).await;
}
let redirect_url = referer
.filter(|r| r.contains("/schedule/") && r.contains("/edit"))
+4 -1
View File
@@ -134,6 +134,7 @@ pub struct Translations {
pub settings_pricing_info: &'static str,
pub settings_timezone: &'static str,
pub settings_site_domain: &'static str,
pub settings_seo_keywords: &'static str,
pub landing_contact_label: &'static str,
pub landing_pricing_title: &'static str,
@@ -346,6 +347,7 @@ static RU: Translations = Translations {
settings_pricing_info: "Блок с ценами (отображается на лендинге)",
settings_timezone: "Часовой пояс (например Asia/Vladivostok)",
settings_site_domain: "Домен сайта (например https://example.com)",
settings_seo_keywords: "SEO-ключевые слова (через запятую, отображаются на сайте и в мета-теге keywords)",
landing_contact_label: "Или свяжитесь с нами напрямую",
landing_pricing_title: "Стоимость",
@@ -425,7 +427,7 @@ static RU: Translations = Translations {
schedule_delete_confirm: "Точно удалить этот визит?",
landing_meta_description: "Профессиональный пет-ситтинг: кормление и уход за кошками, грызунами, рептилиями на вашей территории. Оставьте заявку — позаботимся о вашем любимце!",
landing_hero_title: "Позаботимся о вашем питомце, пока вас нет дома",
landing_hero_title: "Позаботимся о вашем питомце, пока вас нет дома. Город Хабаровск",
landing_hero_subtitle: "Кормление и уход за кошками, грызунами, рептилиями на вашей территории. Ежедневные визиты — ваш питомец в надёжных руках, пока вы в отпуске или командировке.",
landing_hero_description: "Почему лучше оставить кошку дома на время отъезда, чем, скажем, поместить в зоогостиницу? Как известно — кошка территориальное животное. Поэтому, когда кошка оказывается на незнакомой территории — она может испытывать стресс. К тому же в зоогостинице животное часто содержится в клетке. А кошки любят свободу. И дома ожидать своих хозяев — ей будет гораздо проще и комфортнее.",
landing_hero_cta: "Оставить заявку",
@@ -548,6 +550,7 @@ static EN: Translations = Translations {
settings_pricing_info: "Pricing block (shown on landing page)",
settings_timezone: "Timezone (e.g. Asia/Vladivostok)",
settings_site_domain: "Site domain (e.g. https://example.com)",
settings_seo_keywords: "SEO keywords (comma-separated, shown on site and in keywords meta tag)",
landing_contact_label: "Or contact us directly",
landing_pricing_title: "Pricing",
+8
View File
@@ -71,6 +71,7 @@ struct LandingTemplate<'a> {
lang: Lang,
contact_info: String,
pricing_info: String,
seo_keywords: String,
testimonials: Vec<Testimonial>,
site_domain: String,
review_count: usize,
@@ -103,6 +104,12 @@ async fn landing_page(request: Request, db: Database) -> cot::Result<Response> {
.await?
.map(|s| s.value)
.unwrap_or_else(|| "https://example.net".to_string());
let seo_key = "seo_keywords".to_string();
let seo_keywords = query!(Setting, $key == seo_key)
.get(&db)
.await?
.map(|s| s.value)
.unwrap_or_default();
let mut testimonials = Testimonial::objects().all(&db).await?;
testimonials.retain(|t| t.status == "active");
testimonials.sort_by(|a, b| a.sort_order.cmp(&b.sort_order));
@@ -112,6 +119,7 @@ async fn landing_page(request: Request, db: Database) -> cot::Result<Response> {
lang,
contact_info,
pricing_info,
seo_keywords,
testimonials,
site_domain,
review_count,