mirror of
https://github.com/Cametendo/devil-fruit-encyclopedia.git
synced 2026-09-14 00:09:47 +02:00
Replaces the 4-card quickstart mockup with a data-driven wiki covering the 100 most well-known One Piece characters and every Devil Fruit they carry (57 fruits total), each with its own linked detail page. - js/characters-data.js: 100 character profiles (stats, bio, abilities) - js/fruits-data.js: 57 Devil Fruit entries (history, powers, strengths/ weaknesses, full user lineage) cross-linked to character ids - index.html + main.js: searchable/filterable character grid - character.html + character.js: character detail template driven by ?id= - fruits.html + fruits.js: searchable Devil Fruit index with type filter - fruit.html + fruit.js: Devil Fruit detail template driven by ?id= - css/styles.css: new wanted-poster/ocean-navy design system, responsive - Fixed docker-compose volume mount (previously pointed at a nonexistent ./data directory) and rewrote README for the new structure Verified with a headless browser: all four page types render without script errors, search/filter interactions work, and every character- fruit cross-reference resolves correctly.
50 lines
2.0 KiB
JavaScript
50 lines
2.0 KiB
JavaScript
/* Devil Fruit index page: search + category filter over FRUITS. */
|
|
|
|
(function () {
|
|
const grid = document.getElementById('fruit-grid');
|
|
const searchInput = document.getElementById('search-input');
|
|
const resultCount = document.getElementById('result-count');
|
|
const chipRow = document.getElementById('category-chips');
|
|
|
|
document.getElementById('stat-fruits').textContent = FRUITS.length;
|
|
document.getElementById('stat-paramecia').textContent = FRUITS.filter((f) => f.category === 'Paramecia').length;
|
|
document.getElementById('stat-zoan').textContent = FRUITS.filter((f) => f.category === 'Zoan').length;
|
|
document.getElementById('stat-logia').textContent = FRUITS.filter((f) => f.category === 'Logia').length;
|
|
|
|
const categories = ['All', 'Paramecia', 'Zoan', 'Logia'];
|
|
let activeCategory = 'All';
|
|
|
|
chipRow.innerHTML = categories.map((cat) =>
|
|
`<button type="button" class="chip${cat === activeCategory ? ' is-active' : ''}" data-cat="${cat}">${cat}</button>`
|
|
).join('');
|
|
|
|
function applyFilters() {
|
|
const term = searchInput.value.trim().toLowerCase();
|
|
|
|
const results = FRUITS.filter((f) => {
|
|
if (activeCategory !== 'All' && f.category !== activeCategory) return false;
|
|
if (term) {
|
|
const userNames = f.users.map((u) => (findCharacter(u.id) || {}).name || '').join(' ');
|
|
const haystack = `${f.name} ${f.englishName} ${f.tagline} ${userNames}`.toLowerCase();
|
|
if (!haystack.includes(term)) return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
renderCardGrid(grid, results, fruitCardHTML, 'No Devil Fruits match your search.');
|
|
resultCount.textContent = `${results.length} of ${FRUITS.length} Devil Fruits`;
|
|
}
|
|
|
|
chipRow.addEventListener('click', (e) => {
|
|
const btn = e.target.closest('.chip');
|
|
if (!btn) return;
|
|
activeCategory = btn.dataset.cat;
|
|
chipRow.querySelectorAll('.chip').forEach((c) => c.classList.toggle('is-active', c === btn));
|
|
applyFilters();
|
|
});
|
|
|
|
searchInput.addEventListener('input', applyFilters);
|
|
|
|
applyFilters();
|
|
})();
|