93 lines
3.5 KiB
JavaScript
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;
|