From 74c31f898c9b66408873c9c68f7e3eb6c3d17b9c Mon Sep 17 00:00:00 2001 From: Jukka Lampikoski Date: Sun, 8 Mar 2026 12:48:01 +0200 Subject: [PATCH] Add subcategory management to admin panel + Kala/Liha defaults Categories now show their subcategories as tags with remove buttons, plus an input field to add new subcategories directly from admin. Added Kala and Liha as default subcategories for Reseptit. Co-Authored-By: Claude Opus 4.6 --- admin.html | 68 ++++++++++++++++++++++++++++++++++++++++++++++-------- api.php | 2 ++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/admin.html b/admin.html index f6a02b0..7cea3b6 100644 --- a/admin.html +++ b/admin.html @@ -159,6 +159,19 @@ .cat-info { flex: 1; font-family: Arial, sans-serif; font-size: 0.88rem; color: #3b2a1a; } .cat-info span { color: #7a5c3e; font-size: 0.78rem; } + /* Subcategory tags */ + .subcat-row { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; padding-left: 38px; } + .subcat-tag { + display: inline-flex; align-items: center; gap: 4px; + background: #f5ece0; color: #7c4a1e; padding: 3px 10px; border-radius: 12px; + font-family: Arial, sans-serif; font-size: 0.78rem; font-weight: bold; + } + .subcat-remove { + background: none; border: none; color: #c0856a; cursor: pointer; + font-size: 0.7rem; padding: 0 2px; line-height: 1; + } + .subcat-remove:hover { color: #c04040; } + /* User list */ .user-table { width: 100%; border-collapse: collapse; font-family: Arial, sans-serif; font-size: 0.88rem; } .user-table th { text-align: left; color: #7a5c3e; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.5px; padding: 6px 10px; border-bottom: 2px solid #e8d5c0; } @@ -575,19 +588,54 @@ const cats = ADMIN.categories; const el = document.getElementById('catList'); if (!cats.length) { el.innerHTML = `

${at('cat_empty')}

`; return; } - el.innerHTML = cats.map(c => ` -
- ${c.emoji || '📁'} -
- ${c.fi} / ${c.en} - · id: ${c.id} -
- -
- `).join(''); + el.innerHTML = cats.map(c => { + const subs = (c.subcategories || []).map(s => + `${s.fi} ` + ).join(''); + return ` +
+ ${c.emoji || '📁'} +
+ ${c.fi} / ${c.en} + · id: ${c.id} +
+ +
+ ${subs || 'Ei alikategorioita'} +
+ + +
+
+
`; + }).join(''); populateCategorySelect(); } + async function addSubcat(catId) { + const input = document.getElementById('newSub_' + catId); + const name = input.value.trim(); + if (!name) return; + const cat = ADMIN.categories.find(c => c.id === catId); + if (!cat) return; + if (!cat.subcategories) cat.subcategories = []; + const id = name.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/\s+/g,'_').replace(/[^a-z0-9_]/g,''); + if (cat.subcategories.some(s => s.id === id)) { showToast('⚠️ Alikategoria on jo olemassa.'); return; } + cat.subcategories.push({ id, fi: name }); + await apiPost('save_categories', { categories: ADMIN.categories }); + renderCatList(); + showToast('✅ Alikategoria lisätty!'); + } + + async function removeSubcat(catId, subId) { + const cat = ADMIN.categories.find(c => c.id === catId); + if (!cat) return; + cat.subcategories = (cat.subcategories || []).filter(s => s.id !== subId); + await apiPost('save_categories', { categories: ADMIN.categories }); + renderCatList(); + showToast('🗑️ Alikategoria poistettu.'); + } + async function addCategory() { const fi = document.getElementById('newCatFi').value.trim(); const en = document.getElementById('newCatEn').value.trim(); diff --git a/api.php b/api.php index 0795a86..a4dbaa6 100644 --- a/api.php +++ b/api.php @@ -104,6 +104,8 @@ function defaultCategories(): array { 'subcategories' => [ ['id' => 'kasvis', 'fi' => 'Kasvis'], ['id' => 'vegaaniset', 'fi' => 'Vegaaniset'], + ['id' => 'kala', 'fi' => 'Kala'], + ['id' => 'liha', 'fi' => 'Liha'], ['id' => 'jalkiruuat', 'fi' => 'Jälkiruuat'], ['id' => 'muut', 'fi' => 'Muut'], ]],