Attachment viewer widget needed

Sure. Just create a Custom Widget Builder, and put the following in the HTML and the Javascript pages.

<!DOCTYPE html>
<meta charset="utf-8" />
<script src="https://docs.getgrist.com/grist-plugin-api.js"></script>
<style>
  :root { color-scheme: light dark; }
  html, body { height: 100%; margin: 0; }
  body {
    font-family: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, "Helvetica Neue", Arial, sans-serif;
    display: grid; place-items: center;
    background: canvas; color: canvastext;
  }
  #wrap { position: relative; width: 100%; height: 100%; }
  #img {
    max-width: 100%;
    max-height: 100%;
    object-fit: cover;
    object-position: center;
    display: none;
  }
</style>

<div id="wrap">
  <img id="img" alt="" />
  <div id="msg">Select a row and map an attachment column in the widget settings…</div>
</div>

// Request mapping for one Attachments-type column.
grist.ready({
  requiredAccess: 'read table',
  columns: [{
    name: 'Attachment',           // logical name used inside the widget
    title: 'Attachment column',   // label shown in the mapping UI
    type: 'Attachments',
    optional: false
  }]
});

const img = document.getElementById('img');
const msg = document.getElementById('msg');

async function buildAttachmentUrl(attId) {
  // Short-lived, safe URL parts for the current document
  const { token, baseUrl } = await grist.docApi.getAccessToken({ readOnly: true });
  return `${baseUrl}/attachments/${attId}/download?auth=${token}`;
}

function showMessage(text) {
  img.removeAttribute('src');
  img.style.display = 'none';
  msg.textContent = text;
}

async function render(record) {
  const mapped = grist.mapColumnNames(record) || {};
  const list = mapped.Attachment;

  // Attachment cells are arrays of IDs; show the first if present.
  const attId = Array.isArray(list) && list.length ? list[0] : null;

  if (!attId) {
    showMessage('X'); //whatever you want to show if nothing
    return;
  }

  try {
    const url = await buildAttachmentUrl(attId);
    img.src = url;
    img.alt = `Attachment ${attId}`;
    img.style.display = 'block';
    msg.textContent = '';
  } catch (err) {
    console.error('Attachment load error:', err);
    showMessage('Unable to load image (check access or file type).');
  } finally {
    // Nudge height after image settles
    queueMicrotask(() => grist.setHeight(document.body.scrollHeight));
  }
}

// Update when the selected record changes.
grist.onRecord(render);

// Keep height sensible on resizes and image events.
window.addEventListener('resize', () => grist.setHeight(document.body.scrollHeight));
img.addEventListener('load',  () => grist.setHeight(document.body.scrollHeight));
img.addEventListener('error', () => grist.setHeight(document.body.scrollHeight));

Once you have this all you need to do is specify the attachment field.

1 Like