first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:30:42 +03:00
commit 4d92991817
1982 changed files with 284835 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Sepet Yönetimi</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/carts" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2"
placeholder="User ID ile Ara..." value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3 border-0 text-muted small text-uppercase">ID</th>
<th class="border-0 text-muted small text-uppercase">Kullanıcı (User ID)</th>
<th class="border-0 text-muted small text-uppercase">Ürün Sayısı (Çeşit)</th>
<th class="border-0 text-muted small text-uppercase">Oluşturulma Tarihi</th>
<th class="border-0 text-muted small text-uppercase text-end pe-3">İşlemler</th>
</tr>
</thead>
<tbody>
{{ range .Carts }}
<tr>
<td class="ps-3"><span class="text-secondary fw-medium">#{{ .ID }}</span></td>
<td>
<div class="d-flex align-items-center">
<div class="ms-2">
<div class="fw-semibold text-dark">Kullanıcı ID: {{ .UserID }}</div>
</div>
</div>
</td>
<td>
<span class="badge bg-info text-dark rounded-pill">{{ len .Items }} çeşit ürün
eklendi</span>
</td>
<td class="text-secondary small">
{{ .CreatedAt.Format "02.01.2006 15:04" }}
</td>
<td class="text-end pe-3">
<form action="/admin/carts/{{ .ID }}/delete" method="POST" class="d-inline"
onsubmit="return confirm('Bu sepeti silmek istediğinize emin misiniz?');">
<button type="submit" class="btn btn-sm btn-outline-danger" title="Sil">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
{{ else }}
<tr>
<td colspan="5" class="text-center py-5 text-muted">
<i class="bi bi-cart-x fs-1 d-block mb-2"></i>
Henüz kullanıcılar sepet oluşturmamış.
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>

View File

