Korjaa alikategoria-ongelmat
- api.php: getOrInitCategories() päivittää automaattisesti subcategories-kentän olemassaolevaan categories.json-tiedostoon ilman manuaalista seedausta - index.html: alikategoria-valitsin julkaisulomakkeeseen (näkyy kun kategorialla on alikategoriat) - script.js: subcategory tallennetaan uuteen julkaisuun - script.js: filterPosts null-turva + hakukenttä etsii myös alikategoria-id:llä - script.js: updateSubcategoryPicker() päivittää alikategoriat kategorian vaihtuessa Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
16
api.php
16
api.php
@@ -315,7 +315,21 @@ function getOrInitCategories(): array {
|
|||||||
writeData('categories.json', $cats);
|
writeData('categories.json', $cats);
|
||||||
return $cats;
|
return $cats;
|
||||||
}
|
}
|
||||||
return readData('categories.json', []);
|
$cats = readData('categories.json', []);
|
||||||
|
// Merge in subcategories if existing file doesn't have them yet
|
||||||
|
$defaults = defaultCategories();
|
||||||
|
$defaultMap = [];
|
||||||
|
foreach ($defaults as $d) { $defaultMap[$d['id']] = $d; }
|
||||||
|
$changed = false;
|
||||||
|
foreach ($cats as &$cat) {
|
||||||
|
if (!isset($cat['subcategories']) && isset($defaultMap[$cat['id']]['subcategories'])) {
|
||||||
|
$cat['subcategories'] = $defaultMap[$cat['id']]['subcategories'];
|
||||||
|
$changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($cat);
|
||||||
|
if ($changed) writeData('categories.json', $cats);
|
||||||
|
return $cats;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ─── Routing ───────────────────────────────────────────────────
|
// ─── Routing ───────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -109,7 +109,12 @@
|
|||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label>Kategoria</label>
|
<label>Kategoria</label>
|
||||||
<select id="sub-category"></select>
|
<select id="sub-category" onchange="updateSubcategoryPicker()"></select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group" id="sub-subcategory-group" style="display:none">
|
||||||
|
<label>Alikategoria</label>
|
||||||
|
<select id="sub-subcategory"></select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
|
|||||||
39
script.js
39
script.js
@@ -239,9 +239,10 @@ function filterPosts() {
|
|||||||
cards.forEach(card => {
|
cards.forEach(card => {
|
||||||
const matchesCat = currentFilter === 'all' || card.dataset.category === currentFilter;
|
const matchesCat = currentFilter === 'all' || card.dataset.category === currentFilter;
|
||||||
const matchesSub = currentSubFilter === 'all' || card.dataset.subcategory === currentSubFilter;
|
const matchesSub = currentSubFilter === 'all' || card.dataset.subcategory === currentSubFilter;
|
||||||
const title = card.querySelector('h3').textContent.toLowerCase();
|
const title = (card.querySelector('h3')?.textContent || '').toLowerCase();
|
||||||
const desc = card.querySelector('p:not(.card-author)').textContent.toLowerCase();
|
const desc = (card.querySelector('p:not(.card-author)')?.textContent || '').toLowerCase();
|
||||||
const matchesSearch = title.includes(query) || desc.includes(query);
|
const subLbl = (card.dataset.subcategory || '').toLowerCase();
|
||||||
|
const matchesSearch = !query || title.includes(query) || desc.includes(query) || subLbl.includes(query);
|
||||||
const show = matchesCat && matchesSub && matchesSearch;
|
const show = matchesCat && matchesSub && matchesSearch;
|
||||||
card.style.display = show ? '' : 'none';
|
card.style.display = show ? '' : 'none';
|
||||||
if (show) visible++;
|
if (show) visible++;
|
||||||
@@ -402,10 +403,27 @@ function setSubmitType(type) {
|
|||||||
document.getElementById('sub-typePostBtn').classList.toggle('active', type === 'post');
|
document.getElementById('sub-typePostBtn').classList.toggle('active', type === 'post');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateSubcategoryPicker() {
|
||||||
|
const catId = document.getElementById('sub-category').value;
|
||||||
|
const cat = APP.categories.find(c => c.id === catId);
|
||||||
|
const subs = cat?.subcategories || [];
|
||||||
|
const group = document.getElementById('sub-subcategory-group');
|
||||||
|
const sel = document.getElementById('sub-subcategory');
|
||||||
|
if (!subs.length) {
|
||||||
|
group.style.display = 'none';
|
||||||
|
sel.innerHTML = '';
|
||||||
|
} else {
|
||||||
|
sel.innerHTML = `<option value="">— Valitse alikategoria —</option>` +
|
||||||
|
subs.map(s => `<option value="${s.id}">${s.fi}</option>`).join('');
|
||||||
|
group.style.display = '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function openSubmitModal() {
|
function openSubmitModal() {
|
||||||
const cats = APP.categories;
|
const cats = APP.categories;
|
||||||
const sel = document.getElementById('sub-category');
|
const sel = document.getElementById('sub-category');
|
||||||
sel.innerHTML = cats.map(c => `<option value="${c.id}">${c.emoji || ''} ${c.fi}</option>`).join('');
|
sel.innerHTML = cats.map(c => `<option value="${c.id}">${c.emoji || ''} ${c.fi}</option>`).join('');
|
||||||
|
updateSubcategoryPicker();
|
||||||
setSubmitType('recipe');
|
setSubmitType('recipe');
|
||||||
document.getElementById('submitOverlay').classList.add('open');
|
document.getElementById('submitOverlay').classList.add('open');
|
||||||
document.body.style.overflow = 'hidden';
|
document.body.style.overflow = 'hidden';
|
||||||
@@ -507,12 +525,13 @@ async function submitPublicPost() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const category = document.getElementById('sub-category').value;
|
const category = document.getElementById('sub-category').value;
|
||||||
const cat = APP.categories.find(c => c.id === category);
|
const subcategory = document.getElementById('sub-subcategory')?.value || '';
|
||||||
const emoji = cat?.emoji || '📝';
|
const cat = APP.categories.find(c => c.id === category);
|
||||||
const author = document.getElementById('sub-author').value.trim() || 'Vieras';
|
const emoji = cat?.emoji || '📝';
|
||||||
const desc = document.getElementById('sub-desc').value.trim();
|
const author = document.getElementById('sub-author').value.trim() || 'Vieras';
|
||||||
const images = [
|
const desc = document.getElementById('sub-desc').value.trim();
|
||||||
|
const images = [
|
||||||
document.getElementById('sub-img1').value.trim(),
|
document.getElementById('sub-img1').value.trim(),
|
||||||
document.getElementById('sub-img2').value.trim(),
|
document.getElementById('sub-img2').value.trim(),
|
||||||
document.getElementById('sub-img3').value.trim(),
|
document.getElementById('sub-img3').value.trim(),
|
||||||
@@ -520,7 +539,7 @@ async function submitPublicPost() {
|
|||||||
|
|
||||||
const post = {
|
const post = {
|
||||||
id: title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/\s+/g,'_').replace(/[^a-z0-9_]/g,'') + '_' + Date.now(),
|
id: title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/\s+/g,'_').replace(/[^a-z0-9_]/g,'') + '_' + Date.now(),
|
||||||
title, emoji, category, author, desc, images,
|
title, emoji, category, subcategory, author, desc, images,
|
||||||
type: submitType,
|
type: submitType,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user