9c93b4e51a
Homepage gallery: - Show only 3 before/after samples as a teaser (was: all items) - Add "مشاهده گالری کامل (N نمونه)" CTA when more than 3 exist - Remove the now-pointless category tabs from the teaser New /gallery page: - Full before/after grid with category filter tabs (deduped from data) - Responsive cards with قبل/بعد labels + captions, empty state - Added to sitemap.xml (priority 0.8) Blog content editor: - New 🖼 تصویر toolbar button inserts an uploaded image at the cursor (direct upload, no forced crop) — for richer post bodies - Responsive img styling on the public post page Note: the filler-lab-soorat cover not showing is a data issue — that post has an empty featuredImage in the DB (verified); re-upload + save fixes it. The upload/save path itself is correct. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
109 lines
5.1 KiB
C#
109 lines
5.1 KiB
C#
using Microsoft.AspNetCore.Mvc.RazorPages;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using DrSousan.Api.Data;
|
|
using DrSousan.Api.Models;
|
|
|
|
namespace DrSousan.Api.Pages;
|
|
|
|
public class IndexModel : PageModel
|
|
{
|
|
private readonly AppDbContext _db;
|
|
|
|
public IndexModel(AppDbContext db) => _db = db;
|
|
|
|
// Hero
|
|
public Dictionary<string, string> Hero { get; private set; } = new();
|
|
public Dictionary<string, string> About { get; private set; } = new();
|
|
public Dictionary<string, string> Contact { get; private set; } = new();
|
|
|
|
// Collections
|
|
public List<Service> Services { get; private set; } = new();
|
|
public List<GalleryItem> Gallery { get; private set; } = new();
|
|
public int GalleryTotal { get; private set; } = 0;
|
|
public List<Testimonial> Testimonials { get; private set; } = new();
|
|
public List<BlogPost> RecentPosts { get; private set; } = new();
|
|
public List<Faq> Faqs { get; private set; } = new();
|
|
|
|
public async Task OnGetAsync()
|
|
{
|
|
var settings = await _db.SiteSettings.ToListAsync();
|
|
|
|
Hero = settings.Where(s => s.Section == "hero")
|
|
.ToDictionary(s => s.Key, s => s.Value);
|
|
About = settings.Where(s => s.Section == "about")
|
|
.ToDictionary(s => s.Key, s => s.Value);
|
|
Contact = settings.Where(s => s.Section == "contact")
|
|
.ToDictionary(s => s.Key, s => s.Value);
|
|
|
|
Services = await _db.Services
|
|
.Where(s => s.IsActive)
|
|
.OrderBy(s => s.Order)
|
|
.ToListAsync();
|
|
|
|
// Homepage shows only a teaser of 3; full set lives on /gallery
|
|
var galleryQuery = _db.GalleryItems.Where(g => g.IsActive);
|
|
GalleryTotal = await galleryQuery.CountAsync();
|
|
Gallery = await galleryQuery
|
|
.OrderBy(g => g.Order)
|
|
.Take(3)
|
|
.ToListAsync();
|
|
|
|
Testimonials = await _db.Testimonials
|
|
.Where(t => t.IsActive)
|
|
.OrderByDescending(t => t.CreatedAt)
|
|
.ToListAsync();
|
|
|
|
RecentPosts = await _db.BlogPosts
|
|
.Include(p => p.Category)
|
|
.Where(p => p.IsPublished)
|
|
.OrderByDescending(p => p.PublishedAt)
|
|
.Take(3)
|
|
.ToListAsync();
|
|
|
|
Faqs = await _db.Faqs
|
|
.Where(f => f.IsActive)
|
|
.OrderBy(f => f.Order)
|
|
.ToListAsync();
|
|
|
|
// Expose site name for layout
|
|
var siteName = Hero.GetValueOrDefault("name", "دکتر سوسن آلطه");
|
|
ViewData["SiteName"] = siteName;
|
|
ViewData["Title"] = $"{siteName} | متخصص زیبایی پوست تهران";
|
|
}
|
|
|
|
// ── Helpers for the view ─────────────────────────────────────────────────
|
|
public static string Stars(int count)
|
|
{
|
|
var s = string.Concat(Enumerable.Repeat("⭐", count));
|
|
return string.IsNullOrEmpty(s) ? "⭐⭐⭐⭐⭐" : s;
|
|
}
|
|
|
|
public static string ServiceIcon(string title) => title switch
|
|
{
|
|
var t when t.Contains("لیزر") => "✨",
|
|
var t when t.Contains("بوتاکس") || t.Contains("فیلر") => "💉",
|
|
var t when t.Contains("مزو") => "💊",
|
|
var t when t.Contains("پاکسازی") => "🧴",
|
|
var t when t.Contains("مشاوره") => "🩺",
|
|
var t when t.Contains("هایفو") || t.Contains("HIFU") => "🔬",
|
|
var t when t.Contains("RF") => "⚡",
|
|
_ => "🌟"
|
|
};
|
|
|
|
public static string ServiceIconSvg(string title) => title switch
|
|
{
|
|
var t when t.Contains("لیزر") =>
|
|
"""<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>""",
|
|
var t when t.Contains("بوتاکس") || t.Contains("فیلر") =>
|
|
"""<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 12s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>""",
|
|
var t when t.Contains("مزو") =>
|
|
"""<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"/></svg>""",
|
|
var t when t.Contains("پاکسازی") =>
|
|
"""<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="16"/><line x1="8" y1="12" x2="16" y2="12"/></svg>""",
|
|
var t when t.Contains("مشاوره") =>
|
|
"""<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>""",
|
|
_ =>
|
|
"""<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>"""
|
|
};
|
|
}
|