User:Docmoates/common.js: Difference between revisions

From XMethod Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
/* SocialFeed v5 - Clean professional design */
/* SocialFeed v6 - Clean Modern Design */
if (mw.config.get("wgPageName").indexOf("User:Docmoates/Social") !== -1) {
if (mw.config.get("wgPageName").indexOf("User:Docmoates/Social") !== -1) {
mw.loader.using(["mediawiki.api", "mediawiki.util"]).then(function() {
mw.loader.using(["mediawiki.api", "mediawiki.util"]).then(function() {
var $=jQuery,api=new mw.Api(),apiUrl=mw.util.wikiScript("api"),user=mw.config.get("wgUserName")||"Guest";
var $=jQuery,api=new mw.Api(),apiUrl=mw.util.wikiScript("api"),user=mw.config.get("wgUserName")||"Guest";
var ud={photo:localStorage.getItem("sf_photo_"+user)||"",bio:localStorage.getItem("sf_bio_"+user)||"",name:localStorage.getItem("sf_name_"+user)||user};
var ud={photo:localStorage.getItem("sf_photo_"+user)||"",bio:localStorage.getItem("sf_bio_"+user)||""};
var pp={image:"",video:"",location:""},uf={};
var pp={image:"",location:""},uf={};


function gi(n){return(n||"?").split(/[\s_]+/).map(function(w){return(w[0]||"").toUpperCase();}).join("").substring(0,2)||"?";}
function gi(n){return(n||"?").charAt(0).toUpperCase();}
function esc(t){var d=document.createElement("div");d.textContent=t;return d.innerHTML;}
function esc(t){var d=document.createElement("div");d.textContent=t;return d.innerHTML;}
function ago(ds){var s=Math.floor((Date.now()-new Date(ds))/1000);if(s<60)return"Just now";var m=Math.floor(s/60);if(m<60)return m+" min ago";var h=Math.floor(m/60);if(h<24)return h+"h ago";return Math.floor(h/24)+"d ago";}
function ago(ds){var s=Math.floor((Date.now()-new Date(ds))/1000);if(s<60)return"now";var m=Math.floor(s/60);if(m<60)return m+"m";var h=Math.floor(m/60);if(h<24)return h+"h";return Math.floor(h/24)+"d";}
function av(pic,name,sz){if(pic)return'<img src="'+esc(pic)+'">';return'<div class="sf-av-ph" style="font-size:'+(sz||14)+'px">'+gi(name)+'</div>';}
function av(p,n,s){return p?'<img src="'+esc(p)+'" style="width:100%;height:100%;object-fit:cover">':'<div style="width:100%;height:100%;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:600;font-size:'+s+'px">'+gi(n)+'</div>';}
function om(id){$("#"+id).addClass("open");}
function om(id){$("#"+id).addClass("open");}
function cm(id){$("#"+id).removeClass("open");}
function cm(id){$("#"+id).removeClass("open");}
function upload(file,pre,prog){return api.getToken("csrf").then(function(tk){var ext=file.name.split(".").pop()||"jpg",fn=pre+"_"+user+"_"+Date.now()+"."+ext,fd=new FormData();fd.append("action","upload");fd.append("filename",fn);fd.append("file",file);fd.append("token",tk);fd.append("format","json");fd.append("ignorewarnings","1");return $.ajax({url:apiUrl,type:"POST",data:fd,processData:false,contentType:false,xhr:function(){var x=$.ajaxSettings.xhr();if(x.upload&&prog)x.upload.addEventListener("progress",function(e){if(e.lengthComputable)prog(Math.round(e.loaded/e.total*100));});return x;}});}).then(function(r){if(r.upload&&r.upload.imageinfo)return r.upload.imageinfo.url;throw new Error(r.error?r.error.info:"Upload failed");});}
function upload(file,pre,prog){return api.getToken("csrf").then(function(tk){var fd=new FormData();fd.append("action","upload");fd.append("filename",pre+"_"+user+"_"+Date.now()+"."+file.name.split(".").pop());fd.append("file",file);fd.append("token",tk);fd.append("format","json");fd.append("ignorewarnings","1");return $.ajax({url:apiUrl,type:"POST",data:fd,processData:false,contentType:false,xhr:function(){var x=$.ajaxSettings.xhr();if(x.upload&&prog)x.upload.addEventListener("progress",function(e){if(e.lengthComputable)prog(Math.round(e.loaded/e.total*100));});return x;}});}).then(function(r){if(r.upload&&r.upload.imageinfo)return r.upload.imageinfo.url;throw new Error("Upload failed");});}


// Hide Design Page button
setTimeout(function(){$('button,a').filter(function(){return $(this).text().indexOf('Design')!==-1;}).hide();},200);
setTimeout(function(){$('button,a').filter(function(){return $(this).text().indexOf('Design')!==-1;}).hide();},100);
setTimeout(function(){$('button,a').filter(function(){return $(this).text().indexOf('Design')!==-1;}).hide();},500);


var css='\
var css=`
[class*="wikibox"]{display:none!important}\
[class*="wikibox"]{display:none!important}
#social-app{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#f5f5f5;min-height:100vh;padding:20px}\
#social-app{font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#f8fafc;min-height:100vh;padding:24px}
#social-app *{box-sizing:border-box;margin:0;padding:0}\
#social-app *{box-sizing:border-box;margin:0;padding:0}
.sf-layout{display:flex;gap:24px;max-width:1100px;margin:0 auto}\
.sf-wrap{max-width:680px;margin:0 auto}
.sf-main{flex:1;min-width:0}\
.sf-card{background:#fff;border-radius:16px;box-shadow:0 1px 3px rgba(0,0,0,0.06),0 1px 2px rgba(0,0,0,0.04);margin-bottom:16px;overflow:hidden}
.sf-sidebar{width:280px;flex-shrink:0}\
.sf-compose{padding:20px}
.sf-card{background:#fff;border-radius:16px;box-shadow:0 1px 3px rgba(0,0,0,0.08);margin-bottom:20px;overflow:hidden}\
.sf-compose-row{display:flex;gap:14px;align-items:flex-start}
.sf-profile-card .sf-card-header{background:linear-gradient(135deg,#10b981,#059669);color:#fff;padding:16px 20px;font-weight:600;font-size:15px}\
.sf-avatar{width:44px;height:44px;border-radius:50%;overflow:hidden;flex-shrink:0}
.sf-profile-card .sf-card-body{padding:0}\
.sf-input-wrap{flex:1}
.sf-profile-row{display:flex;padding:14px 20px;border-bottom:1px solid #f0f0f0;font-size:14px}\
.sf-input{width:100%;border:none;font-size:15px;color:#1e293b;resize:none;outline:none;min-height:60px;font-family:inherit;line-height:1.5}
.sf-profile-row:last-child{border-bottom:none}\
.sf-input::placeholder{color:#94a3b8}
.sf-profile-label{width:110px;color:#666;font-weight:500}\
.sf-preview{margin-top:12px;position:relative;display:none}
.sf-profile-value{flex:1;color:#333}\
.sf-preview.show{display:block}
.sf-profile-value a{color:#0095f6;text-decoration:none}\
.sf-preview img{max-width:100%;border-radius:12px}
.sf-compose{padding:20px}\
.sf-preview-x{position:absolute;top:8px;right:8px;width:28px;height:28px;border-radius:50%;background:rgba(0,0,0,0.6);color:#fff;border:none;cursor:pointer;font-size:16px}
.sf-compose-toolbar{display:flex;align-items:center;gap:12px;padding-bottom:16px;border-bottom:1px solid #eee;margin-bottom:16px}\
.sf-loc{margin-top:8px;font-size:13px;color:#6366f1;display:none;align-items:center;gap:6px}
.sf-toolbar-btn{background:#f5f5f5;border:1px solid #e0e0e0;padding:8px 12px;border-radius:6px;font-size:13px;cursor:pointer;font-weight:500;color:#333}\
.sf-loc.show{display:flex}
.sf-toolbar-btn:hover{background:#eee}\
.sf-loc button{background:none;border:none;color:#94a3b8;cursor:pointer;font-size:14px}
.sf-compose-main{display:flex;gap:16px}\
.sf-divider{height:1px;background:#f1f5f9;margin:16px 0}
.sf-compose-avatar{width:48px;height:48px;border-radius:50%;overflow:hidden;flex-shrink:0}\
.sf-actions{display:flex;align-items:center;justify-content:space-between}
.sf-compose-avatar img{width:100%;height:100%;object-fit:cover}\
.sf-btns{display:flex;gap:4px}
.sf-av-ph{width:100%;height:100%;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:600;border-radius:50%}\
.sf-btn{width:40px;height:40px;border-radius:12px;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.15s}
.sf-compose-input{flex:1;border:none;resize:none;font-size:15px;outline:none;font-family:inherit;min-height:80px;color:#333}\
.sf-btn svg{width:20px;height:20px}
.sf-compose-input::placeholder{color:#999}\
.sf-btn-photo{background:#eff6ff;color:#3b82f6}
.sf-compose-preview{margin-top:12px;display:none}\
.sf-btn-photo:hover{background:#dbeafe}
.sf-compose-preview.show{display:block}\
.sf-btn-video{background:#fef2f2;color:#ef4444}
.sf-compose-preview img{max-width:100%;max-height:200px;border-radius:12px}\
.sf-btn-video:hover{background:#fee2e2}
.sf-compose-loc{margin-top:10px;font-size:13px;color:#ef4444;display:none;align-items:center;gap:6px}\
.sf-btn-loc{background:#f0fdf4;color:#22c55e}
.sf-compose-loc.show{display:flex}\
.sf-btn-loc:hover{background:#dcfce7}
.sf-compose-loc button{background:none;border:none;cursor:pointer;color:#999;margin-left:4px}\
.sf-btn-emoji{background:#fffbeb;color:#f59e0b}
.sf-compose-actions{display:flex;justify-content:space-between;align-items:center;margin-top:20px;padding-top:16px;border-top:1px solid #eee}\
.sf-btn-emoji:hover{background:#fef3c7}
.sf-action-btns{display:flex;gap:8px}\
.sf-btn-gif{background:#faf5ff;color:#a855f7}
.sf-action-btn{width:44px;height:44px;border-radius:50%;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px;transition:transform 0.15s}\
.sf-btn-gif:hover{background:#f3e8ff}
.sf-action-btn:hover{transform:scale(1.1)}\
.sf-post-btn{background:#3b82f6;color:#fff;border:none;padding:10px 24px;border-radius:12px;font-weight:600;font-size:14px;cursor:pointer;transition:all 0.15s}
.sf-action-btn.gif{background:#10b981;color:#fff}\
.sf-post-btn:hover{background:#2563eb;transform:translateY(-1px)}
.sf-action-btn.photo{background:#3b82f6;color:#fff}\
.sf-post-btn:disabled{background:#e2e8f0;color:#94a3b8;cursor:default;transform:none}
.sf-action-btn.check{background:#6366f1;color:#fff}\
.sf-post{overflow:visible}
.sf-action-btn.person{background:#0ea5e9;color:#fff}\
.sf-post-head{display:flex;align-items:center;gap:12px;padding:16px 20px}
.sf-action-btn.emoji{background:#f59e0b;color:#fff}\
.sf-post-info{flex:1}
.sf-action-btn.video{background:#ef4444;color:#fff}\
.sf-post-name{font-weight:600;font-size:14px;color:#1e293b}
.sf-action-btn.location{background:#ec4899;color:#fff}\
.sf-post-time{font-size:13px;color:#94a3b8}
.sf-action-btn.file{background:#6b7280;color:#fff}\
.sf-post-menu{background:none;border:none;color:#94a3b8;cursor:pointer;font-size:18px;padding:4px 8px;border-radius:8px}
.sf-share-btn{background:#f5f5f5;border:1px solid #e0e0e0;padding:10px 16px;border-radius:8px;font-size:13px;cursor:pointer;display:flex;align-items:center;gap:6px}\
.sf-post-menu:hover{background:#f1f5f9;color:#64748b}
.sf-share-btn:hover{background:#eee}\
.sf-post-body{padding:0 20px 16px;font-size:15px;line-height:1.6;color:#334155}
.sf-post-btn{background:#3b82f6;color:#fff;border:none;padding:12px 28px;border-radius:10px;font-weight:600;font-size:14px;cursor:pointer}\
.sf-post-media img{width:100%;display:block}
.sf-post-btn:disabled{opacity:0.4;cursor:default}\
.sf-post-media video{width:100%}
.sf-post-btn:not(:disabled):hover{background:#2563eb}\
.sf-post-media iframe{width:100%;aspect-ratio:16/9;border:none}
.sf-post{padding:0}\
.sf-post-foot{padding:12px 20px;display:flex;gap:20px;border-top:1px solid #f1f5f9}
.sf-post-header{display:flex;align-items:center;gap:14px;padding:18px 20px}\
.sf-react{background:none;border:none;font-size:22px;cursor:pointer;padding:4px;transition:transform 0.15s}
.sf-post-avatar{width:48px;height:48px;border-radius:50%;overflow:hidden}\
.sf-react:hover{transform:scale(1.2)}
.sf-post-avatar img{width:100%;height:100%;object-fit:cover}\
.sf-react.liked{color:#ef4444}
.sf-post-info{flex:1}\
.sf-stats{padding:0 20px 8px;font-size:14px;font-weight:600;color:#1e293b}
.sf-post-name{font-weight:600;font-size:15px;color:#333;display:flex;align-items:center;gap:8px}\
.sf-view-comments{padding:0 20px 12px;font-size:14px;color:#64748b;cursor:pointer}
.sf-post-badge{width:18px;height:18px}\
.sf-view-comments:hover{color:#3b82f6}
.sf-post-time{font-size:13px;color:#888;margin-top:2px}\
.sf-comments{display:none;padding:0 20px 12px}
.sf-post-actions-top{display:flex;gap:8px}\
.sf-comments.show{display:block}
.sf-post-action-btn{width:32px;height:32px;border-radius:8px;border:1px solid #e0e0e0;background:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:14px;color:#666}\
.sf-cmt{display:flex;gap:10px;margin-bottom:12px}
.sf-post-action-btn:hover{background:#f5f5f5}\
.sf-cmt-av{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}
.sf-post-content{padding:0 20px 16px;font-size:15px;line-height:1.5;color:#333}\
.sf-cmt-text{font-size:14px;line-height:1.4;color:#334155}
.sf-post-media{border-radius:0}\
.sf-cmt-text b{font-weight:600;color:#1e293b}
.sf-post-media img{width:100%;display:block}\
.sf-cmt-time{font-size:12px;color:#94a3b8;margin-top:2px}
.sf-post-media video{width:100%}\
.sf-cmt-form{display:flex;gap:12px;padding:12px 20px;border-top:1px solid #f1f5f9;align-items:center}
.sf-post-media iframe{width:100%;height:400px;border:none}\
.sf-cmt-input{flex:1;border:none;font-size:14px;outline:none;color:#1e293b}
.sf-post-footer{padding:16px 20px;display:flex;gap:20px;border-top:1px solid #f0f0f0}\
.sf-cmt-input::placeholder{color:#94a3b8}
.sf-post-react{background:none;border:none;cursor:pointer;font-size:22px;padding:0}\
.sf-cmt-btn{background:none;border:none;color:#3b82f6;font-weight:600;font-size:14px;cursor:pointer}
.sf-post-react:hover{transform:scale(1.15)}\
.sf-cmt-btn:hover{color:#2563eb}
.sf-post-react.liked{color:#ef4444}\
.sf-empty{padding:60px 20px;text-align:center}
.sf-post-stats{padding:0 20px 12px;font-size:14px;color:#333}\
.sf-empty-icon{font-size:48px;margin-bottom:16px;opacity:0.5}
.sf-post-stats b{font-weight:600}\
.sf-empty-title{font-size:18px;font-weight:600;color:#1e293b;margin-bottom:6px}
.sf-post-comments-link{padding:0 20px 12px;font-size:14px;color:#888;cursor:pointer}\
.sf-empty-text{font-size:14px;color:#64748b}
.sf-post-comments-link:hover{color:#333}\
.sf-modal{display:none;position:fixed;inset:0;background:rgba(15,23,42,0.6);z-index:9999;align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(4px)}
.sf-post-comments{display:none;padding:0 20px 16px;max-height:200px;overflow-y:auto}\
.sf-modal.open{display:flex}
.sf-post-comments.show{display:block}\
.sf-modal-box{background:#fff;border-radius:20px;width:100%;max-width:440px;overflow:hidden;animation:slideUp 0.2s ease}
.sf-comment{display:flex;gap:10px;margin-bottom:12px}\
@keyframes slideUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
.sf-comment-avatar{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}\
.sf-modal-head{display:flex;align-items:center;justify-content:space-between;padding:20px;border-bottom:1px solid #f1f5f9}
.sf-comment-avatar img{width:100%;height:100%;object-fit:cover}\
.sf-modal-title{font-weight:600;font-size:17px;color:#1e293b}
.sf-comment-body{flex:1}\
.sf-modal-x{background:none;border:none;font-size:24px;color:#94a3b8;cursor:pointer;line-height:1}
.sf-comment-text{font-size:14px;line-height:1.4}\
.sf-modal-x:hover{color:#64748b}
.sf-comment-text b{font-weight:600}\
.sf-modal-body{padding:20px}
.sf-comment-time{font-size:12px;color:#888;margin-top:3px}\
.sf-field{margin-bottom:16px}
.sf-comment-form{display:flex;gap:12px;padding:14px 20px;border-top:1px solid #f0f0f0;align-items:center}\
.sf-label{display:block;font-weight:500;font-size:13px;color:#64748b;margin-bottom:6px}
.sf-comment-input{flex:1;border:none;font-size:14px;outline:none;background:transparent}\
.sf-text-input{width:100%;padding:12px 14px;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#1e293b;outline:none;transition:border-color 0.15s}
.sf-comment-input::placeholder{color:#999}\
.sf-text-input:focus{border-color:#3b82f6}
.sf-comment-submit{background:none;border:none;color:#3b82f6;font-weight:600;cursor:pointer;font-size:14px}\
.sf-textarea-input{width:100%;padding:12px 14px;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#1e293b;outline:none;resize:vertical;min-height:80px;font-family:inherit}
.sf-empty{text-align:center;padding:60px 20px}\
.sf-textarea-input:focus{border-color:#3b82f6}
.sf-empty-icon{font-size:48px;margin-bottom:16px}\
.sf-upload-area{border:2px dashed #e2e8f0;border-radius:12px;padding:32px;text-align:center;cursor:pointer;transition:all 0.15s}
.sf-empty-title{font-size:20px;font-weight:500;margin-bottom:8px;color:#333}\
.sf-upload-area:hover{border-color:#3b82f6;background:#f8faff}
.sf-empty-text{color:#888;font-size:14px}\
.sf-upload-area input{display:none}
.sf-modal{display:none;position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.5);z-index:9999;align-items:center;justify-content:center;padding:20px}\
.sf-upload-icon{font-size:32px;margin-bottom:8px}
.sf-modal.open{display:flex}\
.sf-upload-text{font-size:14px;color:#64748b}
.sf-modal-box{background:#fff;border-radius:16px;width:100%;max-width:420px;max-height:85vh;overflow:auto}\
.sf-upload-text span{color:#3b82f6;font-weight:500}
.sf-modal-head{display:flex;align-items:center;justify-content:space-between;padding:18px 20px;border-bottom:1px solid #eee}\
.sf-img-preview{width:100%;max-height:150px;object-fit:contain;border-radius:10px;margin-top:12px;display:none}
.sf-modal-title{font-weight:600;font-size:17px}\
.sf-img-preview.show{display:block}
.sf-modal-x{background:none;border:none;font-size:24px;cursor:pointer;color:#666;line-height:1}\
.sf-progress{height:4px;background:#e2e8f0;border-radius:2px;margin-top:12px;overflow:hidden;display:none}
.sf-modal-body{padding:20px}\
.sf-progress.show{display:block}
.sf-tabs{display:flex;border-bottom:1px solid #eee}\
.sf-progress-bar{height:100%;background:#3b82f6;width:0;transition:width 0.2s}
.sf-tab{flex:1;padding:14px;text-align:center;cursor:pointer;font-weight:600;font-size:14px;color:#888;border-bottom:2px solid transparent;margin-bottom:-1px}\
.sf-modal-btns{display:flex;gap:10px;margin-top:20px}
.sf-tab.active{color:#333;border-bottom-color:#3b82f6}\
.sf-modal-btn{flex:1;padding:12px;border-radius:10px;font-weight:600;font-size:14px;cursor:pointer;transition:all 0.15s}
.sf-panel{display:none;padding:20px}\
.sf-modal-btn-primary{background:#3b82f6;color:#fff;border:none}
.sf-panel.active{display:block}\
.sf-modal-btn-primary:hover{background:#2563eb}
.sf-upload{border:2px dashed #ddd;border-radius:12px;padding:32px;text-align:center;cursor:pointer;transition:all 0.2s}\
.sf-modal-btn-secondary{background:#f1f5f9;color:#475569;border:none}
.sf-upload:hover{border-color:#3b82f6;background:#f8faff}\
.sf-modal-btn-secondary:hover{background:#e2e8f0}
.sf-upload input{display:none}\
`;
.sf-upload-icon{font-size:40px;margin-bottom:12px}\
.sf-upload-text{color:#888;font-size:14px}\
.sf-input{width:100%;padding:14px;border:1px solid #ddd;border-radius:10px;font-size:14px;margin-bottom:14px;outline:none}\
.sf-input:focus{border-color:#3b82f6}\
.sf-textarea{width:100%;padding:14px;border:1px solid #ddd;border-radius:10px;font-size:14px;margin-bottom:14px;outline:none;resize:vertical;min-height:80px;font-family:inherit}\
.sf-textarea:focus{border-color:#3b82f6}\
.sf-preview{width:100%;max-height:150px;object-fit:contain;border-radius:10px;margin-top:12px;display:none}\
.sf-preview.show{display:block}\
.sf-progress{height:4px;background:#eee;border-radius:2px;margin-top:12px;overflow:hidden;display:none}\
.sf-progress.show{display:block}\
.sf-progress-bar{height:100%;background:#3b82f6;width:0;transition:width 0.3s}\
.sf-btn-row{display:flex;gap:10px;margin-top:20px}\
.sf-btn{flex:1;padding:14px;border:none;border-radius:10px;font-weight:600;font-size:14px;cursor:pointer}\
.sf-btn-primary{background:#3b82f6;color:#fff}\
.sf-btn-primary:hover{background:#2563eb}\
.sf-btn-secondary{background:#f5f5f5;color:#333;border:1px solid #e0e0e0}\
.sf-btn-secondary:hover{background:#eee}\
@media(max-width:900px){.sf-sidebar{display:none}.sf-layout{max-width:700px}}';
$("<style>").text(css).appendTo("head");
$("<style>").text(css).appendTo("head");


var h='<div class="sf-layout"><div class="sf-main">';
// SVG icons
var icons={
photo:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>',
video:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>',
loc:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>',
emoji:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>',
gif:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><text x="12" y="14" text-anchor="middle" font-size="6" fill="currentColor" stroke="none">GIF</text></svg>'
};


// Composer
var h='<div class="sf-wrap">';
h+='<div class="sf-card sf-compose">';
h+='<div class="sf-card sf-compose">';
h+='<div class="sf-compose-toolbar"><button class="sf-toolbar-btn"><b>B</b></button><button class="sf-toolbar-btn"><i>I</i></button><button class="sf-toolbar-btn"><u>U</u></button><button class="sf-toolbar-btn">Text Color ▾</button><button class="sf-toolbar-btn">Outline ▾</button></div>';
h+='<div class="sf-compose-row"><div class="sf-avatar" id="user-avatar">'+av(ud.photo,user,16)+'</div>';
h+='<div class="sf-compose-main"><div class="sf-compose-avatar" id="composer-avatar">'+av(ud.photo,user,18)+'</div><textarea class="sf-compose-input" id="post-input" placeholder="What\'s on your mind, '+esc(user.split(/[\s_]/)[0])+'?"></textarea></div>';
h+='<div class="sf-input-wrap"><textarea class="sf-input" id="post-input" placeholder="What\'s on your mind?"></textarea>';
h+='<div class="sf-compose-preview" id="post-preview"></div>';
h+='<div class="sf-preview" id="post-preview"></div>';
h+='<div class="sf-compose-loc" id="post-location">📍 <span></span><button id="remove-location"></button></div>';
h+='<div class="sf-loc" id="post-loc"><span></span><button id="rm-loc">×</button></div></div></div>';
h+='<div class="sf-compose-actions"><div class="sf-action-btns">';
h+='<div class="sf-divider"></div>';
h+='<button class="sf-action-btn gif" title="GIF">GIF</button>';
h+='<div class="sf-actions"><div class="sf-btns">';
h+='<button class="sf-action-btn photo" id="btn-add-photo" title="Photo">🖼</button>';
h+='<button class="sf-btn sf-btn-photo" id="btn-photo" title="Photo">'+icons.photo+'</button>';
h+='<button class="sf-action-btn check" title="Poll">✓</button>';
h+='<button class="sf-btn sf-btn-video" title="Video">'+icons.video+'</button>';
h+='<button class="sf-action-btn person" title="Tag">👤</button>';
h+='<button class="sf-btn sf-btn-loc" id="btn-loc" title="Location">'+icons.loc+'</button>';
h+='<button class="sf-action-btn emoji" id="btn-add-emoji" title="Emoji">😊</button>';
h+='<button class="sf-btn sf-btn-emoji" id="btn-emoji" title="Emoji">'+icons.emoji+'</button>';
h+='<button class="sf-action-btn video" id="btn-add-video" title="Video">🎬</button>';
h+='<button class="sf-btn sf-btn-gif" title="GIF">'+icons.gif+'</button>';
h+='<button class="sf-action-btn location" id="btn-add-location" title="Location">📍</button>';
h+='</div><button class="sf-post-btn" id="btn-post" disabled>Post</button></div></div>';
h+='<button class="sf-action-btn file" title="File">📁</button>';
h+='<div id="feed"></div></div>';
h+='</div>';
h+='<button class="sf-share-btn">Share to... ▾</button>';
h+='<button class="sf-post-btn" id="btn-submit-post" disabled>Post</button>';
h+='</div></div>';


// Feed
// Modal
h+='<div class="sf-feed" id="feed-container"></div>';
h+='<div class="sf-modal" id="modal-photo"><div class="sf-modal-box"><div class="sf-modal-head"><span class="sf-modal-title">Add Photo</span><button class="sf-modal-x" data-close="modal-photo">×</button></div><div class="sf-modal-body">';
h+='</div>';
h+='<div class="sf-upload-area" id="upload-photo"><input type="file" accept="image/*"><div class="sf-upload-icon">📷</div><div class="sf-upload-text">Click or drag to <span>upload</span></div></div>';
h+='<div class="sf-progress" id="prog-photo"><div class="sf-progress-bar"></div></div>';
h+='<img class="sf-img-preview" id="prev-photo">';
h+='<div class="sf-field" style="margin-top:16px"><div class="sf-label">Or paste URL</div><input class="sf-text-input" id="url-photo" placeholder="https://..."></div>';
h+='<div class="sf-modal-btns"><button class="sf-modal-btn sf-modal-btn-secondary" data-close="modal-photo">Cancel</button><button class="sf-modal-btn sf-modal-btn-primary" id="add-photo">Add Photo</button></div></div></div></div>';


// Sidebar
h+='<div class="sf-modal" id="modal-profile"><div class="sf-modal-box"><div class="sf-modal-head"><span class="sf-modal-title">Edit Profile</span><button class="sf-modal-x" data-close="modal-profile">×</button></div><div class="sf-modal-body">';
h+='<div class="sf-sidebar"><div class="sf-card sf-profile-card">';
h+='<div class="sf-field"><div class="sf-label">Profile Photo</div><div class="sf-upload-area" id="upload-pic"><input type="file" accept="image/*"><div class="sf-upload-icon">👤</div><div class="sf-upload-text">Click to <span>upload</span></div></div><div class="sf-progress" id="prog-pic"><div class="sf-progress-bar"></div></div><img class="sf-img-preview" id="prev-pic"></div>';
h+='<div class="sf-card-header">Profile Details</div>';
h+='<div class="sf-field"><div class="sf-label">Bio</div><textarea class="sf-textarea-input" id="inp-bio" placeholder="Tell us about yourself...">'+esc(ud.bio)+'</textarea></div>';
h+='<div class="sf-card-body">';
h+='<div class="sf-modal-btns"><button class="sf-modal-btn sf-modal-btn-secondary" data-close="modal-profile">Cancel</button><button class="sf-modal-btn sf-modal-btn-primary" id="save-profile">Save</button></div></div></div></div>';
h+='<div class="sf-profile-row"><div class="sf-profile-label">Username</div><div class="sf-profile-value">@'+esc(user)+'</div></div>';
h+='<div class="sf-profile-row"><div class="sf-profile-label">Member Since</div><div class="sf-profile-value">January 1, 2026</div></div>';
h+='<div class="sf-profile-row"><div class="sf-profile-label">Location</div><div class="sf-profile-value" id="profile-location">'+(ud.bio||"Not set")+'</div></div>';
h+='<div class="sf-profile-row"><div class="sf-profile-label">Total Posts</div><div class="sf-profile-value" id="total-posts">0</div></div>';
h+='<div class="sf-profile-row"><div class="sf-profile-label">Website</div><div class="sf-profile-value"><a href="https://docmoates.com" target="_blank">docmoates.com</a></div></div>';
h+='</div></div>';
h+='<button class="sf-btn sf-btn-secondary" style="width:100%" id="edit-profile-btn">Edit Profile</button>';
h+='</div></div>';
 
// Modals
h+='<div class="sf-modal" id="modal-edit-profile"><div class="sf-modal-box"><div class="sf-modal-head"><span class="sf-modal-title">Edit Profile</span><button class="sf-modal-x" data-close="modal-edit-profile"></button></div><div class="sf-modal-body"><label style="font-weight:600;font-size:13px;display:block;margin-bottom:8px">Display Name</label><input class="sf-input" id="input-display-name" value="'+esc(ud.name)+'"><label style="font-weight:600;font-size:13px;display:block;margin-bottom:8px">Location / Bio</label><textarea class="sf-textarea" id="input-bio" placeholder="Your location or short bio...">'+esc(ud.bio)+'</textarea><label style="font-weight:600;font-size:13px;display:block;margin-bottom:8px">Profile Photo</label><div class="sf-upload" id="zone-profile-pic"><input type="file" accept="image/*"><div class="sf-upload-icon">📷</div><div class="sf-upload-text">Click to upload photo</div></div><div class="sf-progress" id="progress-profile-pic"><div class="sf-progress-bar"></div></div><img class="sf-preview" id="preview-profile-pic"><div class="sf-btn-row"><button class="sf-btn sf-btn-secondary" data-close="modal-edit-profile">Cancel</button><button class="sf-btn sf-btn-primary" id="save-profile">Save Changes</button></div></div></div></div>';
 
h+='<div class="sf-modal" id="modal-photo"><div class="sf-modal-box"><div class="sf-modal-head"><span class="sf-modal-title">Add Photo</span><button class="sf-modal-x" data-close="modal-photo">✕</button></div><div class="sf-tabs"><div class="sf-tab active" data-panel="panel-photo-upload">Upload</div><div class="sf-tab" data-panel="panel-photo-url">URL</div></div><div class="sf-panel active" id="panel-photo-upload"><div class="sf-upload" id="zone-photo"><input type="file" accept="image/*"><div class="sf-upload-icon">📷</div><div class="sf-upload-text">Click to upload</div></div><div class="sf-progress" id="progress-photo"><div class="sf-progress-bar"></div></div><img class="sf-preview" id="preview-photo"></div><div class="sf-panel" id="panel-photo-url"><input class="sf-input" id="input-photo-url" placeholder="Paste image URL..."><img class="sf-preview" id="preview-photo-url"></div><div class="sf-btn-row" style="padding:0 20px 20px"><button class="sf-btn sf-btn-secondary" data-close="modal-photo">Cancel</button><button class="sf-btn sf-btn-primary" id="add-photo">Add Photo</button></div></div></div>';


$("#social-app").html(h);
$("#social-app").html(h);
Line 191: Line 165:
$a.on("click","[data-close]",function(){cm($(this).data("close"));});
$a.on("click","[data-close]",function(){cm($(this).data("close"));});
$a.on("click",".sf-modal",function(e){if($(e.target).hasClass("sf-modal"))cm(this.id);});
$a.on("click",".sf-modal",function(e){if($(e.target).hasClass("sf-modal"))cm(this.id);});
$a.on("click",".sf-tab",function(){var $t=$(this),$p=$("#"+$t.data("panel"));$t.addClass("active").siblings().removeClass("active");$p.addClass("active").siblings(".sf-panel").removeClass("active");});
function suz(zid,pid,prid,fk){var $z=$("#"+zid),$i=$z.find("input"),$pv=$("#"+pid),$pr=$("#"+prid);$z.on("click",function(){$i.click();});$i.on("change",function(){if(this.files.length){var f=this.files[0];uf[fk]=f;if(f.type.startsWith("image/")){var r=new FileReader();r.onload=function(e){$pv.attr("src",e.target.result).addClass("show");};r.readAsDataURL(f);}}});return{reset:function(){uf[fk]=null;$pv.removeClass("show").attr("src","");$pr.removeClass("show").find(".sf-progress-bar").css("width",0);$i.val("");},setP:function(p){$pr.addClass("show").find(".sf-progress-bar").css("width",p+"%");}};}


var upPic=suz("zone-profile-pic","preview-profile-pic","progress-profile-pic","profilePic");
function setupUpload(zoneId,prevId,progId,key){
var upPho=suz("zone-photo","preview-photo","progress-photo","photo");
  var $z=$("#"+zoneId),$i=$z.find("input"),$pv=$("#"+prevId),$pr=$("#"+progId);
  $z.on("click",function(){$i.click();});
  $i.on("change",function(){if(this.files[0]){uf[key]=this.files[0];var r=new FileReader();r.onload=function(e){$pv.attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});
  return{reset:function(){uf[key]=null;$pv.removeClass("show");$pr.removeClass("show").find(".sf-progress-bar").css("width",0);$i.val("");},prog:function(p){$pr.addClass("show").find(".sf-progress-bar").css("width",p+"%");}};
}
var upPhoto=setupUpload("upload-photo","prev-photo","prog-photo","photo");
var upPic=setupUpload("upload-pic","prev-pic","prog-pic","pic");


$("#input-photo-url").on("input",function(){var v=$(this).val();$("#preview-photo-url").attr("src",v).toggleClass("show",!!v);});
$("#url-photo").on("input",function(){var v=$(this).val();if(v)$("#prev-photo").attr("src",v).addClass("show");else $("#prev-photo").removeClass("show");});


$("#edit-profile-btn").on("click",function(){upPic.reset();om("modal-edit-profile");});
$("#btn-photo").on("click",function(){upPhoto.reset();$("#url-photo").val("");om("modal-photo");});
$("#save-profile").on("click",function(){
$("#add-photo").on("click",function(){
   ud.name=$("#input-display-name").val().trim()||user;
   var url=$("#url-photo").val().trim();
   ud.bio=$("#input-bio").val().trim();
   if(url){pp.image=url;showPreview(url);cm("modal-photo");}
  localStorage.setItem("sf_name_"+user,ud.name);
   else if(uf.photo){upload(uf.photo,"Post",upPhoto.prog).then(function(u){pp.image=u;showPreview(u);cm("modal-photo");upPhoto.reset();});}
  localStorage.setItem("sf_bio_"+user,ud.bio);
   else alert("Select or paste an image");
  $("#profile-location").text(ud.bio||"Not set");
   if(uf.profilePic){
    upload(uf.profilePic,"ProfilePic",upPic.setP).then(function(u){
      ud.photo=u;localStorage.setItem("sf_photo_"+user,u);
      $("#composer-avatar").html(av(u,user,18));
      cm("modal-edit-profile");upPic.reset();
    }).fail(function(){alert("Upload error");});
   }else{cm("modal-edit-profile");}
});
});
function showPreview(u){$("#post-preview").addClass("show").html('<img src="'+u+'"><button class="sf-preview-x" id="rm-preview">×</button>');upd();}
$a.on("click","#rm-preview",function(){pp.image="";$("#post-preview").removeClass("show").html("");upd();});


$("#btn-add-photo").on("click",function(){upPho.reset();$("#input-photo-url").val("");$("#preview-photo-url").removeClass("show");om("modal-photo");});
$("#btn-loc").on("click",function(){var l=prompt("Location:");if(l){pp.location=l;$("#post-loc").addClass("show").find("span").text("📍 "+l);}});
$("#add-photo").on("click",function(){var ap=$("#modal-photo .sf-tab.active").data("panel");if(ap==="panel-photo-url"){var u=$("#input-photo-url").val().trim();if(u){pp.image=u;$("#post-preview").addClass("show").html('<img src="'+u+'" style="max-width:100%;max-height:200px;border-radius:12px">');upd();cm("modal-photo");}else alert("Enter a URL");}else if(uf.photo){upload(uf.photo,"Post",upPho.setP).then(function(u){pp.image=u;$("#post-preview").addClass("show").html('<img src="'+u+'" style="max-width:100%;max-height:200px;border-radius:12px">');upd();cm("modal-photo");upPho.reset();}).fail(function(){alert("Upload error");});}else alert("Select an image");});
$a.on("click","#rm-loc",function(){pp.location="";$("#post-loc").removeClass("show");});
$("#btn-emoji").on("click",function(){var e=prompt("Emoji:");if(e){var t=$("#post-input")[0];t.value=t.value.slice(0,t.selectionStart)+e+t.value.slice(t.selectionEnd);t.focus();upd();}});


$("#btn-add-location").on("click",function(){var l=prompt("Enter location:");if(l){pp.location=l;$("#post-location").addClass("show").find("span").text(l);}});
$("#post-input").on("input",upd);
$a.on("click","#remove-location",function(){pp.location="";$("#post-location").removeClass("show");});
function upd(){$("#btn-post").prop("disabled",!$("#post-input").val().trim()&&!pp.image);}
$("#btn-add-emoji").on("click",function(){var e=prompt("Enter emoji:");if(e){var $i=$("#post-input")[0];var s=$i.selectionStart,v=$i.value;$i.value=v.slice(0,s)+e+v.slice($i.selectionEnd);$i.selectionStart=$i.selectionEnd=s+e.length;$i.focus();upd();}});


$("#post-input").on("input",upd);
$("#btn-post").on("click",function(){
function upd(){var h=$("#post-input").val().trim()||pp.image||pp.video;$("#btn-submit-post").prop("disabled",!h);}
  var t=$("#post-input").val().trim();if(!t&&!pp.image)return;
  var $b=$(this).prop("disabled",true).text("...");
  var p={action:"socialfeed",sfaction:"createpost",content:t||"(media)"};
  if(pp.image)p.image_url=pp.image;
  if(pp.location)p.location=pp.location;
  api.postWithToken("csrf",p).then(function(){
    $("#post-input").val("");pp={image:"",location:""};
    $("#post-preview,#post-loc").removeClass("show").html("");
    $b.prop("disabled",true).text("Post");loadFeed();
  }).fail(function(){$b.prop("disabled",false).text("Post");});
});


$("#btn-submit-post").on("click",function(){var t=$("#post-input").val().trim();if(!t&&!pp.image&&!pp.video)return;var $b=$(this);$b.prop("disabled",true).text("Posting...");var p={action:"socialfeed",sfaction:"createpost",content:t||"(media)"};if(pp.image)p.image_url=pp.image;if(pp.video)p.video_url=pp.video;if(pp.location)p.location=pp.location;api.postWithToken("csrf",p).then(function(){$("#post-input").val("");pp={image:"",video:"",location:""};$("#post-preview").removeClass("show").html("");$("#post-location").removeClass("show");$b.prop("disabled",true).text("Post");loadP();}).fail(function(c,d){alert("Error: "+(d&&d.error?d.error.info:c));$b.prop("disabled",false).text("Post");});});
$("#save-profile").on("click",function(){
  ud.bio=$("#inp-bio").val().trim();
  localStorage.setItem("sf_bio_"+user,ud.bio);
  if(uf.pic){upload(uf.pic,"Pic",upPic.prog).then(function(u){
    ud.photo=u;localStorage.setItem("sf_photo_"+user,u);
    $("#user-avatar").html(av(u,user,16));cm("modal-profile");upPic.reset();
  });}else cm("modal-profile");
});


$a.on("click",".sf-post-react[data-like]",function(){var id=$(this).data("like");api.postWithToken("csrf",{action:"socialfeed",sfaction:"react",post_id:id,reaction_type:"like"}).then(loadP);});
$a.on("click",".sf-react[data-id]",function(){api.postWithToken("csrf",{action:"socialfeed",sfaction:"react",post_id:$(this).data("id"),reaction_type:"like"}).then(loadFeed);});
$a.on("click",".sf-post-action-btn[data-del]",function(){if(confirm("Delete this post?")){api.postWithToken("csrf",{action:"socialfeed",sfaction:"deletepost",post_id:$(this).data("del")}).then(loadP);}});
$a.on("click",".sf-post-menu[data-del]",function(){if(confirm("Delete?")){api.postWithToken("csrf",{action:"socialfeed",sfaction:"deletepost",post_id:$(this).data("del")}).then(loadFeed);}});
$a.on("click",".sf-post-comments-link",function(){var id=$(this).data("post"),$s=$("#cmts-"+id);if($s.hasClass("show"))$s.removeClass("show");else{$s.addClass("show");loadC(id);}});
$a.on("click",".sf-view-comments",function(){var id=$(this).data("id"),$c=$("#cmt-"+id);$c.toggleClass("show");if($c.hasClass("show"))loadComments(id);});
$a.on("keypress",".sf-comment-input",function(e){if(e.which===13){var $i=$(this),t=$i.val().trim(),id=$i.data("post");if(t){$i.val("").prop("disabled",true);api.postWithToken("csrf",{action:"socialfeed",sfaction:"comment",post_id:id,content:t}).then(function(){$i.prop("disabled",false);loadC(id);loadP();}).fail(function(){$i.prop("disabled",false);});}}});
$a.on("keypress",".sf-cmt-input",function(e){if(e.which===13){var $i=$(this),t=$i.val().trim(),id=$i.data("id");if(t){$i.val("").prop("disabled",true);api.postWithToken("csrf",{action:"socialfeed",sfaction:"comment",post_id:id,content:t}).then(function(){$i.prop("disabled",false);loadComments(id);loadFeed();});}}});


function loadP(){api.get({action:"socialfeed",sfaction:"getposts",limit:20}).then(function(r){var ps=(r.socialfeed&&r.socialfeed.posts)||[];$("#total-posts").text(ps.length);if(!ps.length){$("#feed-container").html('<div class="sf-card"><div class="sf-empty"><div class="sf-empty-icon">📷</div><div class="sf-empty-title">Share Photos</div><div class="sf-empty-text">When you share photos, they will appear here.</div></div></div>');return;}var h=ps.map(function(p){var up=localStorage.getItem("sf_photo_"+p.username)||"",tr=0;for(var k in p.reaction_counts)tr+=p.reaction_counts[k];var m="";if(p.image_url)m='<div class="sf-post-media"><img src="'+esc(p.image_url)+'"></div>';if(p.video_url){if(p.video_url.match(/youtube|youtu\.be/)){var vi=(p.video_url.match(/(?:v=|youtu\.be\/)([^&]+)/)||[])[1];if(vi)m='<div class="sf-post-media"><iframe src="https://www.youtube.com/embed/'+vi+'" allowfullscreen></iframe></div>';}else m='<div class="sf-post-media"><video src="'+esc(p.video_url)+'" controls></video></div>';}var del=p.username===user?'<button class="sf-post-action-btn" data-del="'+p.id+'" title="Delete"></button>':"";var lc=p.user_reaction==="like"?" liked":"";return'<div class="sf-card sf-post"><div class="sf-post-header"><div class="sf-post-avatar">'+av(up,p.username,16)+'</div><div class="sf-post-info"><div class="sf-post-name">'+esc(p.username)+'</div><div class="sf-post-time">'+ago(p.created)+'</div></div><div class="sf-post-actions-top"><button class="sf-post-action-btn" title="Edit">✎</button>'+del+'</div></div>'+m+(p.content&&p.content!=="(media)"?'<div class="sf-post-content">'+esc(p.content)+'</div>':'')+'<div class="sf-post-footer"><button class="sf-post-react'+lc+'" data-like="'+p.id+'">'+(p.user_reaction==="like"?"❤️":"🤍")+'</button><button class="sf-post-react">💬</button><button class="sf-post-react">📤</button><button class="sf-post-react">🔖</button></div>'+(tr?'<div class="sf-post-stats"><b>'+tr+"</b> like"+(tr>1?"s":"")+"</div>":"")+(p.comments?'<div class="sf-post-comments-link" data-post="'+p.id+'">View all '+p.comments+" comment"+(p.comments>1?"s":"")+"</div>":"")+'<div class="sf-post-comments" id="cmts-'+p.id+'"></div><div class="sf-comment-form"><input class="sf-comment-input" data-post="'+p.id+'" placeholder="Add a comment..."><button class="sf-comment-submit">Post</button></div></div>';}).join("");$("#feed-container").html(h);});}
function loadFeed(){
  api.get({action:"socialfeed",sfaction:"getposts",limit:20}).then(function(r){
    var posts=(r.socialfeed&&r.socialfeed.posts)||[];
    if(!posts.length){$("#feed").html('<div class="sf-card"><div class="sf-empty"><div class="sf-empty-icon">📷</div><div class="sf-empty-title">No posts yet</div><div class="sf-empty-text">Share something to get started</div></div></div>');return;}
    var h=posts.map(function(p){
      var pic=localStorage.getItem("sf_photo_"+p.username)||"";
      var likes=0;for(var k in p.reaction_counts)likes+=p.reaction_counts[k];
      var media="";
      if(p.image_url)media='<div class="sf-post-media"><img src="'+esc(p.image_url)+'"></div>';
      else if(p.video_url&&p.video_url.match(/youtube|youtu\.be/)){var vid=(p.video_url.match(/(?:v=|youtu\.be\/)([^&]+)/)||[])[1];if(vid)media='<div class="sf-post-media"><iframe src="https://www.youtube.com/embed/'+vid+'" allowfullscreen></iframe></div>';}
      var del=p.username===user?'<button class="sf-post-menu" data-del="'+p.id+'">×</button>':"";
      var liked=p.user_reaction==="like"?" liked":"";
      return '<div class="sf-card sf-post"><div class="sf-post-head"><div class="sf-avatar">'+av(pic,p.username,14)+'</div><div class="sf-post-info"><div class="sf-post-name">'+esc(p.username)+'</div><div class="sf-post-time">'+ago(p.created)+'</div></div>'+del+'</div>'+(p.content&&p.content!=="(media)"?'<div class="sf-post-body">'+esc(p.content)+'</div>':'')+media+'<div class="sf-post-foot"><button class="sf-react'+liked+'" data-id="'+p.id+'">'+(liked?"❤️":"🤍")+'</button><button class="sf-react">💬</button><button class="sf-react"></button></div>'+(likes?'<div class="sf-stats">'+likes+' like'+(likes>1?'s':'')+'</div>':'')+(p.comments?'<div class="sf-view-comments" data-id="'+p.id+'">View '+p.comments+' comment'+(p.comments>1?'s':'')+'</div>':'')+'<div class="sf-comments" id="cmt-'+p.id+'"></div><div class="sf-cmt-form"><input class="sf-cmt-input" data-id="'+p.id+'" placeholder="Add a comment..."><button class="sf-cmt-btn">Post</button></div></div>';
    }).join("");
    $("#feed").html(h);
  });
}


function loadC(id){api.get({action:"socialfeed",sfaction:"getcomments",post_id:id}).then(function(r){var cs=(r.socialfeed&&r.socialfeed.comments)||[];var h=cs.map(function(c){var up=localStorage.getItem("sf_photo_"+c.username)||"";return'<div class="sf-comment"><div class="sf-comment-avatar">'+av(up,c.username,11)+'</div><div class="sf-comment-body"><div class="sf-comment-text"><b>'+esc(c.username)+"</b> "+esc(c.content)+'</div><div class="sf-comment-time">'+ago(c.created)+"</div></div></div>";}).join("");$("#cmts-"+id).html(h||'<div style="color:#888;font-size:13px;padding:8px 0">No comments yet</div>');});}
function loadComments(id){
  api.get({action:"socialfeed",sfaction:"getcomments",post_id:id}).then(function(r){
    var cmts=(r.socialfeed&&r.socialfeed.comments)||[];
    var h=cmts.map(function(c){
      var pic=localStorage.getItem("sf_photo_"+c.username)||"";
      return '<div class="sf-cmt"><div class="sf-cmt-av">'+av(pic,c.username,11)+'</div><div><div class="sf-cmt-text"><b>'+esc(c.username)+'</b> '+esc(c.content)+'</div><div class="sf-cmt-time">'+ago(c.created)+'</div></div></div>';
    }).join("");
    $("#cmt-"+id).html(h||'<div style="padding:8px 0;color:#94a3b8;font-size:14px">No comments yet</div>');
  });
}


loadP();
loadFeed();
});
});
}
}

Revision as of 14:22, 4 February 2026

/* SocialFeed v6 - Clean Modern Design */
if (mw.config.get("wgPageName").indexOf("User:Docmoates/Social") !== -1) {
mw.loader.using(["mediawiki.api", "mediawiki.util"]).then(function() {
var $=jQuery,api=new mw.Api(),apiUrl=mw.util.wikiScript("api"),user=mw.config.get("wgUserName")||"Guest";
var ud={photo:localStorage.getItem("sf_photo_"+user)||"",bio:localStorage.getItem("sf_bio_"+user)||""};
var pp={image:"",location:""},uf={};

function gi(n){return(n||"?").charAt(0).toUpperCase();}
function esc(t){var d=document.createElement("div");d.textContent=t;return d.innerHTML;}
function ago(ds){var s=Math.floor((Date.now()-new Date(ds))/1000);if(s<60)return"now";var m=Math.floor(s/60);if(m<60)return m+"m";var h=Math.floor(m/60);if(h<24)return h+"h";return Math.floor(h/24)+"d";}
function av(p,n,s){return p?'<img src="'+esc(p)+'" style="width:100%;height:100%;object-fit:cover">':'<div style="width:100%;height:100%;background:linear-gradient(135deg,#6366f1,#8b5cf6);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:600;font-size:'+s+'px">'+gi(n)+'</div>';}
function om(id){$("#"+id).addClass("open");}
function cm(id){$("#"+id).removeClass("open");}
function upload(file,pre,prog){return api.getToken("csrf").then(function(tk){var fd=new FormData();fd.append("action","upload");fd.append("filename",pre+"_"+user+"_"+Date.now()+"."+file.name.split(".").pop());fd.append("file",file);fd.append("token",tk);fd.append("format","json");fd.append("ignorewarnings","1");return $.ajax({url:apiUrl,type:"POST",data:fd,processData:false,contentType:false,xhr:function(){var x=$.ajaxSettings.xhr();if(x.upload&&prog)x.upload.addEventListener("progress",function(e){if(e.lengthComputable)prog(Math.round(e.loaded/e.total*100));});return x;}});}).then(function(r){if(r.upload&&r.upload.imageinfo)return r.upload.imageinfo.url;throw new Error("Upload failed");});}

setTimeout(function(){$('button,a').filter(function(){return $(this).text().indexOf('Design')!==-1;}).hide();},200);

var css=`
[class*="wikibox"]{display:none!important}
#social-app{font-family:Inter,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;background:#f8fafc;min-height:100vh;padding:24px}
#social-app *{box-sizing:border-box;margin:0;padding:0}
.sf-wrap{max-width:680px;margin:0 auto}
.sf-card{background:#fff;border-radius:16px;box-shadow:0 1px 3px rgba(0,0,0,0.06),0 1px 2px rgba(0,0,0,0.04);margin-bottom:16px;overflow:hidden}
.sf-compose{padding:20px}
.sf-compose-row{display:flex;gap:14px;align-items:flex-start}
.sf-avatar{width:44px;height:44px;border-radius:50%;overflow:hidden;flex-shrink:0}
.sf-input-wrap{flex:1}
.sf-input{width:100%;border:none;font-size:15px;color:#1e293b;resize:none;outline:none;min-height:60px;font-family:inherit;line-height:1.5}
.sf-input::placeholder{color:#94a3b8}
.sf-preview{margin-top:12px;position:relative;display:none}
.sf-preview.show{display:block}
.sf-preview img{max-width:100%;border-radius:12px}
.sf-preview-x{position:absolute;top:8px;right:8px;width:28px;height:28px;border-radius:50%;background:rgba(0,0,0,0.6);color:#fff;border:none;cursor:pointer;font-size:16px}
.sf-loc{margin-top:8px;font-size:13px;color:#6366f1;display:none;align-items:center;gap:6px}
.sf-loc.show{display:flex}
.sf-loc button{background:none;border:none;color:#94a3b8;cursor:pointer;font-size:14px}
.sf-divider{height:1px;background:#f1f5f9;margin:16px 0}
.sf-actions{display:flex;align-items:center;justify-content:space-between}
.sf-btns{display:flex;gap:4px}
.sf-btn{width:40px;height:40px;border-radius:12px;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.15s}
.sf-btn svg{width:20px;height:20px}
.sf-btn-photo{background:#eff6ff;color:#3b82f6}
.sf-btn-photo:hover{background:#dbeafe}
.sf-btn-video{background:#fef2f2;color:#ef4444}
.sf-btn-video:hover{background:#fee2e2}
.sf-btn-loc{background:#f0fdf4;color:#22c55e}
.sf-btn-loc:hover{background:#dcfce7}
.sf-btn-emoji{background:#fffbeb;color:#f59e0b}
.sf-btn-emoji:hover{background:#fef3c7}
.sf-btn-gif{background:#faf5ff;color:#a855f7}
.sf-btn-gif:hover{background:#f3e8ff}
.sf-post-btn{background:#3b82f6;color:#fff;border:none;padding:10px 24px;border-radius:12px;font-weight:600;font-size:14px;cursor:pointer;transition:all 0.15s}
.sf-post-btn:hover{background:#2563eb;transform:translateY(-1px)}
.sf-post-btn:disabled{background:#e2e8f0;color:#94a3b8;cursor:default;transform:none}
.sf-post{overflow:visible}
.sf-post-head{display:flex;align-items:center;gap:12px;padding:16px 20px}
.sf-post-info{flex:1}
.sf-post-name{font-weight:600;font-size:14px;color:#1e293b}
.sf-post-time{font-size:13px;color:#94a3b8}
.sf-post-menu{background:none;border:none;color:#94a3b8;cursor:pointer;font-size:18px;padding:4px 8px;border-radius:8px}
.sf-post-menu:hover{background:#f1f5f9;color:#64748b}
.sf-post-body{padding:0 20px 16px;font-size:15px;line-height:1.6;color:#334155}
.sf-post-media img{width:100%;display:block}
.sf-post-media video{width:100%}
.sf-post-media iframe{width:100%;aspect-ratio:16/9;border:none}
.sf-post-foot{padding:12px 20px;display:flex;gap:20px;border-top:1px solid #f1f5f9}
.sf-react{background:none;border:none;font-size:22px;cursor:pointer;padding:4px;transition:transform 0.15s}
.sf-react:hover{transform:scale(1.2)}
.sf-react.liked{color:#ef4444}
.sf-stats{padding:0 20px 8px;font-size:14px;font-weight:600;color:#1e293b}
.sf-view-comments{padding:0 20px 12px;font-size:14px;color:#64748b;cursor:pointer}
.sf-view-comments:hover{color:#3b82f6}
.sf-comments{display:none;padding:0 20px 12px}
.sf-comments.show{display:block}
.sf-cmt{display:flex;gap:10px;margin-bottom:12px}
.sf-cmt-av{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}
.sf-cmt-text{font-size:14px;line-height:1.4;color:#334155}
.sf-cmt-text b{font-weight:600;color:#1e293b}
.sf-cmt-time{font-size:12px;color:#94a3b8;margin-top:2px}
.sf-cmt-form{display:flex;gap:12px;padding:12px 20px;border-top:1px solid #f1f5f9;align-items:center}
.sf-cmt-input{flex:1;border:none;font-size:14px;outline:none;color:#1e293b}
.sf-cmt-input::placeholder{color:#94a3b8}
.sf-cmt-btn{background:none;border:none;color:#3b82f6;font-weight:600;font-size:14px;cursor:pointer}
.sf-cmt-btn:hover{color:#2563eb}
.sf-empty{padding:60px 20px;text-align:center}
.sf-empty-icon{font-size:48px;margin-bottom:16px;opacity:0.5}
.sf-empty-title{font-size:18px;font-weight:600;color:#1e293b;margin-bottom:6px}
.sf-empty-text{font-size:14px;color:#64748b}
.sf-modal{display:none;position:fixed;inset:0;background:rgba(15,23,42,0.6);z-index:9999;align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(4px)}
.sf-modal.open{display:flex}
.sf-modal-box{background:#fff;border-radius:20px;width:100%;max-width:440px;overflow:hidden;animation:slideUp 0.2s ease}
@keyframes slideUp{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
.sf-modal-head{display:flex;align-items:center;justify-content:space-between;padding:20px;border-bottom:1px solid #f1f5f9}
.sf-modal-title{font-weight:600;font-size:17px;color:#1e293b}
.sf-modal-x{background:none;border:none;font-size:24px;color:#94a3b8;cursor:pointer;line-height:1}
.sf-modal-x:hover{color:#64748b}
.sf-modal-body{padding:20px}
.sf-field{margin-bottom:16px}
.sf-label{display:block;font-weight:500;font-size:13px;color:#64748b;margin-bottom:6px}
.sf-text-input{width:100%;padding:12px 14px;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#1e293b;outline:none;transition:border-color 0.15s}
.sf-text-input:focus{border-color:#3b82f6}
.sf-textarea-input{width:100%;padding:12px 14px;border:1px solid #e2e8f0;border-radius:10px;font-size:14px;color:#1e293b;outline:none;resize:vertical;min-height:80px;font-family:inherit}
.sf-textarea-input:focus{border-color:#3b82f6}
.sf-upload-area{border:2px dashed #e2e8f0;border-radius:12px;padding:32px;text-align:center;cursor:pointer;transition:all 0.15s}
.sf-upload-area:hover{border-color:#3b82f6;background:#f8faff}
.sf-upload-area input{display:none}
.sf-upload-icon{font-size:32px;margin-bottom:8px}
.sf-upload-text{font-size:14px;color:#64748b}
.sf-upload-text span{color:#3b82f6;font-weight:500}
.sf-img-preview{width:100%;max-height:150px;object-fit:contain;border-radius:10px;margin-top:12px;display:none}
.sf-img-preview.show{display:block}
.sf-progress{height:4px;background:#e2e8f0;border-radius:2px;margin-top:12px;overflow:hidden;display:none}
.sf-progress.show{display:block}
.sf-progress-bar{height:100%;background:#3b82f6;width:0;transition:width 0.2s}
.sf-modal-btns{display:flex;gap:10px;margin-top:20px}
.sf-modal-btn{flex:1;padding:12px;border-radius:10px;font-weight:600;font-size:14px;cursor:pointer;transition:all 0.15s}
.sf-modal-btn-primary{background:#3b82f6;color:#fff;border:none}
.sf-modal-btn-primary:hover{background:#2563eb}
.sf-modal-btn-secondary{background:#f1f5f9;color:#475569;border:none}
.sf-modal-btn-secondary:hover{background:#e2e8f0}
`;
$("<style>").text(css).appendTo("head");

// SVG icons
var icons={
photo:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><circle cx="8.5" cy="8.5" r="1.5"/><path d="M21 15l-5-5L5 21"/></svg>',
video:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="23 7 16 12 23 17 23 7"/><rect x="1" y="5" width="15" height="14" rx="2"/></svg>',
loc:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0118 0z"/><circle cx="12" cy="10" r="3"/></svg>',
emoji:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M8 14s1.5 2 4 2 4-2 4-2"/><line x1="9" y1="9" x2="9.01" y2="9"/><line x1="15" y1="9" x2="15.01" y2="9"/></svg>',
gif:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="4" width="20" height="16" rx="2"/><text x="12" y="14" text-anchor="middle" font-size="6" fill="currentColor" stroke="none">GIF</text></svg>'
};

var h='<div class="sf-wrap">';
h+='<div class="sf-card sf-compose">';
h+='<div class="sf-compose-row"><div class="sf-avatar" id="user-avatar">'+av(ud.photo,user,16)+'</div>';
h+='<div class="sf-input-wrap"><textarea class="sf-input" id="post-input" placeholder="What\'s on your mind?"></textarea>';
h+='<div class="sf-preview" id="post-preview"></div>';
h+='<div class="sf-loc" id="post-loc"><span></span><button id="rm-loc">×</button></div></div></div>';
h+='<div class="sf-divider"></div>';
h+='<div class="sf-actions"><div class="sf-btns">';
h+='<button class="sf-btn sf-btn-photo" id="btn-photo" title="Photo">'+icons.photo+'</button>';
h+='<button class="sf-btn sf-btn-video" title="Video">'+icons.video+'</button>';
h+='<button class="sf-btn sf-btn-loc" id="btn-loc" title="Location">'+icons.loc+'</button>';
h+='<button class="sf-btn sf-btn-emoji" id="btn-emoji" title="Emoji">'+icons.emoji+'</button>';
h+='<button class="sf-btn sf-btn-gif" title="GIF">'+icons.gif+'</button>';
h+='</div><button class="sf-post-btn" id="btn-post" disabled>Post</button></div></div>';
h+='<div id="feed"></div></div>';

// Modal
h+='<div class="sf-modal" id="modal-photo"><div class="sf-modal-box"><div class="sf-modal-head"><span class="sf-modal-title">Add Photo</span><button class="sf-modal-x" data-close="modal-photo">×</button></div><div class="sf-modal-body">';
h+='<div class="sf-upload-area" id="upload-photo"><input type="file" accept="image/*"><div class="sf-upload-icon">📷</div><div class="sf-upload-text">Click or drag to <span>upload</span></div></div>';
h+='<div class="sf-progress" id="prog-photo"><div class="sf-progress-bar"></div></div>';
h+='<img class="sf-img-preview" id="prev-photo">';
h+='<div class="sf-field" style="margin-top:16px"><div class="sf-label">Or paste URL</div><input class="sf-text-input" id="url-photo" placeholder="https://..."></div>';
h+='<div class="sf-modal-btns"><button class="sf-modal-btn sf-modal-btn-secondary" data-close="modal-photo">Cancel</button><button class="sf-modal-btn sf-modal-btn-primary" id="add-photo">Add Photo</button></div></div></div></div>';

h+='<div class="sf-modal" id="modal-profile"><div class="sf-modal-box"><div class="sf-modal-head"><span class="sf-modal-title">Edit Profile</span><button class="sf-modal-x" data-close="modal-profile">×</button></div><div class="sf-modal-body">';
h+='<div class="sf-field"><div class="sf-label">Profile Photo</div><div class="sf-upload-area" id="upload-pic"><input type="file" accept="image/*"><div class="sf-upload-icon">👤</div><div class="sf-upload-text">Click to <span>upload</span></div></div><div class="sf-progress" id="prog-pic"><div class="sf-progress-bar"></div></div><img class="sf-img-preview" id="prev-pic"></div>';
h+='<div class="sf-field"><div class="sf-label">Bio</div><textarea class="sf-textarea-input" id="inp-bio" placeholder="Tell us about yourself...">'+esc(ud.bio)+'</textarea></div>';
h+='<div class="sf-modal-btns"><button class="sf-modal-btn sf-modal-btn-secondary" data-close="modal-profile">Cancel</button><button class="sf-modal-btn sf-modal-btn-primary" id="save-profile">Save</button></div></div></div></div>';

$("#social-app").html(h);
var $a=$("#social-app");

$a.on("click","[data-close]",function(){cm($(this).data("close"));});
$a.on("click",".sf-modal",function(e){if($(e.target).hasClass("sf-modal"))cm(this.id);});

function setupUpload(zoneId,prevId,progId,key){
  var $z=$("#"+zoneId),$i=$z.find("input"),$pv=$("#"+prevId),$pr=$("#"+progId);
  $z.on("click",function(){$i.click();});
  $i.on("change",function(){if(this.files[0]){uf[key]=this.files[0];var r=new FileReader();r.onload=function(e){$pv.attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});
  return{reset:function(){uf[key]=null;$pv.removeClass("show");$pr.removeClass("show").find(".sf-progress-bar").css("width",0);$i.val("");},prog:function(p){$pr.addClass("show").find(".sf-progress-bar").css("width",p+"%");}};
}
var upPhoto=setupUpload("upload-photo","prev-photo","prog-photo","photo");
var upPic=setupUpload("upload-pic","prev-pic","prog-pic","pic");

$("#url-photo").on("input",function(){var v=$(this).val();if(v)$("#prev-photo").attr("src",v).addClass("show");else $("#prev-photo").removeClass("show");});

$("#btn-photo").on("click",function(){upPhoto.reset();$("#url-photo").val("");om("modal-photo");});
$("#add-photo").on("click",function(){
  var url=$("#url-photo").val().trim();
  if(url){pp.image=url;showPreview(url);cm("modal-photo");}
  else if(uf.photo){upload(uf.photo,"Post",upPhoto.prog).then(function(u){pp.image=u;showPreview(u);cm("modal-photo");upPhoto.reset();});}
  else alert("Select or paste an image");
});
function showPreview(u){$("#post-preview").addClass("show").html('<img src="'+u+'"><button class="sf-preview-x" id="rm-preview">×</button>');upd();}
$a.on("click","#rm-preview",function(){pp.image="";$("#post-preview").removeClass("show").html("");upd();});

$("#btn-loc").on("click",function(){var l=prompt("Location:");if(l){pp.location=l;$("#post-loc").addClass("show").find("span").text("📍 "+l);}});
$a.on("click","#rm-loc",function(){pp.location="";$("#post-loc").removeClass("show");});
$("#btn-emoji").on("click",function(){var e=prompt("Emoji:");if(e){var t=$("#post-input")[0];t.value=t.value.slice(0,t.selectionStart)+e+t.value.slice(t.selectionEnd);t.focus();upd();}});

$("#post-input").on("input",upd);
function upd(){$("#btn-post").prop("disabled",!$("#post-input").val().trim()&&!pp.image);}

$("#btn-post").on("click",function(){
  var t=$("#post-input").val().trim();if(!t&&!pp.image)return;
  var $b=$(this).prop("disabled",true).text("...");
  var p={action:"socialfeed",sfaction:"createpost",content:t||"(media)"};
  if(pp.image)p.image_url=pp.image;
  if(pp.location)p.location=pp.location;
  api.postWithToken("csrf",p).then(function(){
    $("#post-input").val("");pp={image:"",location:""};
    $("#post-preview,#post-loc").removeClass("show").html("");
    $b.prop("disabled",true).text("Post");loadFeed();
  }).fail(function(){$b.prop("disabled",false).text("Post");});
});

$("#save-profile").on("click",function(){
  ud.bio=$("#inp-bio").val().trim();
  localStorage.setItem("sf_bio_"+user,ud.bio);
  if(uf.pic){upload(uf.pic,"Pic",upPic.prog).then(function(u){
    ud.photo=u;localStorage.setItem("sf_photo_"+user,u);
    $("#user-avatar").html(av(u,user,16));cm("modal-profile");upPic.reset();
  });}else cm("modal-profile");
});

$a.on("click",".sf-react[data-id]",function(){api.postWithToken("csrf",{action:"socialfeed",sfaction:"react",post_id:$(this).data("id"),reaction_type:"like"}).then(loadFeed);});
$a.on("click",".sf-post-menu[data-del]",function(){if(confirm("Delete?")){api.postWithToken("csrf",{action:"socialfeed",sfaction:"deletepost",post_id:$(this).data("del")}).then(loadFeed);}});
$a.on("click",".sf-view-comments",function(){var id=$(this).data("id"),$c=$("#cmt-"+id);$c.toggleClass("show");if($c.hasClass("show"))loadComments(id);});
$a.on("keypress",".sf-cmt-input",function(e){if(e.which===13){var $i=$(this),t=$i.val().trim(),id=$i.data("id");if(t){$i.val("").prop("disabled",true);api.postWithToken("csrf",{action:"socialfeed",sfaction:"comment",post_id:id,content:t}).then(function(){$i.prop("disabled",false);loadComments(id);loadFeed();});}}});

function loadFeed(){
  api.get({action:"socialfeed",sfaction:"getposts",limit:20}).then(function(r){
    var posts=(r.socialfeed&&r.socialfeed.posts)||[];
    if(!posts.length){$("#feed").html('<div class="sf-card"><div class="sf-empty"><div class="sf-empty-icon">📷</div><div class="sf-empty-title">No posts yet</div><div class="sf-empty-text">Share something to get started</div></div></div>');return;}
    var h=posts.map(function(p){
      var pic=localStorage.getItem("sf_photo_"+p.username)||"";
      var likes=0;for(var k in p.reaction_counts)likes+=p.reaction_counts[k];
      var media="";
      if(p.image_url)media='<div class="sf-post-media"><img src="'+esc(p.image_url)+'"></div>';
      else if(p.video_url&&p.video_url.match(/youtube|youtu\.be/)){var vid=(p.video_url.match(/(?:v=|youtu\.be\/)([^&]+)/)||[])[1];if(vid)media='<div class="sf-post-media"><iframe src="https://www.youtube.com/embed/'+vid+'" allowfullscreen></iframe></div>';}
      var del=p.username===user?'<button class="sf-post-menu" data-del="'+p.id+'">×</button>':"";
      var liked=p.user_reaction==="like"?" liked":"";
      return '<div class="sf-card sf-post"><div class="sf-post-head"><div class="sf-avatar">'+av(pic,p.username,14)+'</div><div class="sf-post-info"><div class="sf-post-name">'+esc(p.username)+'</div><div class="sf-post-time">'+ago(p.created)+'</div></div>'+del+'</div>'+(p.content&&p.content!=="(media)"?'<div class="sf-post-body">'+esc(p.content)+'</div>':'')+media+'<div class="sf-post-foot"><button class="sf-react'+liked+'" data-id="'+p.id+'">'+(liked?"❤️":"🤍")+'</button><button class="sf-react">💬</button><button class="sf-react">↗</button></div>'+(likes?'<div class="sf-stats">'+likes+' like'+(likes>1?'s':'')+'</div>':'')+(p.comments?'<div class="sf-view-comments" data-id="'+p.id+'">View '+p.comments+' comment'+(p.comments>1?'s':'')+'</div>':'')+'<div class="sf-comments" id="cmt-'+p.id+'"></div><div class="sf-cmt-form"><input class="sf-cmt-input" data-id="'+p.id+'" placeholder="Add a comment..."><button class="sf-cmt-btn">Post</button></div></div>';
    }).join("");
    $("#feed").html(h);
  });
}

function loadComments(id){
  api.get({action:"socialfeed",sfaction:"getcomments",post_id:id}).then(function(r){
    var cmts=(r.socialfeed&&r.socialfeed.comments)||[];
    var h=cmts.map(function(c){
      var pic=localStorage.getItem("sf_photo_"+c.username)||"";
      return '<div class="sf-cmt"><div class="sf-cmt-av">'+av(pic,c.username,11)+'</div><div><div class="sf-cmt-text"><b>'+esc(c.username)+'</b> '+esc(c.content)+'</div><div class="sf-cmt-time">'+ago(c.created)+'</div></div></div>';
    }).join("");
    $("#cmt-"+id).html(h||'<div style="padding:8px 0;color:#94a3b8;font-size:14px">No comments yet</div>');
  });
}

loadFeed();
});
}