Files
devil-fruit-encyclopedia/js/fruit.js
Claude c645ee09d2 Add original generated portrait/icon artwork for every entry
Adds js/portraits.js: procedurally generated, original SVG artwork for
all 101 characters (a role-themed line-art medallion — sword for
swordsmen, crown for royalty, compass for navigators, etc., derived
from each character's role/epithet/affiliation) and all 58 Devil
Fruits (a stylized swirled-fruit icon colored by category with the
fruit's symbolic emoji at center).

Official One Piece artwork is copyrighted (Oda/Shueisha/Toei), so
rather than scraping and re-hosting character art from the web, every
image here is drawn from scratch with basic SVG primitives — no
external assets, no copyright risk, fully offline-capable, and crisp
at any size since it's vector.

Wires the new generators into every card and detail view: character
cards/profile header, Devil Fruit cards/detail header, the Devil-Fruit
callout on character pages, and user chips on Devil Fruit pages.
Removes the now-unused plain-letter initialFor() avatar helper.
2026-08-14 23:47:39 +00:00

83 lines
2.8 KiB
JavaScript

/* Devil Fruit detail page: renders a full entry from ?id= against FRUITS/CHARACTERS. */
(function () {
const root = document.getElementById('fruit-content');
const id = qs('id');
const fruit = id ? findFruit(id) : null;
if (!fruit) {
root.innerHTML = `
<div class="empty-state">
Devil Fruit not found. <a href="fruits.html">Return to the Devil Fruit index</a>.
</div>
`;
return;
}
document.title = `${fruit.name} — One Piece Wiki`;
const metaDesc = document.querySelector('meta[name="description"]');
if (metaDesc) metaDesc.setAttribute('content', `${fruit.name} (${fruit.englishName}) — history, powers, and every known user on the One Piece Wiki.`);
const historyParagraphs = fruit.history.split('\n\n').map((p) => `<p>${escapeHtml(p)}</p>`).join('');
const usersHTML = fruit.users.map((u) => {
const c = findCharacter(u.id);
if (!c) return '';
return `
<a class="user-chip" href="${characterLink(c.id)}" style="--accent:${accentFor(c)}">
<div class="user-chip__avatar">${characterPortraitSVG(c)}</div>
<div>
<div class="user-chip__name">${escapeHtml(c.name)}</div>
<div class="user-chip__status">${escapeHtml(u.status)}</div>
</div>
</a>
`;
}).join('');
root.innerHTML = `
<section class="fruit-detail-header" data-cat="${escapeHtml(fruit.category)}">
<div class="fruit-detail-header__icon">${fruitPortraitSVG(fruit)}</div>
<div>
<p class="profile-eyebrow" style="color:var(--cat-color)">${escapeHtml(fruit.category)}${fruit.subtype ? ' · ' + escapeHtml(fruit.subtype) : ''}${fruit.awakened ? ' · Awakened' : ''}</p>
<h1>${escapeHtml(fruit.name)}</h1>
<p class="profile-epithet">${escapeHtml(fruit.englishName)}</p>
<p class="fruit-meaning">${escapeHtml(fruit.meaning)}</p>
</div>
</section>
<div class="profile-layout">
<div class="profile-main">
<div class="card">
<h2>Overview</h2>
<p>${escapeHtml(fruit.description)}</p>
</div>
<div class="card">
<h2>History</h2>
<div class="prose">${historyParagraphs}</div>
</div>
<div class="card">
<h2>Powers &amp; Techniques</h2>
<ul class="power-list">
${fruit.powers.map((p) => `<li>${escapeHtml(p)}</li>`).join('')}
</ul>
</div>
<div class="card">
<h2>Strengths &amp; Weaknesses</h2>
<p><strong style="color:var(--text)">Strengths:</strong> ${escapeHtml(fruit.strengths)}</p>
<p><strong style="color:var(--text)">Weaknesses:</strong> ${escapeHtml(fruit.weaknesses)}</p>
</div>
</div>
<aside class="card">
<h2>Users</h2>
<div class="user-list">
${usersHTML || '<p>No known users.</p>'}
</div>
</aside>
</div>
`;
})();