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
+70
View File
@@ -0,0 +1,70 @@
@page
@model AsadiTools.Pages.Admin.Products.ProductsIndexModel
@{ ViewData["Title"] = "محصولات"; Layout = "_AdminLayout"; }
<div class="p-6 md:p-8">
<div class="flex items-center justify-between mb-8">
<h1 class="text-2xl font-extrabold text-gray-900">محصولات</h1>
<a href="/Admin/Products/Create" class="flex items-center gap-2 bg-blue-700 text-white px-4 py-2.5 rounded-xl text-sm font-bold hover:bg-blue-800 transition-colors">
➕ افزودن محصول
</a>
</div>
<div class="bg-white rounded-2xl border border-gray-100 overflow-hidden">
<div class="overflow-x-auto">
<table class="w-full text-sm">
<thead class="bg-gray-50 border-b">
<tr>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">نام</th>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">دسته</th>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">برند</th>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">قیمت</th>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">موجودی</th>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">وضعیت</th>
<th class="px-5 py-3.5 text-right font-medium text-gray-500">عملیات</th>
</tr>
</thead>
<tbody class="divide-y divide-gray-50">
@foreach (var p in Model.Products)
{
var cat = SiteData.Categories.FirstOrDefault(c => c.Id == p.Category);
var brand = SiteData.Brands.FirstOrDefault(b => b.Id == p.Brand);
<tr class="hover:bg-gray-50/50">
<td class="px-5 py-4">
<div class="font-medium text-gray-900">@p.NameFa</div>
@if (p.Sku != null) { <div class="text-xs text-gray-400 font-mono">@p.Sku</div> }
</td>
<td class="px-5 py-4 text-gray-500">@(cat != null ? cat.Icon + " " + cat.NameFa : p.Category)</td>
<td class="px-5 py-4">
@if (brand != null)
{
<span class="text-xs font-bold px-2 py-0.5 rounded-full text-white" style="background-color:@brand.Color">@brand.NameFa</span>
}
else { <span class="text-gray-400"></span> }
</td>
<td class="px-5 py-4 font-bold text-blue-700">@SiteData.FormatPrice(p.Price)</td>
<td class="px-5 py-4">
<span class="font-bold @(p.Stock == 0 ? "text-red-500" : p.Stock < 5 ? "text-yellow-500" : "text-green-600")">@p.Stock</span>
</td>
<td class="px-5 py-4">
<span class="text-xs px-2 py-1 rounded-full font-medium @(p.IsActive ? "bg-green-100 text-green-700" : "bg-gray-100 text-gray-500")">
@(p.IsActive ? "فعال" : "غیرفعال")
</span>
</td>
<td class="px-5 py-4">
<div class="flex items-center gap-3">
<a href="/Admin/Products/Edit?id=@p.Id" class="text-blue-600 hover:text-blue-800 text-xs font-medium">ویرایش</a>
<form method="post" asp-page-handler="Delete" onsubmit="return confirm('حذف شود؟')">
@Html.AntiForgeryToken()
<input type="hidden" name="id" value="@p.Id" />
<button type="submit" class="text-red-400 hover:text-red-600 text-xs font-medium">حذف</button>
</form>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>