@@ -0,0 +1,82 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Kategoriler</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/categories" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2" placeholder="Ara..." value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
<a href="/admin/categories/new" class="btn btn-sm btn-primary">Yeni Kategori</a>
<div class="btn-group">
<a href="/admin/content/categories" class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/categories?deleted=true" class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>Başlık</th>
<th class="text-muted">Slug</th>
<th class="text-muted">Parent</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Categories }}
{{ range .Categories }}
<tr>
<td class="fw-semibold">{{ .Title }}</td>
<td class="text-secondary small text-nowrap">{{ .Slug }}</td>
<td>
{{ if .Parent }}
<span class="badge bg-secondary">{{ .Parent.Title }}</span>
{{ else }}
<span class="text-muted">-</span>
{{ end }}
</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/categories/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/categories/{{ .ID }}/edit" class="btn btn-sm btn-outline-secondary" title="Düzenle"><i class="bi bi-pencil"></i></a>
<form action="/admin/categories/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="5" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
<!-- Pagination -->
{{ if gt .TotalPages 1 }}
<div class="d-flex justify-content-end mt-3">
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{ if eq .Page 1 }}disabled{{ end }}"><a class="page-link" href="/admin/content/categories?page={{ .PrevPage }}">&laquo; Önceki</a></li>
<li class="page-item disabled"><span class="page-link">Sayfa {{ .Page }} / {{ .TotalPages }}</span></li>
<li class="page-item {{ if eq .Page .TotalPages }}disabled{{ end }}"><a class="page-link" href="/admin/content/categories?page={{ .NextPage }}">Sonraki &raquo;</a></li>
</ul>
</nav>
</div>
{{ end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,71 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Category Views</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/category-views" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2" placeholder="IP ara..." value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
<div class="btn-group">
<a href="/admin/content/category-views" class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/category-views?deleted=true" class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>Category</th>
<th class="text-muted">IP Address</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Views }}
{{ range .Views }}
<tr>
<td>{{ index $.CatMap .CategoryID }}</td>
<td class="text-secondary small">{{ .IPAddress }}</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group">
{{ if $.ShowDeleted }}
<form action="/admin/category-views/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<form action="/admin/category-views/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="4" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .TotalPages 1 }}
<div class="d-flex justify-content-end mt-3">
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{ if eq .Page 1 }}disabled{{ end }}"><a class="page-link" href="/admin/content/category-views?page={{ .PrevPage }}">&laquo; Önceki</a></li>
<li class="page-item disabled"><span class="page-link">Sayfa {{ .Page }} / {{ .TotalPages }}</span></li>
<li class="page-item {{ if eq .Page .TotalPages }}disabled{{ end }}"><a class="page-link" href="/admin/content/category-views?page={{ .NextPage }}">Sonraki &raquo;</a></li>
</ul>
</nav>
</div>
{{ end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,74 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Yorumlar</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/comments" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2" placeholder="Ara..." value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
<div class="btn-group">
<a href="/admin/content/comments" class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/comments?deleted=true" class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>Kullanıcı</th>
<th>Post ID</th>
<th class="text-muted">Yorum</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Comments }}
{{ range .Comments }}
<tr>
<td>{{ .UserID }}</td>
<td>{{ .PostID }}</td>
<td class="text-truncate" style="max-width:400px;">{{ .Body }}</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/comments/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/comments/{{ .ID }}/edit" class="btn btn-sm btn-outline-secondary" title="Düzenle"><i class="bi bi-pencil"></i></a>
<form action="/admin/comments/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="5" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .TotalPages 1 }}
<div class="d-flex justify-content-end mt-3">
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{ if eq .Page 1 }}disabled{{ end }}"><a class="page-link" href="/admin/content/comments?page={{ .PrevPage }}">&laquo; Önceki</a></li>
<li class="page-item disabled"><span class="page-link">Sayfa {{ .Page }} / {{ .TotalPages }}</span></li>
<li class="page-item {{ if eq .Page .TotalPages }}disabled{{ end }}"><a class="page-link" href="/admin/content/comments?page={{ .NextPage }}">Sonraki &raquo;</a></li>
</ul>
</nav>
</div>
{{ end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,75 @@
<div class="container-fluid">
<h2 class="mb-4">Dashboard</h2>
<!-- Stats Cards -->
<div class="row g-4 mb-4">
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body">
<h6 class="card-subtitle mb-2 text-muted">Toplam Kullanıcı</h6>
<h3 class="card-title">1,250</h3>
<p class="card-text text-success"><i class="bi bi-arrow-up"></i> %5 artış</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body">
<h6 class="card-subtitle mb-2 text-muted">Aktif Oturumlar</h6>
<h3 class="card-title">45</h3>
<p class="card-text text-primary">Anlık</p>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card h-100 border-0 shadow-sm">
<div class="card-body">
<h6 class="card-subtitle mb-2 text-muted">Sistem Yükü</h6>
<h3 class="card-title">%12</h3>
<p class="card-text text-success">Normal</p>
</div>
</div>
</div>
</div>
<!-- Recent Activity Table -->
<div class="card border-0 shadow-sm">
<div class="card-header bg-transparent border-0">
<h5 class="mb-0">Son Aktiviteler</h5>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Kullanıcı</th>
<th>İşlem</th>
<th>Tarih</th>
<th>Durum</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ahmet Yılmaz</td>
<td>Giriş Yaptı</td>
<td>10 dk önce</td>
<td><span class="badge bg-success">Başarılı</span></td>
</tr>
<tr>
<td>Ayşe Demir</td>
<td>Profil Güncelledi</td>
<td>1 saat önce</td>
<td><span class="badge bg-primary">Kaydedildi</span></td>
</tr>
<tr>
<td>Mehmet Kara</td>
<td>Hatalı Giriş</td>
<td>2 saat önce</td>
<td><span class="badge bg-danger">Hata</span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,90 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Yazılar</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/posts" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2" placeholder="Ara..." value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
<a href="/admin/posts/new" class="btn btn-sm btn-primary">Yeni Yazı</a>
<div class="btn-group">
<a href="/admin/content/posts" class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/posts?deleted=true" class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>Başlık</th>
<th>Kategoriler</th>
<th>Taglar</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Posts }}
{{ range .Posts }}
<tr>
<td style="width:56px;">
{{ with index $.ImageMap .ID }}
<img src="{{ . }}" alt="thumb" class="rounded" style="width:48px;height:48px;object-fit:cover;">
{{ else }}
<div class="bg-secondary rounded" style="width:48px;height:48px;"></div>
{{ end }}
</td>
<td>{{ .Title }}</td>
<td>
{{ range .Categories }}
<span class="badge bg-secondary me-1">{{ .Title }}</span>
{{ end }}
</td>
<td>
{{ range .Tags }}
<span class="badge bg-info text-dark me-1">{{ .Name }}</span>
{{ end }}
</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/posts/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/posts/{{ .ID }}/edit" class="btn btn-sm btn-outline-secondary" title="Düzenle"><i class="bi bi-pencil"></i></a>
<form action="/admin/posts/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="5" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .TotalPages 1 }}
<div class="d-flex justify-content-end mt-3">
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{ if eq .Page 1 }}disabled{{ end }}"><a class="page-link" href="/admin/content/posts?page={{ .PrevPage }}">&laquo; Önceki</a></li>
<li class="page-item disabled"><span class="page-link">Sayfa {{ .Page }} / {{ .TotalPages }}</span></li>
<li class="page-item {{ if eq .Page .TotalPages }}disabled{{ end }}"><a class="page-link" href="/admin/content/posts?page={{ .NextPage }}">Sonraki &raquo;</a></li>
</ul>
</nav>
</div>
{{ end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,73 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Ürün Kategorileri</h2>
<div class="d-flex gap-2 align-items-center">
<a href="/admin/product-categories/new" class="btn btn-sm btn-primary">Yeni Kategori</a>
<div class="btn-group">
<a href="/admin/content/product-categories"
class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/product-categories?deleted=true"
class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>Başlık</th>
<th class="text-muted">Slug</th>
<th class="text-muted">Üst Kategori</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Categories }}
{{ range .Categories }}
<tr>
<td class="fw-semibold">{{ .Title }}</td>
<td class="text-secondary small text-nowrap">{{ .Slug }}</td>
<td>
{{ if .Parent }}
<span class="badge bg-secondary">{{ .Parent.Title }}</span>
{{ else }}
<span class="text-muted">-</span>
{{ end }}
</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/product-categories/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i
class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/product-categories/{{ .ID }}/edit"
class="btn btn-sm btn-outline-secondary" title="Düzenle"><i
class="bi bi-pencil"></i></a>
<form action="/admin/product-categories/{{ .ID }}/delete" method="POST"
onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i
class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="5" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,46 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Kategori Görüntülenmeleri</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/product-category-views" method="GET">
<input type="search" name="category_id" class="form-control form-control-sm me-2"
placeholder="Category ID..." value="{{ .CategoryID }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3 border-0 text-muted small text-uppercase">ID</th>
<th class="border-0 text-muted small text-uppercase">Kategori ID</th>
<th class="border-0 text-muted small text-uppercase">IP Adresi</th>
<th class="border-0 text-muted small text-uppercase">Ziyaret Tarihi</th>
</tr>
</thead>
<tbody>
{{ range .Views }}
<tr>
<td class="ps-3"><span class="text-secondary fw-medium">#{{ .ID }}</span></td>
<td><span class="badge bg-primary">Kategori #{{ .CategoryID }}</span></td>
<td><span class="text-dark font-monospace">{{ .IPAddress }}</span></td>
<td class="text-secondary small">
{{ .CreatedAt.Format "02.01.2006 15:04" }}
</td>
</tr>
{{ else }}
<tr>
<td colspan="4" class="text-center py-5 text-muted">
<i class="bi bi-eye fs-1 d-block mb-2"></i>
Kategorileriniz henüz görüntülenmemiş veya veri yok.
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>

