Files
pantry-management-frontend/item-component.js
2026-03-08 16:25:59 +00:00

93 lines
3.5 KiB
JavaScript

// item-component.js
// Reusable item component: image on left, three text areas on right.
const _ensureStyles = (() => {
if (document.getElementById('item-component-styles')) return true;
const style = document.createElement('style');
style.id = 'item-component-styles';
style.textContent = `
/* Grid wrapper for multiple item components */
.item-component-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:16px;align-items:start}
.item-component{display:flex;align-items:flex-start;gap:12px;font-family:inherit;padding:10px;border:1px solid #e6e6e6;border-radius:8px;background:#fff}
.item-component__img{flex:0 0 auto}
.item-component__img img{display:block;width:72px;height:72px;object-fit:cover;border-radius:6px}
.item-component__content{flex:1;display:flex;flex-direction:column;gap:6px}
.item-component__line{margin:0;padding:0;color:#222}
.item-component__line--title{font-weight:700}
.item-component__line--subtitle{color:#555;font-size:0.95em}
.item-component__line--desc{color:#666;font-size:0.9em}
.item-component__textarea{width:100%;box-sizing:border-box;padding:6px;font:inherit;border:1px solid #ccc;border-radius:4px}
/* Responsive: on small screens show 1 or 2 columns */
@media (max-width: 900px){
.item-component-grid{grid-template-columns:repeat(2,1fr)}
}
@media (max-width: 560px){
.item-component-grid{grid-template-columns:repeat(1,1fr)}
}
`;
document.head.appendChild(style);
return true;
})();
/**
* Create an item component element.
* @param {Object} opts
* @param {string} opts.imgSrc - image URL
* @param {string} opts.imgAlt - image alt text
* @param {string} opts.text1 - first text area (title)
* @param {string} opts.text2 - second text area (subtitle)
* @param {string} opts.text3 - third text area (description)
* @param {boolean} opts.editable - if true, text areas are `<textarea>` elements for editing
* @param {number} opts.imgWidth - image width in px
* @param {number} opts.imgHeight - image height in px
* @returns {HTMLElement}
*/
export function createItemComponent({imgSrc = '', imgAlt = '', text1 = '', text2 = '', text3 = '', editable = false, imgWidth = 80, imgHeight = 80} = {}) {
_ensureStyles;
const root = document.createElement('div');
root.className = 'item-component';
// Image container
const imgWrap = document.createElement('div');
imgWrap.className = 'item-component__img';
const img = document.createElement('img');
if (imgSrc) img.src = imgSrc;
img.alt = imgAlt || '';
img.width = imgWidth;
img.height = imgHeight;
imgWrap.appendChild(img);
root.appendChild(imgWrap);
// Content container with three text areas
const content = document.createElement('div');
content.className = 'item-component__content';
function makeTextNode(text, cls) {
if (editable) {
const ta = document.createElement('textarea');
ta.className = 'item-component__textarea ' + cls;
ta.value = text;
return ta;
}
const el = document.createElement('div');
el.className = 'item-component__line ' + cls;
el.textContent = text;
return el;
}
const line1 = makeTextNode(text1, 'item-component__line--title');
const line2 = makeTextNode(text2, 'item-component__line--subtitle');
const line3 = makeTextNode(text3, 'item-component__line--desc');
content.appendChild(line1);
content.appendChild(line2);
content.appendChild(line3);
root.appendChild(content);
return root;
}
export default createItemComponent;