diff --git a/Dockerfile b/Dockerfile index 40f13c5..7340d81 100644 --- a/Dockerfile +++ b/Dockerfile @@ -7,6 +7,7 @@ COPY src /usr/share/nginx/html/src COPY assets/scenes /usr/share/nginx/html/assets/scenes COPY assets/characters /usr/share/nginx/html/assets/characters COPY assets/audio /usr/share/nginx/html/assets/audio +COPY assets/icons /usr/share/nginx/html/assets/icons COPY assets/voices /usr/share/nginx/html/assets/voices EXPOSE 80 diff --git a/assets/icons/chiave.svg b/assets/icons/chiave.svg new file mode 100644 index 0000000..71ecfdc --- /dev/null +++ b/assets/icons/chiave.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/libro.svg b/assets/icons/libro.svg new file mode 100644 index 0000000..d528bed --- /dev/null +++ b/assets/icons/libro.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/squama.svg b/assets/icons/squama.svg new file mode 100644 index 0000000..7fe619a --- /dev/null +++ b/assets/icons/squama.svg @@ -0,0 +1 @@ + diff --git a/src/main.js b/src/main.js index e51987a..09f9867 100644 --- a/src/main.js +++ b/src/main.js @@ -177,12 +177,21 @@ function updateInventory() { inventoryKey = key; const box = $('inventory'); box.replaceChildren(...game.state.inventory.map(id => { - const b = document.createElement('button'), item = story.items[id], dot = document.createElement('i'); + const b = document.createElement('button'), item = story.items[id]; b.type = 'button'; b.dataset.item = id; b.setAttribute('aria-pressed', String(command.item === id)); - dot.style.background = item.icon?.fill ?? '#ccc'; - b.append(dot, item.name); + // L'icona a pixel dell'oggetto (assets/icons); senza, un pallino del suo colore. + let icon; + if (item.icon?.src) { + icon = document.createElement('img'); + icon.src = item.icon.src; + icon.alt = ''; + } else { + icon = document.createElement('i'); + icon.style.background = item.icon?.fill ?? '#ccc'; + } + b.append(icon, item.name); let timer = null, long = false; b.addEventListener('pointerdown', () => { long = false; timer = setTimeout(() => { long = true; command.clickItem(id, { look: true }); }, LONG_PRESS); }); b.addEventListener('pointerup', () => clearTimeout(timer)); diff --git a/src/story/story.js b/src/story/story.js index 89c62ec..5983a7a 100644 --- a/src/story/story.js +++ b/src/story/story.js @@ -38,7 +38,7 @@ export const story = { items: { squama: { name: 'squama', - icon: { fill: '#4fae5e', shape: 'scale' }, + icon: { src: 'assets/icons/squama.svg', fill: '#4fae5e' }, actions: { look: [{ say: 'Una squama verde, grande come una moneta da due euro. Puzza di cantina.' }], use: [{ say: 'Potrei usarla come plettro. Ma prima scopro di chi è.' }], @@ -47,7 +47,7 @@ export const story = { // Lo scherzo del libro (idea di Andrea, 2026-10-23): «La storia infinita» ha una pagina sola. libro: { name: 'libro', - icon: { fill: '#c46a3a', shape: 'book' }, + icon: { src: 'assets/icons/libro.svg', fill: '#c46a3a' }, droppable: true, // non serve alla storia: si può buttare actions: { drop: [{ say: 'Una pagina sola, e pure con la fine. Lo lascio qui per il prossimo lettore.' }, { drop: 'libro' }], @@ -63,7 +63,7 @@ export const story = { // La chiave dell'oratorio: la dà San Pietro a chi risolve il suo indovinello. Indispensabile: non si butta. chiave_oratorio: { name: 'chiave dell\'oratorio', - icon: { fill: '#d9b54a', shape: 'key' }, + icon: { src: 'assets/icons/chiave.svg', fill: '#d9b54a' }, actions: { look: [{ say: 'Una chiave grossa e antica. Quella dell\'oratorio, parola di San Pietro.' }], }, diff --git a/style.css b/style.css index d638761..bbbabf3 100644 --- a/style.css +++ b/style.css @@ -44,6 +44,7 @@ body { display: flex; justify-content: center; overflow-x: hidden; -webkit-tap-h #inventory button { display: flex; align-items: center; gap: .35em; justify-content: center; color: var(--ink); } #inventory button[aria-pressed="true"] { border-color: var(--accent); } #inventory i { width: .8em; height: .8em; border-radius: 50% 50% 50% 0; flex: none; } +#inventory img { width: 1.9em; height: 1.9em; flex: none; image-rendering: pixelated; } #choices { margin: 0; padding: 10px 14px 12px 2.4em; background: var(--panel); min-height: 9.5em; } #choices li { padding: .25em 0; font-size: clamp(15px, 2vw, 22px); font-weight: bold; color: var(--dim); cursor: pointer; } diff --git a/tests/story.test.mjs b/tests/story.test.mjs index 1591f60..55c7d45 100644 --- a/tests/story.test.mjs +++ b/tests/story.test.mjs @@ -212,3 +212,11 @@ test('si buttano solo gli oggetti che non servono', () => { for (const [id, item] of Object.entries(story.items)) if (id !== 'libro') assert.ok(!item.droppable, `${id} serve alla storia: non deve potersi buttare`); }); + +test('ogni oggetto ha la sua icona a pixel', () => { + for (const [id, item] of Object.entries(story.items)) { + assert.ok(item.icon?.src, `${id}: manca l'icona`); + const svg = readFileSync(new URL('../' + item.icon.src, import.meta.url), 'utf8'); + assert.match(svg, /viewBox="0 0 16 16"/, `${id}: l'icona deve essere 16x16`); + } +});