Initial commit — AsadiTools v1.0
CI/CD / CI — dotnet build (push) Successful in 44s
CI/CD / Deploy — docker compose (push) Failing after 1s

Full ASP.NET Core 10 Razor Pages app for آساد ابزار tool repair shop
in Karaj, Iran (official DeWalt representative).

Features:
- Homepage, Services, DeWalt page, Shop (pagination + images)
- 10 brand SEO pages (/brands/*) with rich Persian content + FAQ schema
- Blog engine with admin management (/blog, /Admin/Blog)
- Cart, Checkout, Contact (OpenStreetMap embed)
- Admin panel: Products CRUD, Orders, Blog, Change Password
- Jalali date formatting, product images, SiteData centralised contact
- Docker + docker-compose with healthcheck
- Gitea CI/CD via .gitea/workflows/ci-cd.yml (NuGet through Nexus mirror)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Soroush Asadi
2026-06-01 22:08:43 +03:30
commit f97f891d67
146 changed files with 88128 additions and 0 deletions
+218
View File
@@ -0,0 +1,218 @@
@page
@model AsadiTools.Pages.Services.BrandModel
@{ ViewData["Title"] = $"تعمیر ابزار {Model.Brand?.NameFa} در کرج"; Layout = "_Layout"; }
@if (Model.Brand is null)
{
<div class="max-w-xl mx-auto text-center py-20"><p class="text-gray-500">برند یافت نشد.</p></div>
}
else
{
var b = Model.Brand;
var isDewalt = b.Id == "dewalt";
<!-- ═══════════ HERO ═══════════ -->
<div class="relative text-white py-14 px-4 overflow-hidden" style="background:linear-gradient(135deg,@b.Color+dd,@b.Color+99)">
@if (isDewalt)
{
<div class="absolute inset-0 bg-cover bg-center opacity-20"
style="background-image:url('https://images.unsplash.com/photo-1558618666-fcd25c85cd64?w=1200&q=80&auto=format&fit=crop')"></div>
}
<div class="relative max-w-6xl mx-auto flex flex-col sm:flex-row items-center gap-6">
<div class="w-20 h-20 rounded-2xl flex items-center justify-center text-2xl font-extrabold border-2 border-white/30 bg-white/20 shrink-0 shadow-lg"
style="color:@b.TextColor">
@b.Name.Substring(0, 2)
</div>
<div>
<div class="flex flex-wrap items-center gap-3 mb-2">
<h1 class="text-3xl font-extrabold" style="color:@(b.TextColor == "#fff" ? "white" : "#1f2937")">
تعمیر ابزار @b.NameFa در کرج
</h1>
@if (b.IsOfficial)
{
<span class="bg-white text-gray-900 text-sm font-bold px-3 py-1 rounded-full shadow">🛡️ نمایندگی رسمی</span>
}
</div>
<p class="opacity-90 max-w-xl" style="color:@(b.TextColor == "#fff" ? "#e0e0e0" : "#374151")">@b.Description</p>
@if (isDewalt)
{
<a href="/DeWalt" class="inline-block mt-3 bg-yellow-400 text-gray-900 font-bold text-sm px-4 py-2 rounded-lg hover:bg-yellow-300 transition-colors">
مشاهده همه ابزار دیوالت ›
</a>
}
</div>
</div>
</div>
<div class="max-w-6xl mx-auto px-4 py-12 grid lg:grid-cols-3 gap-10">
<!-- ═══════════ MAIN CONTENT ═══════════ -->
<div class="lg:col-span-2 space-y-8">
@if (b.IsOfficial)
{
<div class="bg-yellow-50 border border-yellow-200 rounded-2xl p-6">
<div class="flex items-start gap-3">
<span class="text-yellow-600 text-2xl shrink-0">🛡️</span>
<div>
<h2 class="font-bold text-gray-900 mb-2 text-lg">نمایندگی رسمی @b.NameFa در کرج</h2>
<p class="text-gray-600 text-sm leading-7">
آساد ابزار افتخار دارد نمایندگی رسمی برند @b.NameFa را در شهر کرج داشته باشد.
تمام تعمیرات توسط تکنیسین‌های آموزش‌دیده و با قطعات کاملاً اورجینال انجام می‌شود.
هر تعمیر دارای ضمانت‌نامه کتبی ۳ ماهه است.
</p>
</div>
</div>
</div>
}
<!-- DeWalt: full tools grid -->
@if (isDewalt)
{
<section>
<h2 class="text-xl font-bold text-gray-900 mb-5 pb-2 border-b flex items-center gap-2">
<span class="bg-yellow-400 text-gray-900 text-xs font-bold px-2 py-0.5 rounded">۱۵+ مدل</span>
ابزار دیوالت که تعمیر می‌کنیم
</h2>
<div class="grid sm:grid-cols-2 gap-4">
@{
var catImgs = new Dictionary<string, string>
{
["drill"] = "https://images.unsplash.com/photo-1572981779307-38b8cabb2407?w=400&q=70&auto=format&fit=crop",
["driver"] = "https://images.unsplash.com/photo-1530124566582-a618bc2615dc?w=400&q=70&auto=format&fit=crop",
["grinder"] = "https://images.unsplash.com/photo-1487452066049-a710f7296400?w=400&q=70&auto=format&fit=crop",
["rotary-hammer"] = "https://images.unsplash.com/photo-1504307651254-35680f356dfd?w=400&q=70&auto=format&fit=crop",
["saw"] = "https://images.unsplash.com/photo-1504148455328-c376907d081c?w=400&q=70&auto=format&fit=crop",
["chop-saw"] = "https://images.unsplash.com/photo-1503387762-592deb58ef4e?w=400&q=70&auto=format&fit=crop",
["miter-saw"] = "https://images.unsplash.com/photo-1558618047-3c8c1d8b9df1?w=400&q=70&auto=format&fit=crop",
["woodworking"] = "https://images.unsplash.com/photo-1588854337115-1c67d9247e4d?w=400&q=70&auto=format&fit=crop",
["multi"] = "https://images.unsplash.com/photo-1518770660439-4636190af475?w=400&q=70&auto=format&fit=crop",
["sander"] = "https://images.unsplash.com/photo-1581579438747-1dc8d17bbce4?w=400&q=70&auto=format&fit=crop",
["hedge-trimmer"] = "https://images.unsplash.com/photo-1416879595882-3373a0480b5b?w=400&q=70&auto=format&fit=crop",
["laser-level"] = "https://images.unsplash.com/photo-1609220136736-443140cfeaa8?w=400&q=70&auto=format&fit=crop",
["laser-measure"] = "https://images.unsplash.com/photo-1518770660439-4636190af475?w=400&q=70&auto=format&fit=crop",
};
}
@foreach (var tool in SiteData.DeWaltTools)
{
var img = catImgs.TryGetValue(tool.CategoryId, out var tu) ? tu : catImgs["drill"];
<div class="bg-white rounded-2xl border border-gray-100 overflow-hidden hover:shadow-md transition-shadow">
<div class="relative h-36 overflow-hidden">
<img src="@img" alt="تعمیر @tool.NameFa" loading="lazy"
class="w-full h-full object-cover" />
<div class="absolute inset-0 bg-gradient-to-t from-black/60 to-transparent"></div>
<div class="absolute top-2 left-2">
<span class="bg-yellow-400 text-gray-900 text-xs font-bold px-1.5 py-0.5 rounded">@tool.Power</span>
</div>
<div class="absolute bottom-2 right-3 text-2xl">@tool.Icon</div>
</div>
<div class="p-4">
<h3 class="font-bold text-gray-900 text-sm mb-0.5">@tool.NameFa</h3>
<p class="text-xs text-gray-400 font-mono mb-2">@string.Join(" · ", tool.Models.Take(3))</p>
<div class="flex flex-wrap gap-1">
@foreach (var r in tool.RepairItems.Take(3))
{
<span class="text-xs bg-yellow-50 text-yellow-800 border border-yellow-100 px-1.5 py-0.5 rounded">@r</span>
}
@if (tool.RepairItems.Length > 3)
{
<span class="text-xs text-gray-400">+@(tool.RepairItems.Length - 3) مورد دیگر</span>
}
</div>
</div>
</div>
}
</div>
<div class="mt-6 text-center">
<a href="/DeWalt" class="inline-block bg-yellow-400 text-gray-900 font-bold px-6 py-3 rounded-xl hover:bg-yellow-300 transition-colors">
مشاهده صفحه کامل ابزار دیوالت ›
</a>
</div>
</section>
}
else
{
<!-- Non-DeWalt brands: existing tool service cards -->
<section>
<h2 class="text-xl font-bold text-gray-900 mb-5 pb-2 border-b">خدمات تعمیر @b.NameFa</h2>
<div class="space-y-4">
@foreach (var tool in SiteData.ToolTypes.Where(t => b.Services.Contains(t.NameFa)))
{
<div class="bg-white rounded-2xl border border-gray-100 p-6 hover:shadow-sm transition-shadow">
<div class="flex items-center gap-3 mb-3">
<span class="text-2xl">@tool.Icon</span>
<h3 class="font-bold text-gray-900">تعمیر @tool.NameFa @b.NameFa</h3>
</div>
<p class="text-gray-500 text-sm leading-7 mb-4">@tool.Description</p>
<ul class="grid grid-cols-1 sm:grid-cols-2 gap-2">
@foreach (var issue in tool.CommonIssues)
{
<li class="flex items-start gap-2 text-sm text-gray-600">
<span class="text-green-500 shrink-0">✓</span> @issue
</li>
}
</ul>
</div>
}
</div>
</section>
}
<!-- Repair process -->
<section>
<h2 class="text-xl font-bold text-gray-900 mb-5 pb-2 border-b">فرآیند تعمیر</h2>
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
@foreach (var step in new[] { ("۱","تحویل ابزار","حضوری یا پست"), ("۲","بررسی رایگان","تشخیص سریع"), ("۳","تعمیر تخصصی","قطعه اصل"), ("۴","تحویل با ضمانت","۳ ماه گارانتی") })
{
<div class="text-center p-4 bg-gray-50 rounded-2xl">
<div class="w-10 h-10 rounded-full flex items-center justify-center text-white font-bold mx-auto mb-3 shadow"
style="background-color:@b.Color;color:@b.TextColor">@step.Item1</div>
<div class="font-bold text-gray-800 text-sm">@step.Item2</div>
<div class="text-xs text-gray-400 mt-1">@step.Item3</div>
</div>
}
</div>
</section>
</div>
<!-- ═══════════ SIDEBAR ═══════════ -->
<div class="space-y-5">
<div class="rounded-2xl p-6 text-white" style="background-color:@b.Color">
<h3 class="font-bold text-lg mb-1" style="color:@(b.TextColor == "#fff" ? "white" : "#1f2937")">درخواست تعمیر</h3>
<p class="text-sm mb-5 opacity-80" style="color:@(b.TextColor == "#fff" ? "#e0e0e0" : "#374151")">مشاوره رایگان – تماس بگیرید</p>
<a href="tel:@SiteData.Company.TelPhone" class="block bg-white font-bold text-center py-3 rounded-xl hover:opacity-90 mb-3 transition-opacity"
style="color:@b.Color">📞 @SiteData.Company.Phone</a>
<a href="https://wa.me/@SiteData.Company.Whatsapp" target="_blank"
class="block bg-green-500 text-white font-bold text-center py-3 rounded-xl hover:bg-green-600 transition-colors">💬 واتساپ</a>
</div>
<div class="bg-white rounded-2xl border p-6">
<h3 class="font-bold text-gray-900 mb-4">⭐ مزایای خدمات ما</h3>
<ul class="space-y-2.5 text-sm text-gray-600">
@foreach (var item in new[] { "بررسی و تشخیص عیب رایگان", "قطعات ۱۰۰٪ اورجینال", "ضمانت‌نامه کتبی ۳ ماهه", "تکنیسین مجاز و متخصص", "قیمت شفاف قبل از شروع کار", "تحویل سریع زیر ۴۸ ساعت", "ارسال و دریافت از سراسر کشور" })
{
<li class="flex items-center gap-2">
<span class="text-green-500 shrink-0">✓</span> @item
</li>
}
</ul>
</div>
@if (isDewalt)
{
<div class="bg-yellow-50 border border-yellow-200 rounded-2xl p-5">
<h3 class="font-bold text-gray-900 mb-3">🔩 قطعات موجود DeWalt</h3>
<div class="flex flex-wrap gap-1.5">
@foreach (var p in new[] { "کاربن", "بیرینگ", "آرمیچر", "گیربکس", "چاک", "کلید", "استاتور", "پیستون" })
{
<span class="text-xs bg-yellow-100 text-yellow-800 border border-yellow-200 px-2 py-0.5 rounded-full">@p</span>
}
</div>
</div>
}
<a href="/Shop" class="block bg-gray-50 border border-gray-200 rounded-2xl p-5 hover:shadow-md transition-shadow">
<h3 class="font-bold text-gray-900 mb-1">🛒 فروشگاه قطعات</h3>
<p class="text-sm text-gray-500">قطعات یدکی @b.NameFa را مستقیم سفارش دهید.</p>
</a>
</div>
</div>
}