LISTINGS
Property Listing Catalog
var SPEC={"slug":"listing-catalog","title":"Property Listing Catalog","kicker":"LISTINGS","accent":"#6b8cae","tagline":"Property listings with details, status, and notes.","description":"A browser-local listing catalog that stores property aliases, listing details, and status notes only. It holds no property addresses, financial data, or ownership records and is not a real estate platform, MLS system, or property management tool.","category":"business","color":"blue","height":510,"fields":[{"key":"title","label":"Listing alias","type":"text","required":true,"max":60,"placeholder":"Downtown apartment","span":"half"},{"key":"type","label":"Type","type":"select","options":["Apartment","House","Condo","Commercial","Land","Other"],"default":"Apartment","span":"half"},{"key":"bedrooms","label":"Bedrooms","type":"number","min":0,"max":20,"step":1,"placeholder":"2","span":"third"},{"key":"bathrooms","label":"Bathrooms","type":"number","min":0,"max":20,"step":0.5,"placeholder":"1","span":"third"},{"key":"listedPrice","label":"Listed price (USD)","type":"number","min":0,"max":10000000,"step":1000,"placeholder":"0","span":"third"},{"key":"note","label":"Notes","type":"text","max":150,"placeholder":"Listing notes, no addresses or financial data","span":"wide"}],"titleField":"title","cardFields":[{"key":"type","label":"Type"},{"key":"bedrooms","label":"Beds","kind":"number"},{"key":"bathrooms","label":"Baths","kind":"number"},{"key":"listedPrice","label":"Price","kind":"money"}],"status":{"field":"status","values":["Active","Pending","Sold","Withdrawn","Archived"],"default":"Active","colors":{"Active":"success","Pending":"warning","Sold":"success","Withdrawn":"neutral","Archived":"neutral"}},"sortPriority":{"field":"status","order":["Active","Pending","Sold","Withdrawn","Archived"]},"dateField":{"key":"listedDate","label":"Listed date","future":"in","past":"ago"},"metrics":[{"kind":"total"},{"kind":"sumField","field":"listedPrice","format":"money","label":"Total listed"},{"kind":"statusCount","status":"Active","label":"Active"},{"kind":"statusCount","status":"Sold","label":"Sold"}],"checks":[],"search":true,"empty":"No listings logged yet. Add a listing above to start your catalog.","footnote":"Manual log only. Not a real estate platform, MLS system, or property management tool.","submit":"Add listing","searchPlaceholder":"Filter listings or types"}; (function(){ var cfgEl=document.getElementById('bk-config'),base={};try{base=cfgEl?JSON.parse(cfgEl.textContent||'{}'):{};}catch(e){} var q=new URLSearchParams(location.search),c={};for(var k in base)c[k]=base[k];q.forEach(function(v,k){c[k]=v;}); function safeColor(v,d){return /^#[0-9a-f]{6}$/i.test(String(v||''))?String(v):d;} var theme=['auto','light','dark'].indexOf(String(c.theme||'auto'))>=0?String(c.theme||'auto'):'auto',ACCENT=safeColor(c.accent,SPEC.accent),LABEL=String(c.label||SPEC.title).slice(0,48),KEY="notion-arena.listing-catalog.v1",LIMIT=120; document.documentElement.setAttribute('data-theme',theme);document.documentElement.style.setProperty('--accent',ACCENT);document.getElementById('title').textContent=LABEL;document.title=LABEL; function rgb(h){var s=h.slice(1);return[0,2,4].map(function(i){return parseInt(s.slice(i,i+2),16);});}function lum(a){return a.map(function(v){v/=255;return v<=.04045?v/12.92:Math.pow((v+.055)/1.055,2.4);}).reduce(function(sum,v,i){return sum+v*[.2126,.7152,.0722][i];},0);}function ratio(a,b){var x=lum(a),y=lum(b);return(Math.max(x,y)+.05)/(Math.min(x,y)+.05);}function hex(a){return'#'+a.map(function(v){return Math.max(0,Math.min(255,v)).toString(16).padStart(2,'0');}).join('');}function mix(a,b,t){return a.map(function(v,i){return Math.round(v+(b[i]-v)*t);});}function setAccent(){var dark=theme==='dark'||(theme==='auto'&&window.matchMedia&&window.matchMedia('(prefers-color-scheme: dark)').matches),bg=rgb(dark?'#222220':'#ffffff'),a=rgb(ACCENT),soft=mix(bg,a,.12),target=dark?[255,255,255]:[0,0,0],text=a;for(var t=.02;t<=1;t+=.02){if(ratio(text,soft)>=4.5)break;text=mix(a,target,t);}var black=[0,0,0],white=[255,255,255],ink=ratio(a,black)>=ratio(a,white)?black:white;document.documentElement.style.setProperty('--accent-text',hex(text));document.documentElement.style.setProperty('--accent-ink',hex(ink));document.documentElement.style.setProperty('--soft',hex(soft));document.documentElement.style.colorScheme=dark?'dark':'light';}setAccent();if(theme==='auto'&&window.matchMedia){var mq=window.matchMedia('(prefers-color-scheme: dark)');if(mq.addEventListener)mq.addEventListener('change',setAccent);else if(mq.addListener)mq.addListener(setAccent);} var items=[];try{var raw=JSON.parse(localStorage.getItem(KEY)||'[]');if(Array.isArray(raw))items=raw.filter(function(x){return x&&typeof x.id==='string';}).slice(0,LIMIT);}catch(e){} function el(tag,cls,text){var n=document.createElement(tag);if(cls)n.className=cls;if(text!==undefined&&text!==null)n.textContent=String(text);return n;}function clean(s,max){return String(s||'').trim().slice(0,max);}function uid(){return Date.now().toString(36)+Math.random().toString(36).slice(2,8);}function localToday(){var d=new Date();return d.getFullYear()+'-'+String(d.getMonth()+1).padStart(2,'0')+'-'+String(d.getDate()).padStart(2,'0');}function dateDiff(s){if(!/^\d{4}-\d{2}-\d{2}$/.test(String(s||'')))return null;var a=new Date(s+'T00:00:00'),b=new Date(localToday()+'T00:00:00');if(Number.isNaN(a.getTime()))return null;return Math.round((a-b)/86400000);}function prettyDate(s){if(!/^\d{4}-\d{2}-\d{2}$/.test(String(s||'')))return String(s||'');var d=new Date(s+'T12:00:00');return Number.isNaN(d.getTime())?s:d.toLocaleDateString(undefined,{month:'short',day:'numeric'});}function announce(s){document.getElementById('status').textContent=s;}function save(s){try{localStorage.setItem(KEY,JSON.stringify(items));announce(s||'Saved only in this browser.');}catch(e){announce('Browser storage is unavailable. Changes may not persist.');}} function buildForm(){var form=document.getElementById('form');SPEC.fields.forEach(function(f){var box=el('div','field '+(f.span||'half'));var id='f-'+f.key,lab=el('label','',f.label);lab.htmlFor=id;box.appendChild(lab);var input;if(f.type==='select'){input=el('select','input');(f.options||[]).forEach(function(v){var o=el('option','',v);o.value=v;input.appendChild(o);});}else if(f.type==='textarea'){input=el('textarea','input');input.rows=2;}else{input=el('input','input');input.type=f.type||'text';if(f.min!==undefined)input.min=String(f.min);if(f.max!==undefined){if(f.type==='number')input.max=String(f.max);else input.maxLength=f.max;}if(f.step!==undefined)input.step=String(f.step);}input.id=id;if(f.required)input.required=true;if(f.placeholder)input.placeholder=f.placeholder;if(f.type==='number')input.inputMode='decimal';box.appendChild(input);form.appendChild(box);});var btn=el('button','btn primary submit',SPEC.submit||'Add item');btn.type='submit';form.appendChild(btn);} buildForm(); function statusOptions(){return SPEC.status?SPEC.status.options:[];}function isDone(item){return !!(SPEC.status&&SPEC.status.done.indexOf(item.status)>=0);}function wanted(m){return m.values?m.values:(m.value!==undefined?[m.value]:[]);}function inWanted(m,v){var w=wanted(m);return !w.length||w.indexOf(v)>=0;}function num(v){return Number(v)||0;}function sumOf(rows,key){return rows.reduce(function(a,x){return a+num(x[key]);},0);} function countKind(m){if(m.kind==='total')return items.length; if(m.kind==='open')return items.filter(function(x){return!isDone(x);}).length; if(m.kind==='countStatus')return items.filter(function(x){return inWanted(m,x.status);}).length; if(m.kind==='countField')return items.filter(function(x){return(!m.excludeDone||!isDone(x))&&inWanted(m,x[m.key]);}).length; if(m.kind==='dueSoon'){var w=m.days===undefined?7:m.days;return items.filter(function(x){var n=dateDiff(x[m.key]);return!isDone(x)&&n!==null&&n>=0&&n<=w;}).length;} if(m.kind==='overdue')return items.filter(function(x){var n=dateDiff(x[m.key]);return!isDone(x)&&n!==null&&n<0;}).length; if(m.kind==='recent'){var r=m.days===undefined?7:m.days;return items.filter(function(x){var n=dateDiff(x[m.key]);return n!==null&&n<=0&&n>=-r;}).length;} if(m.kind==='sum')return sumOf(items,m.key); if(m.kind==='sumStatus')return sumOf(items.filter(function(x){return inWanted(m,x.status);}),m.key); if(m.kind==='sumField')return sumOf(items.filter(function(x){return(!m.excludeDone||!isDone(x))&&inWanted(m,x[m.by]);}),m.key); if(m.kind==='checkRate'){var all=0,done=0;items.forEach(function(x){(x.checks||[]).forEach(function(ch){all++;if(ch.done)done++;});});return all?Math.round(done/all*100):0;} if(m.kind==='rate'){var rows=items.filter(function(x){return!m.excludeDone||!isDone(x);});if(!rows.length)return 0;var hit=rows.filter(function(x){return inWanted(m,m.by?x[m.by]:x.status);}).length;return Math.round(hit/rows.length*100);} if(m.kind==='ratio'){var parts=m.parts||[m.key],top=0,total=0;items.forEach(function(x){parts.forEach(function(k,i){var v=num(x[k]);total+=v;if(!i)top+=v;});});return total?Math.round(top/total*100):0;} return 0;} function metricText(m){var n=countKind(m);if(m.format==='money')return'$'+Math.round(n).toLocaleString('en-US');if(m.format==='hours'||m.format==='days')return Number(n).toFixed(1);if(m.format==='percent')return String(n)+'%';if(m.format==='duration'){var s=Math.max(0,Math.round(n));return Math.floor(s/60)+':'+String(s%60).padStart(2,'0');}if(m.kind==='sum'&&m.key==='estimate')return'$'+Math.round(n).toLocaleString('en-US');return String(n);} function drawMetrics(){var root=document.getElementById('metrics');root.textContent='';SPEC.metrics.forEach(function(m){var box=el('div','metric');box.appendChild(el('span','metric-value',metricText(m)));box.appendChild(el('span','metric-label',m.label));root.appendChild(box);});} function makeChip(text,kind){return el('span','chip'+(kind?' '+kind:''),text);}function formatCardField(f,item){var raw=item[f.key];if(raw===undefined||raw===null||raw==='')return null;if(f.kind==='detail')return el('p','detail',String(raw));var value=String(raw);if(f.kind==='date')value=prettyDate(value);if(f.kind==='money')value='$'+num(raw).toLocaleString('en-US',{maximumFractionDigits:0})+' USD est.';if(f.kind==='number')value=f.label+': '+raw;else if(f.label&&f.kind!=='priority')value=f.label+': '+value;return makeChip(value,f.kind==='priority'?'priority':'');} function sortRows(rows){var a=rows.slice();if(SPEC.sortPriority){var p=SPEC.sortPriority.values; a.sort(function(x,y){var ax=p.indexOf(x[SPEC.sortPriority.key]),ay=p.indexOf(y[SPEC.sortPriority.key]);if(ax<0)ax=99;if(ay<0)ay=99;return ax-ay;});}if(SPEC.dateField){a.sort(function(x,y){var ax=x[SPEC.dateField]||'9999-99-99',ay=y[SPEC.dateField]||'9999-99-99';if(SPEC.sortPriority){var p=SPEC.sortPriority.values,px=p.indexOf(x[SPEC.sortPriority.key]),py=p.indexOf(y[SPEC.sortPriority.key]);if(px<0)px=99;if(py<0)py=99;if(px!==py)return px-py;}return ax.localeCompare(ay);});}return a;} function render(){drawMetrics();var root=document.getElementById('list');root.textContent='';var term=document.getElementById('search').value.trim().toLowerCase(),rows=items.filter(function(x){var hay=Object.keys(x).map(function(k){return typeof x[k]==='string'?x[k]:'';}).join(' ').toLowerCase();return!term||hay.indexOf(term)>=0;});rows=sortRows(rows);document.getElementById('count').textContent=rows.length+' shown';if(!rows.length){root.appendChild(el('div','empty',items.length?'No entries match the filter.':SPEC.empty));return;}rows.forEach(function(item){var row=el('article','entry'),main=el('div','entry-main');main.appendChild(el('div','entry-title',item[SPEC.titleField]||'Untitled'));var meta=el('div','chips');(SPEC.cardFields||[]).forEach(function(f){var n=formatCardField(f,item);if(n){if(f.kind==='detail')main.appendChild(n);else meta.appendChild(n);}});if(meta.childNodes.length)main.appendChild(meta);row.appendChild(main);var actions=el('div','actions');if(SPEC.status){var select=el('select','status');statusOptions().forEach(function(v){var o=el('option','',v);o.value=v;select.appendChild(o);});select.value=item.status||SPEC.status.default;select.setAttribute('data-status',item.id);select.setAttribute('aria-label',SPEC.status.label+' for '+(item[SPEC.titleField]||'entry'));actions.appendChild(select);}var del=el('button','remove','Remove');del.type='button';del.setAttribute('data-remove',item.id);del.setAttribute('aria-label','Remove '+(item[SPEC.titleField]||'entry'));actions.appendChild(del);row.appendChild(actions);if(SPEC.checks){var checks=el('div','checklist');(item.checks||[]).forEach(function(ch,i){var lab=el('label','check-row');var input=el('input','check');input.type='checkbox';input.checked=!!ch.done;input.setAttribute('data-check',item.id);input.setAttribute('data-index',String(i));input.id='check-'+item.id+'-'+i;lab.htmlFor=input.id;lab.appendChild(input);lab.appendChild(el('span','',ch.label));checks.appendChild(lab);});var progress=el('div','progress-row');var done=(item.checks||[]).filter(function(ch){return ch.done;}).length;progress.appendChild(el('span','small',done+' of '+(item.checks||[]).length+' checks'));var bar=el('div','bar'),fill=el('span');fill.style.width=(item.checks&&item.checks.length?Math.round(done/item.checks.length*100):0)+'%';bar.appendChild(fill);progress.appendChild(bar);checks.appendChild(progress);row.appendChild(checks);}root.appendChild(row);});} document.getElementById('form').addEventListener('submit',function(e){e.preventDefault();if(items.length>=LIMIT){announce('This local list is full. Remove an entry to add another.');return;}var item={id:uid(),status:SPEC.defaultStatus||statusOptions()[0]||''};SPEC.fields.forEach(function(f){var input=document.getElementById('f-'+f.key),v=input.value;if(f.type==='number'&&v!==''){var n=Number(v);v=Number.isFinite(n)?String(Math.min(f.max===undefined?1e9:f.max,Math.max(f.min||0,n))):'';}item[f.key]=f.type==='date'?String(v||''):clean(v,f.max||160);});if(SPEC.checks)item.checks=SPEC.checks.map(function(label){return{label:label,done:false};});items.unshift(item);try{localStorage.setItem(KEY,JSON.stringify(items));announce('Saved only in this browser.');}catch(err){announce('Browser storage is unavailable. Changes may not persist.');}this.reset();render();document.getElementById('f-'+SPEC.titleField).focus();}); document.getElementById('search').addEventListener('input',render);document.getElementById('list').addEventListener('click',function(e){var n=e.target;while(n&&n!==this){var id=n.getAttribute&&n.getAttribute('data-remove');if(id){items=items.filter(function(x){return x.id!==id;});save('Entry removed.');render();return;}n=n.parentNode;}});document.getElementById('list').addEventListener('change',function(e){var id=e.target.getAttribute('data-status');if(id){var item=items.find(function(x){return x.id===id;});if(item){item.status=e.target.value;save('State updated.');render();}return;}var checkId=e.target.getAttribute('data-check');if(checkId){var row=items.find(function(x){return x.id===checkId;});var index=Number(e.target.getAttribute('data-index'));if(row&&row.checks&&row.checks[index]){row.checks[index].done=e.target.checked;save('Checklist updated.');render();}}});document.getElementById('clear').addEventListener('click',function(){document.getElementById('search').value='';render();});render(); })();