151 lines
8.7 KiB
Plaintext
151 lines
8.7 KiB
Plaintext
package blog
|
|
|
|
import (
|
|
"gobeyhan/database/models"
|
|
"fmt"
|
|
)
|
|
|
|
templ CategoryList(items []models.Category) {
|
|
@Layout("Blog Categories") {
|
|
<div class="flex justify-between items-center mb-6">
|
|
<h1 class="text-2xl font-semibold text-gray-900">Categories</h1>
|
|
<a href="/admin/blog/categories/new" class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700">Add Category</a>
|
|
</div>
|
|
|
|
<div class="bg-white shadow overflow-hidden sm:rounded-lg">
|
|
<table class="min-w-full divide-y divide-gray-200">
|
|
<thead class="bg-gray-50">
|
|
<tr>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">ID</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Title</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Slug</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Order</th>
|
|
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Active</th>
|
|
<th class="px-6 py-3 text-right text-xs font-medium text-gray-500 uppercase tracking-wider">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="bg-white divide-y divide-gray-200">
|
|
for _, cat := range items {
|
|
<tr>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{ fmt.Sprintf("%d", cat.ID) }</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{ cat.Title }</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{ cat.Slug }</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{ fmt.Sprintf("%d", cat.Order) }</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
if cat.IsActive {
|
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-green-100 text-green-800">Active</span>
|
|
} else {
|
|
<span class="px-2 inline-flex text-xs leading-5 font-semibold rounded-full bg-red-100 text-red-800">Inactive</span>
|
|
}
|
|
</td>
|
|
<td class="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
|
<a href={ templ.SafeURL(fmt.Sprintf("/admin/blog/categories/%d/edit", cat.ID)) } class="text-indigo-600 hover:text-indigo-900 mr-4">Edit</a>
|
|
<form id={ fmt.Sprintf("delete-cat-%d", cat.ID) } action={ templ.SafeURL(fmt.Sprintf("/admin/blog/categories/%d/delete", cat.ID)) } method="POST" class="inline">
|
|
<button type="button" class="text-red-600 hover:text-red-900" onclick={ templ.ComponentScript{ Call: fmt.Sprintf("confirmDelete('Delete Category', 'Delete this category and all associations?', 'delete-cat-%d')", cat.ID) } }>Delete</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
templ CategoryForm(cat *models.Category, categories []models.Category, errors map[string]string) {
|
|
@Layout(ifElse(cat.ID == 0, "Create Category", "Edit Category")) {
|
|
<div class="max-w-2xl mx-auto py-6">
|
|
<h1 class="text-2xl font-semibold text-gray-900 mb-6">
|
|
if cat.ID == 0 {
|
|
Create New Category
|
|
} else {
|
|
Edit Category: { cat.Title }
|
|
}
|
|
</h1>
|
|
<form action={ templ.SafeURL(ifElse(cat.ID == 0, "/admin/blog/categories", fmt.Sprintf("/admin/blog/categories/%d", cat.ID))) } method="POST" class="space-y-6 bg-white p-6 rounded-lg shadow">
|
|
<div>
|
|
<label for="title" class="block text-sm font-medium text-gray-700">Title*</label>
|
|
<input type="text" name="title" id="title" value={ cat.Title } required
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm p-2 border" />
|
|
if errors["title"] != "" {
|
|
<p class="mt-2 text-sm text-red-600">{ errors["title"] }</p>
|
|
}
|
|
</div>
|
|
|
|
<div>
|
|
<label for="slug" class="block text-sm font-medium text-gray-700">Slug (leave empty to auto-generate)</label>
|
|
<input type="text" name="slug" id="slug" value={ cat.Slug }
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm p-2 border" />
|
|
</div>
|
|
|
|
<div>
|
|
<label for="parent_id" class="block text-sm font-medium text-gray-700">Parent Category</label>
|
|
<select name="parent_id" id="parent_id" class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm p-2 border">
|
|
<option value="">None</option>
|
|
for _, c := range categories {
|
|
if c.ID != cat.ID {
|
|
<option value={ fmt.Sprintf("%d", c.ID) }
|
|
if cat.ParentID != nil && *cat.ParentID == c.ID {
|
|
selected
|
|
}
|
|
>{ c.Title }</option>
|
|
}
|
|
}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-4">
|
|
<div>
|
|
<label for="order" class="block text-sm font-medium text-gray-700">Display Order</label>
|
|
<input type="number" name="order" id="order" value={ fmt.Sprintf("%d", cat.Order) }
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm p-2 border" />
|
|
</div>
|
|
<div class="flex items-end pb-2">
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="is_active"
|
|
if cat.IsActive || cat.ID == 0 {
|
|
checked
|
|
}
|
|
class="rounded border-gray-300 text-indigo-600 shadow-sm focus:border-indigo-500 focus:ring-indigo-500" />
|
|
<span class="ml-2 text-sm text-gray-700">Active</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="description" class="block text-sm font-medium text-gray-700">Meta Description</label>
|
|
<textarea name="description" id="description" rows="3"
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm p-2 border">{ cat.Desc }</textarea>
|
|
</div>
|
|
|
|
<div>
|
|
<label for="keywords" class="block text-sm font-medium text-gray-700">Meta Keywords</label>
|
|
<input type="text" name="keywords" id="keywords" value={ cat.Keywords }
|
|
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm p-2 border" />
|
|
</div>
|
|
|
|
<div class="flex justify-end gap-3">
|
|
<a href="/admin/blog/categories" class="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50">Cancel</a>
|
|
<button type="submit" class="bg-indigo-600 text-white px-4 py-2 rounded-md hover:bg-indigo-700">
|
|
if cat.ID == 0 {
|
|
Create Category
|
|
} else {
|
|
Save Changes
|
|
}
|
|
</button>
|
|
</div>
|
|
</form>
|
|
<script>
|
|
autoSlug('title', 'slug');
|
|
</script>
|
|
</div>
|
|
}
|
|
}
|
|
|
|
func ifElse(cond bool, a, b string) string {
|
|
if cond {
|
|
return a
|
|
}
|
|
return b
|
|
}
|