SpreadJS supports Image Rich Data as cell values. You can use the setValue API with IImageRichData objects to embed images directly in cells.
The IImageRichData structure includes:
richDataType: Must be "Image"
value.src: The location of the image on the web or base64 string
value.altText: A text description for the image
This demo shows a product inventory list with embedded product images.
// Product image base64 data (64x64 PNG icons)
var productImages = {
laptop: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAYAAADDPmHLAAAFiUlEQVR4nO3dwU8cZRjH8WdgobQU2bailBobbROsgt2aeC1bjXrw4HLx0JhI48H4B3jwJJ49eDSexMT04KUbjfGE3e3VaBdBK4nV1LQUJW0XgRaEZXxeyuyyy7LLvMvO+848v0+yk3cghIT32/dd3jSMQyAaAhAOAQiHAIRDAMIhAOEQgHAIQDgEIBwCEA4BCIcAhEMAwiEA4RCAcAhAOAQgHAIQbk8CeD45/Pa66444LiVcojh/CJqEJyzvOpRrcZyxnzOXvuAPNcThl7ZEMhVfc+kSuZQkCJ5DmZhDw7lMOs93WhoKYGAodRmTbxhHMJVNn+ORFodfWgaTqRF3nT7nIRjmtNCFyUx6jDRoBzBwNpUhoiF+bWh94jmKDb5KzqE+voNmcZfu0tqPX1Ph5i98V5SdupJOkgbtAAbPpu65W97w7XvjA3I6D/MIms29N0Mr333Co4d4EvOTV9KHeOgbf60eXgF4/ks6zn/MVwjK8sX3+VrCK4DWXGp9kYIAzEIAwiEA4UITQGebQ0e72qitVftbibRacOn2wiotrZb9mItCE8DJw+2YfE0qgt/v/sej7UITwKmefXwFXdfmVvi6HQIQAgEIhwCEQwDCIQDhEIBwCEC4yAdw5EArne7dTwfaWvjOHvdX12li9gHduV/gO3MiH8BLTx+0bvI9KoLv/1jkkTmRD+C1k13WHhU/4ADGEUB1exWA2gISvAXst2wVUJOfwxaws70KAGpDAMIhAOEQgHAIQDgEIFzkA1C/BgZxEqgOdWw42fMr8gEEeRKoIjB9sudX5AMI8iRQHe6YPtnzK/IBqC0giJNANfk2nOz5FfkAoDYEIBwCEA4BCIcAhEMAwkU+APVrYBAngfWoQyIbTwojH0CQJ4H1qAhsOymMfABBngTWow6LbDspjHwAagsI4iSwHjX5Np4URj4AqA0BCIcAhEMAwiEA4RCAcAhAOAQgXOgD6H+0nVoc7W8jWiT+UCT+VKweNfmR+FOx0BwIQDgEIBwCEM54AINDqbzrUjcPN+ChUcHZ9tAoh+Yns+niA7z80A6AV4AMlT02boBig6/gsXFN9vCxcd9Q4eYU3xUZeGwcHhxpDSMPjlQqVwEwQvtfv9JQABsPj16nNA+NRXCs7zE6l3yRuro6+S44CwtLdDnzA92a+YfvjMnGWihl7OHRns3tYITfjCS2vjEMwlvnXw988j0qgi8vfsuj4PDPeJ5/xjle9sd0l/2tqgbAE5riCT3NQ+u99+6bo2TQp599NUohwMFMcDBpHpapGgAv7Qle2q/y0HocAF/N4QD4aj/eKs7wVpHjYZmqASj8Bm+UiD7kl9XeuTBM7e1tPAqeiS1A00f8RnGUqtgxAGVgKJUjt7QVPNv/JF/tEo8/Qv3PnKCOjmD/38Hy8gpN/3ad8vl/+c4uv07/xddNDk1MZdMJHlVVM4DKrUAFcKr/OI/AVtemb5QFsNPS76kZgFK5Fbw89ALFu82864ba8vNLNJ79iUdFOy79nroBKFu3gnj3QY7gDI/sFmuN0eM9PTwi+ntujtYKazwqafTzNhrPXuUIFnnE6iz9nl0FEMat4FjvUTpx/CkeEV2/8Sfdmr3No5JGP28bv0u/x+HXroRtK6g3gY1+3iY6S7/H4deuhWkrqLeEN/p5m+gs/R5fAYRxK4g63aXf4ysAJWxbQZQ1svR7fAegVG4Ffb1HeARBm5m9wxEs8oj5XPo9WgFUbgVgnt+l36MVgFK5FYBRvpd+j3YAymYEYJju5CsNBQDhhwCEQwDCIQDhEIBwCEA4BCAcAhAOAQiHAIRDAMIhAOEQgHAIQDgEIBwCEA4BCIcAhEMAwiEA4RCAcAhAOAQgHAIQDgEIhwCEQwDCIQDhEIBwCEC4/wHuWNqug6X4qQAAAABJRU5ErkJggg==",
phone: "data:image/png;base64,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",
headphones: "data:image/png;base64,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",
watch: "data:image/png;base64,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",
camera: "data:image/png;base64,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"
};
// Default product data
var defaultProducts = [
{ name: "Laptop Pro", imageBase64: productImages.laptop, price: 1299, stock: 45, area: "North America" },
{ name: "SmartPhone X", imageBase64: productImages.phone, price: 899, stock: 120, area: "Asia-Pacific" },
{ name: "Studio Phones", imageBase64: productImages.headphones, price: 349, stock: 200, area: "Europe" },
{ name: "Sport Watch", imageBase64: productImages.watch, price: 499, stock: 75, area: "Asia-Pacific" },
{ name: "DSLR Camera", imageBase64: productImages.camera, price: 1599, stock: 30, area: "North America" }
];
// Map of product name (lowercase) → base64 for existing-name detection
var productNameImageMap = {};
var spread, sheet, currentRowCount;
var allProducts = []; // persistent store of all product data
var DATA_START_ROW = 1; // row 0 is header
var DATA_COL_NAME = 0;
var DATA_COL_IMAGE = 1;
var DATA_COL_AREA = 2;
var DATA_COL_PRICE = 3;
var DATA_COL_STOCK = 4;
var TABLE_NAME = "ProductTable";
window.onload = function () {
spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 1 });
initSpread(spread);
bindEvents();
initPanelToggle();
};
function initPanelToggle() {
var panel = document.querySelector('.options-container');
var toggleBtn = document.getElementById('panelToggleBtn');
var collapseBtn = document.getElementById('panelCollapseBtn');
function collapsePanel() {
panel.classList.add('collapsed');
toggleBtn.classList.add('visible');
setTimeout(function () { spread.refresh(); }, 320);
}
function expandPanel() {
panel.classList.remove('collapsed');
toggleBtn.classList.remove('visible');
setTimeout(function () { spread.refresh(); }, 320);
}
collapseBtn.addEventListener('click', collapsePanel);
toggleBtn.addEventListener('click', expandPanel);
}
function initSpread(spread) {
spread.suspendPaint();
sheet = spread.getSheet(0);
sheet.name("Product Inventory");
sheet.setRowCount(200);
sheet.setColumnCount(15);
// Set up headers
sheet.setValue(0, DATA_COL_NAME, "Product Name");
sheet.setValue(0, DATA_COL_IMAGE, "Product Image");
sheet.setValue(0, DATA_COL_AREA, "Area");
sheet.setValue(0, DATA_COL_PRICE, "Price ($)");
sheet.setValue(0, DATA_COL_STOCK, "Stock");
// Set column widths
sheet.setColumnWidth(DATA_COL_NAME, 140);
sheet.setColumnWidth(DATA_COL_IMAGE, 100);
sheet.setColumnWidth(DATA_COL_AREA, 120);
sheet.setColumnWidth(DATA_COL_PRICE, 100);
sheet.setColumnWidth(DATA_COL_STOCK, 80);
// Set uniform row height for all data rows (row 1 to 199) to accommodate images
var DATA_ROW_HEIGHT = 50;
for (var r = DATA_START_ROW; r < 200; r++) {
sheet.setRowHeight(r, DATA_ROW_HEIGHT);
}
// Style headers
var headerStyle = new GC.Spread.Sheets.Style();
headerStyle.font = "bold 13px Calibri";
headerStyle.backColor = "#4a7a00";
headerStyle.foreColor = "#ffffff";
headerStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
headerStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
for (var c = 0; c <= 4; c++) {
sheet.setStyle(0, c, headerStyle);
}
// Populate default product data
currentRowCount = 0;
for (var i = 0; i < defaultProducts.length; i++) {
addProductRow(defaultProducts[i]);
}
// Create table from data
createDataTable();
spread.resumePaint();
}
function createImageRichData(imageBase64, altText) {
return {
richDataType: "Image",
value: {
src: imageBase64,
altText: altText || ""
}
};
}
function addProductRow(product) {
var row = DATA_START_ROW + currentRowCount;
sheet.setValue(row, DATA_COL_NAME, product.name);
// Set image using IImageRichData
var imageData = createImageRichData(product.imageBase64, product.name);
sheet.setValue(row, DATA_COL_IMAGE, imageData);
sheet.setValue(row, DATA_COL_PRICE, product.price);
sheet.setValue(row, DATA_COL_STOCK, product.stock);
sheet.setValue(row, DATA_COL_AREA, product.area);
// Center-align cells
var cellStyle = new GC.Spread.Sheets.Style();
cellStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
cellStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
sheet.setStyle(row, DATA_COL_IMAGE, cellStyle);
sheet.setStyle(row, DATA_COL_PRICE, cellStyle);
sheet.setStyle(row, DATA_COL_STOCK, cellStyle);
sheet.setStyle(row, DATA_COL_AREA, cellStyle);
var nameStyle = new GC.Spread.Sheets.Style();
nameStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
sheet.setStyle(row, DATA_COL_NAME, nameStyle);
currentRowCount++;
// Register in name→image map
productNameImageMap[product.name.toLowerCase()] = product.imageBase64;
// Persist in allProducts array
allProducts.push({ name: product.name, imageBase64: product.imageBase64, price: product.price, stock: product.stock, area: product.area });
}
function createDataTable() {
// Remove existing table if present (this may clear cell data in some SpreadJS builds)
try {
sheet.tables.remove(TABLE_NAME);
} catch (e) { /* ignore if not exists */ }
// Always re-write header row (also cleared by tables.remove)
sheet.setValue(0, DATA_COL_NAME, "Product Name");
sheet.setValue(0, DATA_COL_IMAGE, "Product Image");
sheet.setValue(0, DATA_COL_AREA, "Area");
sheet.setValue(0, DATA_COL_PRICE, "Price ($)");
sheet.setValue(0, DATA_COL_STOCK, "Stock");
var headerStyle = new GC.Spread.Sheets.Style();
headerStyle.font = "bold 13px Calibri";
headerStyle.backColor = "#4a7a00";
headerStyle.foreColor = "#ffffff";
headerStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
headerStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
for (var h = 0; h <= 4; h++) {
sheet.setStyle(0, h, headerStyle);
}
// Always re-write all product rows from the in-memory array so data is never lost
var centerStyle = new GC.Spread.Sheets.Style();
centerStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
centerStyle.hAlign = GC.Spread.Sheets.HorizontalAlign.center;
var nameStyle = new GC.Spread.Sheets.Style();
nameStyle.vAlign = GC.Spread.Sheets.VerticalAlign.center;
for (var i = 0; i < allProducts.length; i++) {
var p = allProducts[i];
var row = DATA_START_ROW + i;
sheet.setValue(row, DATA_COL_NAME, p.name);
sheet.setValue(row, DATA_COL_IMAGE, createImageRichData(p.imageBase64, p.name));
sheet.setValue(row, DATA_COL_PRICE, p.price);
sheet.setValue(row, DATA_COL_STOCK, p.stock);
sheet.setValue(row, DATA_COL_AREA, p.area);
sheet.setStyle(row, DATA_COL_NAME, nameStyle);
sheet.setStyle(row, DATA_COL_IMAGE, centerStyle);
sheet.setStyle(row, DATA_COL_PRICE, centerStyle);
sheet.setStyle(row, DATA_COL_STOCK, centerStyle);
sheet.setStyle(row, DATA_COL_AREA, centerStyle);
}
var table = sheet.tables.add(
TABLE_NAME,
0, // start row
0, // start col
allProducts.length + 1, // header + data rows
5 // col count
);
table.style(GC.Spread.Sheets.Tables.TableThemes.light6);
}
function bindEvents() {
var nameInput = document.getElementById("productName");
var fileInput = document.getElementById("productImageFile");
var uploadLabel = document.getElementById("imageUploadLabel");
var uploadText = document.getElementById("imageUploadText");
var previewWrap = document.getElementById("imagePreviewWrap");
var previewImg = document.getElementById("imagePreview");
var clearBtn = document.getElementById("imageClearBtn");
var base64Input = document.getElementById("productImageBase64");
var uploadGroup = document.getElementById("imageUploadGroup");
function setPreview(base64) {
base64Input.value = base64;
previewImg.src = base64;
previewWrap.style.display = "inline-block";
uploadLabel.style.display = "none";
}
function clearPreview() {
base64Input.value = "";
previewImg.src = "";
previewWrap.style.display = "none";
fileInput.value = "";
uploadLabel.style.display = "";
uploadLabel.classList.remove("locked");
uploadText.textContent = "Click to upload image";
// Remove locked notice if present
var notice = uploadGroup.querySelector(".image-locked-notice");
if (notice) notice.remove();
}
// Product name input: check if name matches an existing product
nameInput.addEventListener("input", function () {
var key = nameInput.value.trim().toLowerCase();
var existing = productNameImageMap[key];
if (existing) {
// Lock image to the existing product's image
setPreview(existing);
uploadLabel.classList.add("locked");
uploadText.textContent = "Image locked (existing product)";
clearBtn.style.display = "none";
if (!uploadGroup.querySelector(".image-locked-notice")) {
var notice = document.createElement("p");
notice.className = "image-locked-notice";
notice.textContent = "Image is auto-filled from existing product.";
uploadGroup.appendChild(notice);
}
} else {
// Not an existing product — allow normal upload
uploadLabel.classList.remove("locked");
clearBtn.style.display = "";
var notice = uploadGroup.querySelector(".image-locked-notice");
if (notice) notice.remove();
// If the current preview came from a lock, clear it
if (uploadLabel.style.display === "none" && base64Input.value) {
// keep user's uploaded image if they already uploaded
}
}
});
// File upload: read as base64 and preview
fileInput.addEventListener("change", function () {
var file = fileInput.files[0];
if (!file) return;
var reader = new FileReader();
reader.onload = function (e) {
setPreview(e.target.result);
};
reader.readAsDataURL(file);
});
// Clear image button
clearBtn.addEventListener("click", function (e) {
e.stopPropagation();
clearPreview();
});
// Add product button
document.getElementById("btnAddProduct").addEventListener("click", function () {
var name = nameInput.value.trim();
var imageBase64 = base64Input.value;
var price = parseFloat(document.getElementById("productPrice").value);
var stock = parseInt(document.getElementById("productStock").value, 10);
var area = document.getElementById("productArea").value;
if (!name) {
alert("Please enter a product name.");
return;
}
if (!imageBase64) {
alert("Please upload a product image.");
return;
}
if (isNaN(price) || price <= 0) {
alert("Please enter a valid price.");
return;
}
if (isNaN(stock) || stock < 0) {
alert("Please enter a valid stock quantity.");
return;
}
spread.suspendPaint();
addProductRow({ name: name, imageBase64: imageBase64, price: price, stock: stock, area: area });
createDataTable();
spread.resumePaint();
// Clear inputs
nameInput.value = "";
document.getElementById("productPrice").value = "";
document.getElementById("productStock").value = "";
clearPreview();
});
}
<!doctype html>
<html style="height:100%;font-size:14px;">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/styles/gc.spread.sheets.excel2013white.css">
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets/dist/gc.spread.sheets.all.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/en/purejs/node_modules/@mescius/spread-sheets-shapes/dist/gc.spread.sheets.shapes.min.js" type="text/javascript"></script>
<script src="$DEMOROOT$/spread/source/js/license.js" type="text/javascript"></script>
<script src="app.js" type="text/javascript"></script>
<link rel="stylesheet" type="text/css" href="styles.css">
</head>
<body>
<div class="sample-tutorial">
<div id="ss" class="sample-spreadsheets"></div>
<div id="panelToggleBtn" class="panel-toggle-btn" title="Toggle Panel">
<span class="panel-toggle-icon"><span></span></span>
</div>
<div class="options-container">
<div class="panel-header">
<span class="panel-title">Image Rich Data</span>
<span id="panelCollapseBtn" class="panel-collapse-btn" title="Collapse">×</span>
</div>
<div class="panel-section">
<div class="panel-section-title">
<span>Add Product</span>
</div>
<div class="panel-card">
<div class="form-group">
<label class="form-label" for="productName">Product Name</label>
<input id="productName" class="form-input" type="text" placeholder="e.g. Tablet" />
</div>
<div class="form-group" id="imageUploadGroup">
<label class="form-label">Product Image</label>
<label id="imageUploadLabel" class="image-upload-label" for="productImageFile">
<span id="imageUploadText">Click to upload image</span>
<input id="productImageFile" type="file" accept="image/*" style="display:none;" />
</label>
<div id="imagePreviewWrap" class="image-preview-wrap" style="display:none;">
<img id="imagePreview" class="image-preview" src="" alt="preview" />
<button id="imageClearBtn" class="image-clear-btn" type="button" title="Remove image">×</button>
</div>
<input id="productImageBase64" type="hidden" value="" />
</div>
<div class="form-group">
<label class="form-label" for="productPrice">Product Price ($)</label>
<input id="productPrice" class="form-input" type="number" placeholder="e.g. 999" />
</div>
<div class="form-group">
<label class="form-label" for="productStock">Product Stock</label>
<input id="productStock" class="form-input" type="number" placeholder="e.g. 50" />
</div>
<div class="form-group">
<label class="form-label" for="productArea">Product Area</label>
<select id="productArea" class="form-select">
<option value="Asia-Pacific">Asia-Pacific</option>
<option value="Europe">Europe</option>
<option value="North America">North America</option>
<option value="Middle East">Middle East</option>
<option value="Latin America">Latin America</option>
</select>
</div>
<div class="panel-actions">
<button id="btnAddProduct" class="btn btn-primary">Add Product</button>
</div>
</div>
</div>
<div class="panel-section">
<div class="panel-section-title">
<span>Info</span>
</div>
<div class="panel-info">
<p>This demo uses <code>IImageRichData</code> to set image cell values via <code>setValue</code>.</p>
<p>Click <strong>Add Product</strong> to append a new product row to the table.</p>
</div>
</div>
</div>
</div>
</body>
</html>
body {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
.sample-tutorial {
position: relative;
height: 100%;
overflow: hidden;
}
.sample-spreadsheets {
width: 100%;
height: 100%;
overflow: hidden;
}
.options-container {
position: absolute;
top: 0;
right: 0;
width: 400px;
height: 100%;
box-sizing: border-box;
background: #fff;
overflow-y: auto;
overflow-x: hidden;
z-index: 1000;
box-shadow: -2px 0 12px rgba(0, 0, 0, 0.10);
transition: transform 0.3s ease;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
font-size: 13px;
color: #333;
}
.options-container.collapsed {
transform: translateX(100%);
}
.panel-toggle-btn {
position: absolute;
top: 8px;
right: 8px;
z-index: 999;
width: 36px;
height: 36px;
background: #4a7a00;
border-radius: 8px;
cursor: pointer;
display: none;
align-items: center;
justify-content: center;
box-shadow: 0 2px 8px rgba(74, 122, 0, 0.3);
transition: background 0.2s;
}
.panel-toggle-btn:hover {
background: #3d6b00;
}
.panel-toggle-btn.visible {
display: flex;
}
.panel-toggle-icon {
width: 18px;
height: 14px;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.panel-toggle-icon::before,
.panel-toggle-icon::after,
.panel-toggle-icon span {
content: '';
display: block;
height: 2px;
background: #fff;
border-radius: 1px;
}
.options-container .panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
border-bottom: 1px solid #e8e8e8;
background: #fff;
position: sticky;
top: 0;
z-index: 2;
}
.options-container .panel-title {
font-weight: 600;
font-size: 15px;
color: #1a1a1a;
}
.options-container .panel-collapse-btn {
cursor: pointer;
font-size: 20px;
color: #999;
width: 28px;
height: 28px;
line-height: 28px;
text-align: center;
border-radius: 6px;
user-select: none;
transition: all 0.15s;
}
.options-container .panel-collapse-btn:hover {
background: #f0f0f0;
color: #333;
}
.options-container .panel-section {
padding: 12px 16px;
border-bottom: 1px solid #f0f0f0;
}
.options-container .panel-section:last-child {
border-bottom: none;
}
.options-container .panel-section-title {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 10px;
font-weight: 600;
font-size: 13px;
color: #555;
text-transform: uppercase;
letter-spacing: 0.3px;
}
.options-container .panel-card {
background: #fafafa;
border: 1px solid #e8e8e8;
border-radius: 8px;
padding: 14px;
}
.options-container .form-group {
margin-bottom: 12px;
}
.options-container .form-group:last-of-type {
margin-bottom: 0;
}
.options-container .form-group-inline {
display: flex;
align-items: center;
}
.options-container .form-group-inline .form-label {
display: inline-block;
width: 100px;
min-width: 100px;
margin-bottom: 0;
padding: 0 4px;
box-sizing: border-box;
}
.options-container .form-group-inline .form-select {
flex: 1;
margin-left: 8px;
}
.options-container .form-label {
display: block;
font-size: 12px;
font-weight: 500;
color: #666;
margin-bottom: 4px;
}
.options-container .form-select {
width: 100%;
height: 32px;
padding: 0 8px;
border: 1px solid #d0d0d0;
border-radius: 6px;
background: #fff;
font-size: 13px;
color: #333;
outline: none;
box-sizing: border-box;
transition: border-color 0.15s;
cursor: pointer;
}
.options-container .form-select:focus {
border-color: #4a7a00;
box-shadow: 0 0 0 2px rgba(74, 122, 0, 0.15);
}
.options-container .form-input {
width: 100%;
height: 32px;
padding: 0 8px;
border: 1px solid #d0d0d0;
border-radius: 6px;
background: #fff;
font-size: 13px;
color: #333;
outline: none;
box-sizing: border-box;
transition: border-color 0.15s;
}
.options-container .form-input:focus {
border-color: #4a7a00;
box-shadow: 0 0 0 2px rgba(74, 122, 0, 0.15);
}
.options-container .image-upload-label {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 64px;
border: 2px dashed #d0d0d0;
border-radius: 6px;
background: #fafafa;
cursor: pointer;
transition: border-color 0.15s, background 0.15s;
box-sizing: border-box;
font-size: 12px;
color: #999;
}
.options-container .image-upload-label:hover {
border-color: #4a7a00;
background: #f0f7e6;
color: #4a7a00;
}
.options-container .image-upload-label.locked {
cursor: not-allowed;
opacity: 0.6;
pointer-events: none;
}
.options-container .image-preview-wrap {
position: relative;
display: inline-block;
margin-top: 6px;
width: 100%;
}
.options-container .image-preview {
display: block;
width: 64px;
height: 64px;
object-fit: contain;
border: 1px solid #e8e8e8;
border-radius: 6px;
background: #f5f5f5;
}
.options-container .image-clear-btn {
position: absolute;
top: -6px;
left: 52px;
width: 18px;
height: 18px;
border-radius: 50%;
border: none;
background: #e74c3c;
color: #fff;
font-size: 13px;
line-height: 18px;
text-align: center;
cursor: pointer;
padding: 0;
}
.options-container .image-clear-btn:hover {
background: #c0392b;
}
.options-container .image-locked-notice {
font-size: 11px;
color: #888;
margin-top: 4px;
font-style: italic;
}
.options-container .panel-actions {
margin-top: 14px;
display: flex;
gap: 8px;
}
.options-container .btn {
height: 34px;
padding: 0 16px;
border: none;
border-radius: 6px;
font-size: 13px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s;
white-space: nowrap;
}
.options-container .btn-primary {
background: #4a7a00;
color: #fff;
flex: 1;
}
.options-container .btn-primary:hover {
background: #3d6b00;
}
.options-container .btn-secondary {
background: #f0f0f0;
color: #333;
border: 1px solid #d0d0d0;
flex: 1;
}
.options-container .btn-secondary:hover {
background: #e5e5e5;
}
.options-container .panel-info {
font-size: 12px;
color: #666;
line-height: 1.5;
}
.options-container .panel-info p {
margin: 0 0 8px 0;
}
.options-container .panel-info p:last-child {
margin-bottom: 0;
}
.options-container .panel-info code {
background: #f0f0f0;
padding: 1px 4px;
border-radius: 3px;
font-size: 11px;
color: #c7254e;
}