{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"inventory-tracker","type":"registry:component","title":"Inventory Counter","description":"Adjust a small item list with plus and minus stock controls.","author":"Notion Arena","categories":["business"],"tags":["widget","free","inventory","stock","supplies","operations","counter"],"meta":{"kind":"widget","tier":"free","version":"1.0.0","updatedAt":"2026-10-11","notionPlan":"Free","emoji":"📦","delivery":["embed","html-block","download"],"capabilities":{"interactive":true,"offlineSafe":true,"persistsLocally":true,"writesToNotion":false,"needsNetwork":false},"embedUrl":"https://notionarena.vercel.app/embed/inventory-tracker","fileUrl":"https://notionarena.vercel.app/widgets/inventory-tracker.html","downloadUrl":"https://notionarena.vercel.app/api/widget/inventory-tracker","height":320,"minHeight":220,"maxHeight":500,"params":[{"key":"label","label":"List name","type":"text","default":"Inventory"},{"key":"items","label":"Starting items","type":"text","default":"Notebook::3||Pens::12||Folders::2","help":"Name::quantity||Name 2::quantity. Up to 40 items."},{"key":"accent","label":"Accent","type":"color","default":"#d9730d"},{"key":"theme","label":"Theme","type":"select","default":"auto","options":[{"value":"auto","label":"Match Notion"},{"value":"light","label":"Light"},{"value":"dark","label":"Dark"}]}]},"files":[{"path":"widgets/inventory-tracker.html","type":"registry:file","target":"notion/widgets/inventory-tracker.html","content":"<!doctype html>\n<html lang=\"en\" data-theme=\"auto\">\n<head>\n<meta charset=\"utf-8\" /><meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" />\n<title>Inventory Counter</title>\n<style>\n:root{--bg:#fff;--fg:#37352f;--muted:#787774;--surface:#f7f7f5;--border:#e9e9e7;--accent:#d9730d;--font:ui-sans-serif,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif}\nhtml[data-theme=\"dark\"]{--bg:#191919;--fg:#e6e6e4;--muted:#9b9a97;--surface:#252525;--border:#343434}\n@media(prefers-color-scheme:dark){html[data-theme=\"auto\"]{--bg:#191919;--fg:#e6e6e4;--muted:#9b9a97;--surface:#252525;--border:#343434}}\n*{box-sizing:border-box}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}html,body{margin:0;height:100%}body{background:var(--bg);color:var(--fg);font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,\"Segoe UI\",Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;overflow:hidden}\n.wrap{height:100%;min-height:220px;display:flex;flex-direction:column;gap:9px;padding:13px;overflow:auto}.head{display:flex;align-items:center;justify-content:space-between;gap:8px}.kicker{font-size:9px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted);font-weight:650}.title{font-size:13.5px;font-weight:650;margin-top:2px}.total{font-size:10px;color:var(--muted);font-variant-numeric:tabular-nums}\n.list{display:flex;min-height:52px;flex:1;flex-direction:column;gap:4px;overflow:auto}.row{display:flex;align-items:center;gap:6px;min-height:31px;padding:4px 6px;border:1px solid var(--border);border-radius:7px;background:var(--surface)}.name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:550}.qty{min-width:35px;text-align:center;font-size:11px;font-weight:650;font-variant-numeric:tabular-nums}.item-btn,.remove{display:grid;place-items:center;width:25px;height:24px;border:1px solid var(--border);border-radius:6px;background:var(--bg);color:var(--fg);font:inherit;font-size:13px;cursor:pointer}.item-btn:hover,.remove:hover{border-color:var(--accent)}.remove{font-size:10px;color:var(--muted)}\n.add{display:flex;gap:5px}.add input{min-width:0;flex:1;height:30px;border:1px solid var(--border);border-radius:7px;background:var(--surface);color:var(--fg);padding:5px 7px;font:inherit;font-size:10.5px}.add input:focus-visible,.add button:focus-visible,.item-btn:focus-visible,.remove:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.add button,.restore{min-height:30px;border:1px solid var(--border);border-radius:7px;background:var(--surface);color:var(--fg);font:inherit;font-size:10.5px;padding:5px 8px;cursor:pointer}.add button:hover,.restore:hover{border-color:var(--accent)}.foot{display:flex;align-items:center;justify-content:space-between;gap:8px;font-size:9px;color:var(--muted)}\n@media(max-width:330px){.wrap{padding:10px}.row{gap:4px;padding:4px}.item-btn,.remove{width:23px}}\n@media(prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}\n</style>\n</head>\n<body><main class=\"wrap\">\n  <header class=\"head\"><div><div class=\"kicker\">Local stock count</div><div class=\"title\" id=\"title\">Inventory</div></div><div class=\"total\" id=\"total\">0 items</div></header>\n  <section class=\"list\" id=\"list\" aria-label=\"Inventory items\"></section>\n  <form class=\"add\" id=\"addForm\"><label class=\"sr-only\" for=\"newItem\">New item name</label><input id=\"newItem\" maxlength=\"50\" placeholder=\"Add an item\" /><button type=\"submit\">Add</button></form>\n  <div class=\"foot\"><span id=\"status\" aria-live=\"polite\">Counts save only in this browser.</span><button class=\"restore\" id=\"restore\" type=\"button\">Restore defaults</button></div>\n</main>\n<script>\n(function(){\n  var cfgEl=document.getElementById('bk-config'),base={};try{base=cfgEl?JSON.parse(cfgEl.textContent||'{}'):{};}catch(e){}\n  var q=new URLSearchParams(location.search),c={};for(var k in base)c[k]=base[k];q.forEach(function(v,k){c[k]=v;});\n  function safeColor(v,d){return /^#[0-9a-f]{6}$/i.test(String(v||''))?String(v):d;}\n  function parseItems(raw){var out=[];String(raw||'').split('||').slice(0,40).forEach(function(row){var cut=row.indexOf('::');if(cut<0)return;var name=row.slice(0,cut).trim(),qty=parseInt(row.slice(cut+2),10);if(name)out.push({name:name.slice(0,50),qty:Math.max(0,Math.min(99999,isFinite(qty)?qty:0))});});return out;}\n  var theme=['auto','light','dark'].indexOf(String(c.theme||'auto'))>-1?String(c.theme||'auto'):'auto',ACCENT=safeColor(c.accent,'#d9730d'),LABEL=String(c.label||'Inventory').slice(0,48),defaults=parseItems(c.items||'Notebook::3||Pens::12||Folders::2');\n  if(!defaults.length)defaults=parseItems('Notebook::3||Pens::12||Folders::2');\n  document.documentElement.setAttribute('data-theme',theme);document.documentElement.style.setProperty('--accent',ACCENT);document.getElementById('title').textContent=LABEL;document.title=LABEL;\n  function hash(s){var h=5381;for(var i=0;i<s.length;i++)h=((h<<5)-h+s.charCodeAt(i))|0;return 'i'+(h>>>0).toString(36);}\n  var id=hash(LABEL+'|'+JSON.stringify(defaults)),KEY='notion-arena.inventory.v1',store={lists:{}},items=defaults.map(function(x){return{name:x.name,qty:x.qty};});\n  try{var saved=JSON.parse(localStorage.getItem(KEY)||'{}');if(saved&&saved.lists)store=saved;if(store.lists&&Array.isArray(store.lists[id]))items=store.lists[id].filter(function(x){return x&&typeof x.name==='string';}).map(function(x){return{name:String(x.name).slice(0,50),qty:Math.max(0,Math.min(99999,parseInt(x.qty,10)||0))};});}catch(e){}\n  function save(){if(!store.lists)store.lists={};store.lists[id]=items;var ids=Object.keys(store.lists);while(ids.length>8){var old=ids.shift();if(old===id){ids.push(old);continue;}delete store.lists[old];}try{localStorage.setItem(KEY,JSON.stringify(store));}catch(e){}}\n  function render(){var list=document.getElementById('list');while(list.firstChild)list.removeChild(list.firstChild);var total=0;items.forEach(function(item,index){total+=item.qty;var row=document.createElement('div'),name=document.createElement('span'),minus=document.createElement('button'),qty=document.createElement('span'),plus=document.createElement('button'),remove=document.createElement('button');row.className='row';name.className='name';name.textContent=item.name;minus.className='item-btn';minus.type='button';minus.textContent='−';minus.setAttribute('aria-label','Remove one '+item.name);qty.className='qty';qty.textContent=String(item.qty);plus.className='item-btn';plus.type='button';plus.textContent='+';plus.setAttribute('aria-label','Add one '+item.name);remove.className='remove';remove.type='button';remove.textContent='×';remove.setAttribute('aria-label','Remove '+item.name+' from list');minus.addEventListener('click',function(){item.qty=Math.max(0,item.qty-1);save();render();});plus.addEventListener('click',function(){item.qty=Math.min(99999,item.qty+1);save();render();});remove.addEventListener('click',function(){items.splice(index,1);save();render();});row.appendChild(name);row.appendChild(minus);row.appendChild(qty);row.appendChild(plus);row.appendChild(remove);list.appendChild(row);});document.getElementById('total').textContent=items.length+' '+(items.length===1?'item':'items')+' · '+total+' total';document.getElementById('status').textContent='Counts save only in this browser.';}\n  document.getElementById('addForm').addEventListener('submit',function(e){e.preventDefault();var input=document.getElementById('newItem'),name=input.value.trim();if(!name)return;var existing=items.find(function(x){return x.name.toLowerCase()===name.toLowerCase();});if(existing)existing.qty=Math.min(99999,existing.qty+1);else if(items.length<40)items.push({name:name.slice(0,50),qty:1});else{document.getElementById('status').textContent='List limit reached.';return;}input.value='';save();render();});\n  document.getElementById('restore').addEventListener('click',function(){items=defaults.map(function(x){return{name:x.name,qty:x.qty};});save();render();});\n  render();save();\n})();\n</script>\n</body>\n</html>\n"}]}