View File

@@ -0,0 +1,65 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Ürün Yorumları</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/product-comments" method="GET">
<input type="search" name="product_id" class="form-control form-control-sm me-2"
placeholder="Ürün ID ile Ara..." value="{{ .ProductID }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="table-responsive">
<table class="table table-hover align-middle mb-0">
<thead class="bg-light">
<tr>
<th class="ps-3 border-0 text-muted small text-uppercase">ID</th>
<th class="border-0 text-muted small text-uppercase">Kullanıcı (User ID)</th>
<th class="border-0 text-muted small text-uppercase">Yorum (Body)</th>
<th class="border-0 text-muted small text-uppercase">Ürün ID</th>
<th class="border-0 text-muted small text-uppercase">Tarih</th>
<th class="border-0 text-muted small text-uppercase text-end pe-3">İşlemler</th>
</tr>
</thead>
<tbody>
{{ range .ProductComments }}
<tr>
<td class="ps-3"><span class="text-secondary fw-medium">#{{ .ID }}</span></td>
<td>
<div class="d-flex align-items-center">
<span class="badge bg-secondary">User #{{ .UserID }}</span>
</div>
</td>
<td>
<div class="text-dark">{{ .Body }}</div>
</td>
<td>
<span class="badge bg-primary">Product #{{ .ProductID }}</span>
</td>
<td class="text-secondary small">
{{ .CreatedAt.Format "02.01.2006 15:04" }}
</td>
<td class="text-end pe-3">
<form action="/admin/product-comments/{{ .ID }}/delete" method="POST" class="d-inline"
onsubmit="return confirm('Bu yorumu silmek istediğinize emin misiniz?');">
<button type="submit" class="btn btn-sm btn-outline-danger" title="Sil">
<i class="bi bi-trash"></i>
</button>
</form>
</td>
</tr>
{{ else }}
<tr>
<td colspan="6" class="text-center py-5 text-muted">
<i class="bi bi-chat-dots fs-1 d-block mb-2"></i>
Henüz ürünlere yorum yapılmamış.
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>

View File

@@ -0,0 +1,63 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Ürün Etiketleri</h2>
<div class="d-flex gap-2 align-items-center">
<a href="/admin/product-tags/new" class="btn btn-sm btn-primary">Yeni Etiket</a>
<div class="btn-group">
<a href="/admin/content/product-tags"
class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/product-tags?deleted=true"
class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>İsim</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Tags }}
{{ range .Tags }}
<tr>
<td class="fw-semibold">{{ .Name }}</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/product-tags/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i
class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/product-tags/{{ .ID }}/edit"
class="btn btn-sm btn-outline-secondary" title="Düzenle"><i
class="bi bi-pencil"></i></a>
<form action="/admin/product-tags/{{ .ID }}/delete" method="POST"
onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i
class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="3" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,102 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Ürünler</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/products" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2" placeholder="Ara..."
value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
<a href="/admin/products/new" class="btn btn-sm btn-primary">Yeni Ürün</a>
<div class="btn-group">
<a href="/admin/content/products"
class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/products?deleted=true"
class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>Ürün</th>
<th>Başlık</th>
<th>Kategoriler</th>
<th>Etiketler</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Products }}
{{ range .Products }}
<tr>
<td style="width:56px;">
{{ with index $.ImageMap .ID }}
<img src="{{ . }}" alt="thumb" class="rounded"
style="width:48px;height:48px;object-fit:cover;">
{{ else }}
<div class="bg-secondary rounded" style="width:48px;height:48px;"></div>
{{ end }}
</td>
<td>{{ .Title }}</td>
<td>
{{ range .Categories }}
<span class="badge bg-secondary me-1">{{ .Title }}</span>
{{ end }}
</td>
<td>
{{ range .Tags }}
<span class="badge bg-info text-dark me-1">{{ .Name }}</span>
{{ end }}
</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/products/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i
class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/products/{{ .ID }}/edit" class="btn btn-sm btn-outline-secondary"
title="Düzenle"><i class="bi bi-pencil"></i></a>
<form action="/admin/products/{{ .ID }}/delete" method="POST"
onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i
class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="6" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .TotalPages 1 }}
<div class="d-flex justify-content-end mt-3">
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{ if eq .Page 1 }}disabled{{ end }}"><a class="page-link"
href="/admin/content/products?page={{ .PrevPage }}">&laquo; Önceki</a></li>
<li class="page-item disabled"><span class="page-link">Sayfa {{ .Page }} / {{ .TotalPages
}}</span></li>
<li class="page-item {{ if eq .Page .TotalPages }}disabled{{ end }}"><a class="page-link"
href="/admin/content/products?page={{ .NextPage }}">Sonraki &raquo;</a></li>
</ul>
</nav>
</div>
{{ end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,538 @@
<div class="container-fluid" hx-trigger="heroListChanged from:body" hx-get="/admin/content/settings" hx-target="this"
hx-swap="outerHTML">
<h2 class="mb-4">Ayarlar & Banner Yönetimi</h2>
<ul class="nav nav-tabs mb-4" id="settingsTab" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="general-tab" data-bs-toggle="tab" data-bs-target="#general"
type="button" role="tab">Genel Ayarlar</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="security-tab" data-bs-toggle="tab" data-bs-target="#security" type="button" role="tab">Güvenlik</button>
</li>
<li class="nav-item" role="presentation">
<button class="nav-link" id="hero-tab" data-bs-toggle="tab" data-bs-target="#hero" type="button"
role="tab">Banner (Hero) Yönetimi</button>
</li>
</ul>
<div class="tab-content" id="settingsTabContent">
<!-- General Settings Tab -->
<div class="tab-pane fade show active" id="general" role="tabpanel">
<div class="card border-0 shadow-sm">
<div class="card-body">
<form action="/admin/settings" method="POST" enctype="multipart/form-data">
<div class="row">
<div class="col-md-6 mb-3">
<label for="title" class="form-label">Site Başlığı</label>
<input type="text" class="form-control" id="title" name="title"
value="{{ .Setting.Title }}">
</div>
<div class="col-md-6 mb-3">
<label for="meta_title" class="form-label">Meta Başlık</label>
<input type="text" class="form-control" id="meta_title" name="meta_title"
value="{{ .Setting.MetaTitle }}">
</div>
</div>
<div class="mb-3">
<label for="meta_description" class="form-label">Meta Açıklama</label>
<textarea class="form-control" id="meta_description" name="meta_description"
rows="2">{{ .Setting.MetaDescription }}</textarea>
</div>
<div class="row">
<div class="col-md-6 mb-3">
<label for="email" class="form-label">E-posta</label>
<input type="email" class="form-control" id="email" name="email"
value="{{ .Setting.Email }}">
</div>
<div class="col-md-6 mb-3">
<label for="phone" class="form-label">Telefon</label>
<input type="text" class="form-control" id="phone" name="phone"
value="{{ .Setting.Phone }}">
</div>
</div>
<div class="mb-3">
<label for="address" class="form-label">Adres</label>
<textarea class="form-control" id="address" name="address"
rows="2">{{ .Setting.Address }}</textarea>
</div>
<div class="mb-3">
<label for="url" class="form-label">Site URL</label>
<input type="text" class="form-control" id="url" name="url" value="{{ .Setting.URL }}">
</div>
<h5 class="mt-4">Logo Ayarları</h5>
<div class="row">
<!-- White Logo (WLogo) -->
<div class="col-md-6">
<div class="card border p-3 mb-3">
<h6 class="mb-3">Beyaz Logo (Genellikle Koyu Zemin İçin)</h6>
<div class="mb-3">
<label class="form-label">Logo Yükle</label>
<input type="file" class="form-control" name="w_logo" accept="image/*">
{{ if .Setting.WLogo }}
<div class="mt-2 text-center p-2 logo-preview logo-preview-light border rounded">
<img src="{{ .Setting.WLogo }}" alt="WLogo" style="max-height: 50px;">
</div>
{{ end }}
</div>
<div class="row g-2">
<div class="col-6">
<label class="form-label small text-muted mb-0">Genişlik</label>
<input type="number" class="form-control form-control-sm" name="w_width"
placeholder="Otomatik" value="{{ .Setting.WWidth }}">
</div>
<div class="col-6">
<label class="form-label small text-muted mb-0">Yükseklik</label>
<input type="number" class="form-control form-control-sm" name="w_height"
placeholder="Otomatik" value="{{ .Setting.WHeight }}">
</div>
<div class="col-6">
<label class="form-label small text-muted mb-0">Kalite (1-100)</label>
<input type="number" class="form-control form-control-sm" name="w_quality"
placeholder="80" value="{{ .Setting.WQuality }}">
</div>
<div class="col-6">
<label class="form-label small text-muted mb-0">Format</label>
<select class="form-select form-select-sm" name="w_format">
<option value="avif" {{ if eq .Setting.WFormat "avif" }}selected{{ end
}}>AVIF (Önerilen)</option>
<option value="webp" {{ if eq .Setting.WFormat "webp" }}selected{{ end
}}>WebP</option>
<option value="png" {{ if eq .Setting.WFormat "png" }}selected{{ end }}>
PNG</option>
<option value="jpg" {{ if eq .Setting.WFormat "jpg" }}selected{{ end }}>
JPG</option>
</select>
</div>
</div>
</div>
</div>
<!-- Black Logo (BLogo) -->
<div class="col-md-6">
<div class="card border p-3 mb-3">
<h6 class="mb-3">Siyah Logo (Genellikle Beyaz Zemin İçin)</h6>
<div class="mb-3">
<label class="form-label">Logo Yükle</label>
<input type="file" class="form-control" name="b_logo" accept="image/*">
{{ if .Setting.BLogo }}
<div class="mt-2 text-center p-2 logo-preview logo-preview-light border rounded">
<img src="{{ .Setting.BLogo }}" alt="BLogo" style="max-height: 50px;">
</div>
{{ end }}
</div>
<div class="row g-2">
<div class="col-6">
<label class="form-label small text-muted mb-0">Genişlik</label>
<input type="number" class="form-control form-control-sm" name="b_width"
placeholder="Otomatik" value="{{ .Setting.BWidth }}">
</div>
<div class="col-6">
<label class="form-label small text-muted mb-0">Yükseklik</label>
<input type="number" class="form-control form-control-sm" name="b_height"
placeholder="Otomatik" value="{{ .Setting.BHeight }}">
</div>
<div class="col-6">
<label class="form-label small text-muted mb-0">Kalite (1-100)</label>
<input type="number" class="form-control form-control-sm" name="b_quality"
placeholder="80" value="{{ .Setting.BQuality }}">
</div>
<div class="col-6">
<label class="form-label small text-muted mb-0">Format</label>
<select class="form-select form-select-sm" name="b_format">
<option value="avif" {{ if eq .Setting.BFormat "avif" }}selected{{ end
}}>AVIF (Önerilen)</option>
<option value="webp" {{ if eq .Setting.BFormat "webp" }}selected{{ end
}}>WebP</option>
<option value="png" {{ if eq .Setting.BFormat "png" }}selected{{ end }}>
PNG</option>
<option value="jpg" {{ if eq .Setting.BFormat "jpg" }}selected{{ end }}>
JPG</option>
</select>
</div>
</div>
</div>
</div>
</div>
<!-- CORS and Rate Limit moved to Güvenlik tab -->
<h5 class="mt-4">Sosyal Medya</h5>
<div class="row">
<div class="col-md-4 mb-3">
<label class="form-label">Instagram</label>
<input type="text" class="form-control" name="instagram"
value="{{ .Setting.Instagram }}">
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Twitter (X)</label>
<input type="text" class="form-control" name="x" value="{{ .Setting.X }}">
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Facebook</label>
<input type="text" class="form-control" name="facebook" value="{{ .Setting.Facebook }}">
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Whatsapp</label>
<input type="text" class="form-control" name="whatsapp" value="{{ .Setting.Whatsapp }}">
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Linkedin</label>
<input type="text" class="form-control" name="linkedin" value="{{ .Setting.Linkedin }}">
</div>
<div class="col-md-4 mb-3">
<label class="form-label">Pinterest</label>
<input type="text" class="form-control" name="pinterest"
value="{{ .Setting.Pinterest }}">
</div>
</div>
<div class="mb-3 form-check form-switch">
<input class="form-check-input" type="checkbox" id="is_active" name="is_active" {{ if
.Setting.IsActive }}checked{{ end }}>
<label class="form-check-label" for="is_active">Site Aktif</label>
</div>
<button type="submit" class="btn btn-primary">Kaydet</button>
</form>
</div>
</div>
</div>
<!-- Security Tab (CORS / Rate Limits) -->
<div class="tab-pane fade" id="security" role="tabpanel">
<div class="card border-0 shadow-sm">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-3">
<h5 class="mb-0">CORS Yönetimi</h5>
<div class="btn-group">
<a href="/admin/content/settings" class="btn btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/settings?deleted=true" class="btn btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
<div class="row mb-3">
<div class="col-md-6">
<div class="card border p-3 mb-3">
<h6 class="mb-3">Whitelist (İzinli Origin'ler)</h6>
{{ if .EditWhitelist.ID }}
<form action="/admin/settings/cors/whitelist/{{ .EditWhitelist.ID }}/update" method="POST" class="mb-3">
<div class="input-group mb-2">
<input type="text" name="origin" class="form-control" placeholder="https://example.com" required value="{{ .EditWhitelist.Origin }}">
</div>
<div class="mb-2">
<input type="text" name="description" class="form-control" placeholder="Açıklama (opsiyonel)" value="{{ .EditWhitelist.Description }}">
</div>
<div class="form-check form-switch mb-2">
<input class="form-check-input" type="checkbox" id="wl_active" name="is_active" {{ if .EditWhitelist.IsActive }}checked{{ end }}>
<label class="form-check-label" for="wl_active">Aktif</label>
</div>
<div class="d-flex gap-2 justify-content-end">
<a href="/admin/content/settings" class="btn btn-sm btn-secondary">İptal</a>
<button class="btn btn-sm btn-primary" type="submit">Güncelle</button>
</div>
</form>
{{ else }}
<form action="/admin/settings/cors/whitelist/create" method="POST" class="mb-3">
<div class="input-group mb-2">
<input type="text" name="origin" class="form-control" placeholder="https://example.com" required>
</div>
<div class="mb-2">
<input type="text" name="description" class="form-control" placeholder="Açıklama (opsiyonel)">
</div>
<div class="d-flex gap-2 justify-content-end">
<button class="btn btn-sm btn-primary" type="submit">Ekle</button>
</div>
</form>
{{ end }}
<div>
<ul class="list-group list-group-flush">
{{ if .CorsWhitelist }}
{{ range .CorsWhitelist }}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>{{ .Origin }}</strong>
<div class="small text-muted">{{ .Description }}</div>
</div>
<div class="btn-group">
{{ if $.ShowDeleted }}
<form action="/admin/settings/cors/whitelist/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success">Geri Yükle</button>
</form>
{{ else }}
<a href="/admin/content/settings?edit_whitelist={{ .ID }}" class="btn btn-sm btn-outline-secondary">Düzenle</a>
<form action="/admin/settings/cors/whitelist/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger">Sil</button>
</form>
{{ end }}
</div>
</li>
{{ end }}
{{ else }}
<li class="list-group-item">Kayıt yok</li>
{{ end }}
</ul>
</div>
</div>
</div>
<div class="col-md-6">
<div class="card border p-3 mb-3">
<h6 class="mb-3">Blacklist (Yasaklı Origin'ler)</h6>
{{ if .EditBlacklist.ID }}
<form action="/admin/settings/cors/blacklist/{{ .EditBlacklist.ID }}/update" method="POST" class="mb-3">
<div class="input-group mb-2">
<input type="text" name="origin" class="form-control" placeholder="https://bad.com" required value="{{ .EditBlacklist.Origin }}">
</div>
<div class="mb-2">
<input type="text" name="reason" class="form-control" placeholder="Sebep (opsiyonel)" value="{{ .EditBlacklist.Reason }}">
</div>
<div class="form-check form-switch mb-2">
<input class="form-check-input" type="checkbox" id="bl_active" name="is_active" {{ if .EditBlacklist.IsActive }}checked{{ end }}>
<label class="form-check-label" for="bl_active">Aktif</label>
</div>
<div class="d-flex gap-2 justify-content-end">
<a href="/admin/content/settings" class="btn btn-sm btn-secondary">İptal</a>
<button class="btn btn-sm btn-primary" type="submit">Güncelle</button>
</div>
</form>
{{ else }}
<form action="/admin/settings/cors/blacklist/create" method="POST" class="mb-3">
<div class="input-group mb-2">
<input type="text" name="origin" class="form-control" placeholder="https://bad.com" required>
</div>
<div class="mb-2">
<input type="text" name="reason" class="form-control" placeholder="Sebep (opsiyonel)">
</div>
<div class="d-flex gap-2 justify-content-end">
<button class="btn btn-sm btn-primary" type="submit">Ekle</button>
</div>
</form>
{{ end }}
<div>
<ul class="list-group list-group-flush">
{{ if .CorsBlacklist }}
{{ range .CorsBlacklist }}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>{{ .Origin }}</strong>
<div class="small text-muted">{{ .Reason }}</div>
</div>
<div class="btn-group">
{{ if $.ShowDeleted }}
<form action="/admin/settings/cors/blacklist/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success">Geri Yükle</button>
</form>
{{ else }}
<a href="/admin/content/settings?edit_blacklist={{ .ID }}" class="btn btn-sm btn-outline-secondary">Düzenle</a>
<form action="/admin/settings/cors/blacklist/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger">Sil</button>
</form>
{{ end }}
</div>
</li>
{{ end }}
{{ else }}
<li class="list-group-item">Kayıt yok</li>
{{ end }}
</ul>
</div>
</div>
</div>
</div>
<h5 class="mb-3">Rate Limit Ayarları</h5>
<div class="card border p-3 mb-3">
{{ if .EditRateLimit.ID }}
<form action="/admin/settings/rate-limit/{{ .EditRateLimit.ID }}/update" method="POST" class="row g-2 mb-3">
<div class="col-md-3">
<input type="text" name="name" class="form-control" placeholder="İsim (ör. login)" required value="{{ .EditRateLimit.Name }}">
</div>
<div class="col-md-3">
<input type="number" name="max_requests" class="form-control" placeholder="Max istek" required value="{{ .EditRateLimit.MaxRequests }}">
</div>
<div class="col-md-3">
<input type="number" name="window_seconds" class="form-control" placeholder="Pencere (s)" required value="{{ .EditRateLimit.WindowSeconds }}">
</div>
<div class="col-md-3 d-flex gap-2">
<a href="/admin/content/settings" class="btn btn-secondary">İptal</a>
<button class="btn btn-primary" type="submit">Güncelle</button>
</div>
</form>
{{ else }}
<form action="/admin/settings/rate-limit/create" method="POST" class="row g-2 mb-3">
<div class="col-md-3">
<input type="text" name="name" class="form-control" placeholder="İsim (ör. login)" required>
</div>
<div class="col-md-3">
<input type="number" name="max_requests" class="form-control" placeholder="Max istek" required>
</div>
<div class="col-md-3">
<input type="number" name="window_seconds" class="form-control" placeholder="Pencere (s)" required>
</div>
<div class="col-md-3 d-flex gap-2">
<button class="btn btn-primary" type="submit">Ekle</button>
</div>
</form>
{{ end }}
<div>
<ul class="list-group list-group-flush">
{{ if .RateLimits }}
{{ range .RateLimits }}
<li class="list-group-item d-flex justify-content-between align-items-center">
<div>
<strong>{{ .Name }}</strong>
<div class="small text-muted">{{ .MaxRequests }} req / {{ .WindowSeconds }}s</div>
</div>
<div class="btn-group">
{{ if $.ShowDeleted }}
<form action="/admin/settings/rate-limit/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success">Geri Yükle</button>
</form>
{{ else }}
<a href="/admin/content/settings?edit_ratelimit={{ .ID }}" class="btn btn-sm btn-outline-secondary">Düzenle</a>
<form action="/admin/settings/rate-limit/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger">Sil</button>
</form>
{{ end }}
</div>
</li>
{{ end }}
{{ else }}
<li class="list-group-item">Kayıt yok</li>
{{ end }}
</ul>
</div>
</div>
</div>
</div>
</div>
<!-- Hero Management Tab -->
<div class="tab-pane fade" id="hero" role="tabpanel">
<div class="d-flex justify-content-between align-items-center mb-3">
<div class="btn-group" role="group">
<a href="/admin/content/settings"
class="btn btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/settings?deleted=true"
class="btn btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
<a href="/admin/heroes/new" class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Yeni Banner Ekle
</a>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>Görsel/Renk</th>
<th>Başlık</th>
<th>Alt Başlık</th>
<th>Durum</th>
<th>İşlemler</th>
</tr>
</thead>
<tbody>
{{ range .Heroes }}
<tr>
<td>
<div style="width: 50px; height: 30px; background-color: {{ .Color }}; border-radius: 4px; border: 1px solid #ddd;"
title="{{ .Color }}"></div>
</td>
<td>{{ .Title }}</td>
<td>{{ .Text1 }}</td>
<td>
{{ if .IsActive }}
<span class="badge bg-success">Aktif</span>
{{ else }}
<span class="badge bg-secondary">Pasif</span>
{{ end }}
</td>
<td>
<div class="d-flex gap-2">
{{ if $.ShowDeleted }}
<form action="/admin/heroes/{{ .ID }}/restore" method="POST"
onsubmit="return confirmRestore(event, this);">
<button type="submit" class="btn btn-sm btn-success" title="Geri Yükle">
<i class="bi bi-arrow-counterclockwise"></i>
</button>
</form>
{{ else }}
<a href="/admin/heroes/{{ .ID }}/edit"
class="btn btn-sm btn-outline-secondary" title="Düzenle">
<i class="bi bi-pencil"></i>
</a>
<form action="/admin/heroes/{{ .ID }}/delete" method="POST"
onsubmit="return confirmDelete(event, this);">
<button type="submit" class="btn btn-sm btn-outline-danger" title="Sil">
<i class="bi bi-trash"></i>
</button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Simple tab state preservation using URL hash or local storage is complex with HTMX
// For now, let's just make sure tabs work via Bootstrap JS
// The tabs might reset to first tab on HTMX swap/update if we are not careful.
// Since we reload the whole #settings-container (this file) on update, tabs will reset.
// We can add a small script to check URL param or sessionStorage to activate correct tab.
(function(){
const STORAGE_KEY = 'admin.settings.activeTab';
// Save active tab id when clicked
document.querySelectorAll('#settingsTab button[data-bs-toggle="tab"]').forEach(btn => {
btn.addEventListener('shown.bs.tab', (e) => {
try { sessionStorage.setItem(STORAGE_KEY, e.target.id); } catch(e){}
});
});
// Restore on load
function restoreTab(){
try{
const id = sessionStorage.getItem(STORAGE_KEY);
if(id){
const btn = document.getElementById(id);
if(btn){
const tab = new bootstrap.Tab(btn);
tab.show();
}
}
}catch(e){}
}
document.addEventListener('DOMContentLoaded', restoreTab);
// HTMX: after swapping settings container, restore the tab
document.addEventListener('htmx:afterSwap', function(evt){
if(evt.detail.target && evt.detail.target.id === undefined){ return; }
const tgt = evt.detail.target;
if(tgt && (tgt.id === 'users-container' || tgt.id === 'main-content' || tgt.id === 'modal-area')){
// not our container
return;
}
// if settings container was swapped, restore
if(tgt && tgt.closest && tgt.closest('.container-fluid') && tgt.closest('.container-fluid').querySelector('#settingsTab')){
restoreTab();
}
});
})();
</script>

View File

@@ -0,0 +1,71 @@
<div class="container-fluid">
<div class="d-flex justify-content-between align-items-center mb-3">
<h2 class="mb-0">Taglar</h2>
<div class="d-flex gap-2 align-items-center">
<form class="d-flex" action="/admin/content/tags" method="GET">
<input type="search" name="search" class="form-control form-control-sm me-2" placeholder="Ara..." value="{{ .Search }}">
<button class="btn btn-sm btn-outline-secondary" type="submit"><i class="bi bi-search"></i></button>
</form>
<a href="/admin/tags/new" class="btn btn-sm btn-primary">Yeni Tag</a>
<div class="btn-group">
<a href="/admin/content/tags" class="btn btn-sm btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/tags?deleted=true" class="btn btn-sm btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
</div>
</div>
<div class="card border-0 shadow-sm">
<div class="card-body p-3">
<div class="table-responsive">
<table class="table table-hover table-sm align-middle">
<thead class="bg-transparent text-muted small">
<tr>
<th>İsim</th>
<th class="text-muted">Oluşturma</th>
<th class="text-end text-muted">İşlemler</th>
</tr>
</thead>
<tbody>
{{ if .Tags }}
{{ range .Tags }}
<tr>
<td class="fw-semibold">{{ .Name }}</td>
<td class="text-muted small">{{ .CreatedAt.Format "2006-01-02" }}</td>
<td class="text-end">
<div class="btn-group" role="group">
{{ if $.ShowDeleted }}
<form action="/admin/tags/{{ .ID }}/restore" method="POST">
<button class="btn btn-sm btn-success" title="Geri Yükle"><i class="bi bi-arrow-counterclockwise"></i></button>
</form>
{{ else }}
<a href="/admin/tags/{{ .ID }}/edit" class="btn btn-sm btn-outline-secondary" title="Düzenle"><i class="bi bi-pencil"></i></a>
<form action="/admin/tags/{{ .ID }}/delete" method="POST" onsubmit="return confirmDelete(event, this);">
<button class="btn btn-sm btn-outline-danger" title="Sil"><i class="bi bi-trash"></i></button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
{{ else }}
<tr>
<td colspan="3" class="text-center text-muted py-4">Kayıt yok</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
{{ if gt .TotalPages 1 }}
<div class="d-flex justify-content-end mt-3">
<nav>
<ul class="pagination pagination-sm mb-0">
<li class="page-item {{ if eq .Page 1 }}disabled{{ end }}"><a class="page-link" href="/admin/content/tags?page={{ .PrevPage }}">&laquo; Önceki</a></li>
<li class="page-item disabled"><span class="page-link">Sayfa {{ .Page }} / {{ .TotalPages }}</span></li>
<li class="page-item {{ if eq .Page .TotalPages }}disabled{{ end }}"><a class="page-link" href="/admin/content/tags?page={{ .NextPage }}">Sonraki &raquo;</a></li>
</ul>
</nav>
</div>
{{ end }}
</div>
</div>
</div>

View File

@@ -0,0 +1,118 @@
<div class="container-fluid" hx-trigger="userListChanged from:body"
hx-get="/admin/content/users?page={{ .Page }}&search={{ .Search }}" hx-target="this" hx-swap="outerHTML">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>Kullanıcılar</h2>
<div>
<input type="text" class="form-control d-inline-block w-auto me-2" placeholder="Ara..." name="search"
value="{{ .Search }}" hx-get="/admin/content/users" hx-trigger="keyup changed delay:500ms"
hx-target="#users-container" hx-push-url="true">
<div class="btn-group me-2" role="group">
<a href="/admin/content/users"
class="btn btn-outline-primary {{ if not .ShowDeleted }}active{{ end }}">Aktif</a>
<a href="/admin/content/users?deleted=true"
class="btn btn-outline-danger {{ if .ShowDeleted }}active{{ end }}">Silinenler</a>
</div>
<a href="/admin/users/new" class="btn btn-primary">
<i class="bi bi-plus-lg"></i> Yeni Kullanıcı
</a>
</div>
</div>
<div class="card border-0 shadow-sm" id="users-container">
<div class="card-body">
<div class="table-responsive">
<table class="table table-hover align-middle">
<thead>
<tr>
<th>ID</th>
<th>Ad Soyad</th>
<th>Email</th>
<th>Rol</th>
<th>Durum</th>
<th>İşlemler</th>
</tr>
</thead>
<tbody>
{{ range .Users }}
<tr>
<td>{{ .ID }}</td>
<td>
<div class="d-flex align-items-center">
{{ if .Profile }}
{{ range .Profile }}
{{ if .AvatarURL }}
<img src="{{ .AvatarURL }}" class="rounded-circle me-2" width="32" height="32"
alt="">
{{ end }}
{{ end }}
{{ end }}
{{ .UserName }}
</div>
</td>
<td>{{ .Email }}</td>
<td>
{{ if isTrue .IsAdmin }}
<span class="badge bg-danger">Admin</span>
{{ else }}
<span class="badge bg-info">User</span>
{{ end }}
</td>
<td>
{{ if isTrue .EmailVerified }}
<span class="text-success"><i class="bi bi-check-circle-fill"></i> Onaylı</span>
{{ else }}
<span class="text-warning"><i class="bi bi-exclamation-circle-fill"></i> Bekliyor</span>
{{ end }}
</td>
<td>
<div class="d-flex gap-2">
{{ if $.ShowDeleted }}
<form action="/admin/users/{{ .ID }}/restore" method="POST"
onsubmit="return confirmRestore(event, this);">
<button type="submit" class="btn btn-sm btn-success" title="Geri Yükle">
<i class="bi bi-arrow-counterclockwise"></i> Geri Yükle
</button>
</form>
{{ else }}
<a href="/admin/users/{{ .ID }}/edit" class="btn btn-sm btn-outline-secondary"
title="Düzenle">
<i class="bi bi-pencil"></i>
</a>
<form action="/admin/users/{{ .ID }}/delete" method="POST"
onsubmit="return confirmDelete(event, this);">
<button type="submit" class="btn btn-sm btn-outline-danger" title="Sil">
<i class="bi bi-trash"></i>
</button>
</form>
{{ end }}
</div>
</td>
</tr>
{{ end }}
</tbody>
</table>
</div>
<!-- Pagination -->
{{ if gt .TotalPages 1 }}
<nav class="mt-3">
<ul class="pagination justify-content-center">
<li class="page-item {{ if le .Page 1 }}disabled{{ end }}">
<a class="page-link" href="#"
hx-get="/admin/content/users?page={{ .PrevPage }}&search={{ .Search }}"
hx-target="#users-container">Önceki</a>
</li>
<li class="page-item disabled"><span class="page-link">{{ .Page }} / {{ .TotalPages }}</span></li>
<li class="page-item {{ if ge .Page .TotalPages }}disabled{{ end }}">
<a class="page-link" href="#"
hx-get="/admin/content/users?page={{ .NextPage }}&search={{ .Search }}"
hx-target="#users-container">Sonraki</a>
</li>
</ul>
</nav>
{{ end }}
</div>
</div>
</div>