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 v7 - Polished Modern Design */
/* SocialFeed v8 - Facebook-style Profile */
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)||""};
var ud={photo:localStorage.getItem("sf_photo_"+user)||"",cover:localStorage.getItem("sf_cover_"+user)||"",bio:localStorage.getItem("sf_bio_"+user)||"",location:localStorage.getItem("sf_location_"+user)||""};
var pp={image:"",location:""},uf={};
var pp={image:"",location:""},uf={};


function gi(n){return(n||"?").charAt(0).toUpperCase();}
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"Just 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)+'">':'<div class="sf-av-placeholder" style="font-size:'+s+'px">'+gi(n)+'</div>';}
function av(p,n,s){return p?'<img src="'+esc(p)+'">':'<div class="fb-avatar-ph" style="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");}
Line 19: Line 19:
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
[class*="wikibox"]{display:none!important}
[class*="wikibox"]{display:none!important}
#social-app{font-family:'Inter',system-ui,-apple-system,sans-serif;background:linear-gradient(180deg,#f0f2f5 0%,#e4e6e9 100%);min-height:100vh;padding:32px 20px}
#social-app{font-family:'Segoe UI',Helvetica,Arial,sans-serif;background:#f0f2f5;min-height:100vh;margin:-20px;padding:0}
#social-app *{box-sizing:border-box;margin:0;padding:0}
#social-app *{box-sizing:border-box;margin:0;padding:0}
.sf-container{max-width:600px;margin:0 auto}


/* Card styles */
/* Cover Section */
.sf-card{background:#fff;border-radius:16px;box-shadow:0 2px 8px rgba(0,0,0,0.08),0 1px 2px rgba(0,0,0,0.06);margin-bottom:20px}
.fb-cover-section{background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.1)}
.fb-cover-wrap{max-width:940px;margin:0 auto}
.fb-cover{height:350px;background:linear-gradient(135deg,#1877f2,#42b72a);border-radius:0 0 8px 8px;position:relative;overflow:hidden}
.fb-cover img{width:100%;height:100%;object-fit:cover}
.fb-cover-btn{position:absolute;bottom:16px;right:16px;background:#fff;border:none;padding:8px 16px;border-radius:6px;font-weight:600;font-size:14px;cursor:pointer;display:flex;align-items:center;gap:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}
.fb-cover-btn:hover{background:#f0f0f0}


/* Composer */
/* Profile Header */
.sf-composer{padding:24px}
.fb-profile-header{display:flex;align-items:flex-end;padding:0 16px 16px;margin-top:-40px;position:relative}
.sf-composer-header{display:flex;gap:16px;margin-bottom:20px}
.fb-profile-pic-wrap{position:relative;margin-right:16px}
.sf-avatar{width:52px;height:52px;border-radius:50%;overflow:hidden;flex-shrink:0;border:2px solid #e8e8e8}
.fb-profile-pic{width:168px;height:168px;border-radius:50%;border:4px solid #fff;overflow:hidden;background:#fff;cursor:pointer;box-shadow:0 2px 4px rgba(0,0,0,0.1)}
.sf-avatar img{width:100%;height:100%;object-fit:cover}
.fb-profile-pic img{width:100%;height:100%;object-fit:cover}
.sf-av-placeholder{width:100%;height:100%;background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700}
.fb-avatar-ph{width:100%;height:100%;background:linear-gradient(135deg,#1877f2,#42b72a);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700}
.sf-composer-input{flex:1;background:#f5f7fa;border-radius:24px;padding:14px 20px;border:none;font-size:16px;color:#1a1a2e;outline:none;resize:none;min-height:52px;font-family:inherit;line-height:1.4}
.fb-camera-btn{position:absolute;bottom:8px;right:8px;width:36px;height:36px;border-radius:50%;background:#e4e6eb;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}
.sf-composer-input::placeholder{color:#8e8e8e}
.fb-camera-btn:hover{background:#d8dadf}
.sf-composer-input:focus{background:#eef1f5}


.sf-preview-area{margin:16px 0;display:none}
.fb-profile-info{flex:1;padding-bottom:16px}
.sf-preview-area.show{display:block}
.fb-profile-name{font-size:32px;font-weight:700;color:#050505}
.sf-preview-area img{width:100%;border-radius:12px;max-height:300px;object-fit:cover}
.fb-profile-stats{font-size:15px;color:#65676b;margin-top:4px}
.sf-preview-remove{position:absolute;top:12px;right:12px;width:32px;height:32px;border-radius:50%;background:rgba(0,0,0,0.7);color:#fff;border:none;cursor:pointer;font-size:18px}
.fb-profile-friends{display:flex;margin-top:8px}
.sf-preview-wrap{position:relative}
.fb-friend-avatar{width:32px;height:32px;border-radius:50%;border:2px solid #fff;margin-left:-8px;overflow:hidden;background:#e4e6eb}
.fb-friend-avatar:first-child{margin-left:0}


.sf-location-tag{background:#e8f5e9;color:#2e7d32;padding:8px 14px;border-radius:20px;font-size:14px;display:inline-flex;align-items:center;gap:8px;margin:12px 0;display:none}
.fb-profile-actions{display:flex;gap:8px;padding-bottom:16px}
.sf-location-tag.show{display:inline-flex}
.fb-btn{padding:10px 20px;border-radius:6px;font-weight:600;font-size:15px;cursor:pointer;display:flex;align-items:center;gap:6px;border:none}
.sf-location-tag button{background:none;border:none;color:#666;cursor:pointer;font-size:16px;margin-left:4px}
.fb-btn-primary{background:#1877f2;color:#fff}
.fb-btn-primary:hover{background:#166fe5}
.fb-btn-secondary{background:#e4e6eb;color:#050505}
.fb-btn-secondary:hover{background:#d8dadf}


.sf-composer-divider{height:1px;background:#eee;margin:20px 0}
/* Tabs */
.fb-tabs-wrap{border-top:1px solid #ddd;margin-top:4px}
.fb-tabs{display:flex;max-width:940px;margin:0 auto;padding:0 16px}
.fb-tab{padding:16px 20px;font-size:15px;font-weight:600;color:#65676b;cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-1px}
.fb-tab:hover{background:#f0f2f5;border-radius:8px 8px 0 0}
.fb-tab.active{color:#1877f2;border-bottom-color:#1877f2}


.sf-composer-actions{display:flex;align-items:center;justify-content:space-between}
/* Main Content */
.sf-action-buttons{display:flex;gap:8px}
.fb-main{max-width:908px;margin:16px auto;display:flex;gap:16px;padding:0 16px}
.sf-action-btn{width:48px;height:48px;border-radius:50%;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:20px;transition:transform 0.2s,box-shadow 0.2s}
.fb-sidebar{width:360px;flex-shrink:0}
.sf-action-btn:hover{transform:scale(1.1);box-shadow:0 4px 12px rgba(0,0,0,0.15)}
.fb-feed{flex:1;min-width:0}
.sf-action-btn.photo{background:linear-gradient(135deg,#4facfe 0%,#00f2fe 100%);color:#fff}
.sf-action-btn.video{background:linear-gradient(135deg,#f093fb 0%,#f5576c 100%);color:#fff}
.sf-action-btn.location{background:linear-gradient(135deg,#43e97b 0%,#38f9d7 100%);color:#fff}
.sf-action-btn.emoji{background:linear-gradient(135deg,#fa709a 0%,#fee140 100%);color:#fff}
.sf-action-btn.gif{background:linear-gradient(135deg,#a18cd1 0%,#fbc2eb 100%);color:#fff}


.sf-post-button{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none;padding:14px 32px;border-radius:25px;font-weight:600;font-size:15px;cursor:pointer;transition:transform 0.2s,box-shadow 0.2s}
/* Cards */
.sf-post-button:hover:not(:disabled){transform:translateY(-2px);box-shadow:0 6px 20px rgba(102,126,234,0.4)}
.fb-card{background:#fff;border-radius:8px;box-shadow:0 1px 2px rgba(0,0,0,0.1);margin-bottom:16px}
.sf-post-button:disabled{opacity:0.5;cursor:not-allowed}
.fb-card-header{padding:16px;font-size:20px;font-weight:700;color:#050505;display:flex;justify-content:space-between;align-items:center}
.fb-card-header a{font-size:14px;font-weight:500;color:#1877f2;text-decoration:none}


/* Posts */
/* Intro Card */
.sf-post-card{overflow:hidden}
.fb-intro-item{display:flex;align-items:center;gap:12px;padding:8px 16px;font-size:15px;color:#050505}
.sf-post-header{display:flex;align-items:center;gap:14px;padding:20px 24px}
.fb-intro-icon{font-size:20px;color:#65676b;width:24px;text-align:center}
.sf-post-avatar{width:48px;height:48px;border-radius:50%;overflow:hidden;border:2px solid #eee}
.fb-intro-btn{width:calc(100% - 32px);margin:8px 16px 16px;padding:10px;background:#e4e6eb;border:none;border-radius:6px;font-weight:600;font-size:15px;color:#050505;cursor:pointer}
.sf-post-avatar img{width:100%;height:100%;object-fit:cover}
.fb-intro-btn:hover{background:#d8dadf}
.sf-post-info{flex:1}
.sf-post-author{font-weight:600;font-size:15px;color:#1a1a2e}
.sf-post-meta{font-size:13px;color:#8e8e8e;margin-top:2px}
.sf-post-menu{width:36px;height:36px;border-radius:50%;background:#f5f5f5;border:none;cursor:pointer;font-size:16px;color:#666}
.sf-post-menu:hover{background:#eee}


.sf-post-content{padding:0 24px 20px;font-size:16px;line-height:1.6;color:#333}
/* Composer */
.sf-post-media{background:#f5f5f5}
.fb-composer{padding:16px}
.sf-post-media img{width:100%;display:block}
.fb-composer-top{display:flex;gap:12px;padding-bottom:12px;border-bottom:1px solid #ced0d4}
.sf-post-media video{width:100%}
.fb-composer-avatar{width:40px;height:40px;border-radius:50%;overflow:hidden}
.sf-post-media iframe{width:100%;aspect-ratio:16/9;border:none}
.fb-composer-avatar img{width:100%;height:100%;object-fit:cover}
.fb-composer-input{flex:1;background:#f0f2f5;border:none;border-radius:20px;padding:10px 16px;font-size:17px;color:#050505;cursor:pointer;text-align:left}
.fb-composer-input:hover{background:#e4e6eb}
.fb-composer-input::placeholder{color:#65676b}
.fb-composer-actions{display:flex;padding-top:12px}
.fb-composer-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border:none;background:none;border-radius:8px;font-size:15px;font-weight:600;color:#65676b;cursor:pointer}
.fb-composer-btn:hover{background:#f0f2f5}
.fb-composer-btn .icon{font-size:24px}
.fb-composer-btn.live .icon{color:#f3425f}
.fb-composer-btn.photo .icon{color:#45bd62}
.fb-composer-btn.feeling .icon{color:#f7b928}


.sf-post-reactions{display:flex;gap:8px;padding:16px 24px;border-top:1px solid #f0f0f0}
/* Post */
.sf-reaction-btn{width:44px;height:44px;border-radius:50%;background:#f5f7fa;border:none;cursor:pointer;font-size:20px;transition:all 0.2s}
.fb-post-header{display:flex;gap:12px;padding:16px}
.sf-reaction-btn:hover{background:#eef1f5;transform:scale(1.15)}
.fb-post-avatar{width:40px;height:40px;border-radius:50%;overflow:hidden}
.sf-reaction-btn.liked{background:#ffe5e5}
.fb-post-avatar img{width:100%;height:100%;object-fit:cover}
.fb-post-meta{flex:1}
.fb-post-author{font-weight:600;font-size:15px;color:#050505}
.fb-post-time{font-size:13px;color:#65676b}
.fb-post-menu{width:36px;height:36px;border-radius:50%;background:none;border:none;cursor:pointer;font-size:20px;color:#65676b}
.fb-post-menu:hover{background:#f0f2f5}
.fb-post-content{padding:0 16px 16px;font-size:15px;line-height:1.5;color:#050505}
.fb-post-media img{width:100%}
.fb-post-stats{display:flex;justify-content:space-between;padding:12px 16px;font-size:15px;color:#65676b;border-bottom:1px solid #ced0d4}
.fb-post-actions{display:flex;padding:4px 16px}
.fb-post-action{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border:none;background:none;border-radius:4px;font-size:15px;font-weight:600;color:#65676b;cursor:pointer}
.fb-post-action:hover{background:#f0f2f5}
.fb-post-action.liked{color:#1877f2}
.fb-post-comments{padding:8px 16px;border-top:1px solid #ced0d4;display:none}
.fb-post-comments.show{display:block}
.fb-comment{display:flex;gap:8px;margin-bottom:8px}
.fb-comment-avatar{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}
.fb-comment-avatar img{width:100%;height:100%;object-fit:cover}
.fb-comment-bubble{background:#f0f2f5;padding:8px 12px;border-radius:18px}
.fb-comment-author{font-weight:600;font-size:13px;color:#050505}
.fb-comment-text{font-size:15px;color:#050505}
.fb-comment-form{display:flex;gap:8px;padding:8px 16px}
.fb-comment-input{flex:1;background:#f0f2f5;border:none;border-radius:20px;padding:8px 12px;font-size:15px;outline:none}
.fb-comment-input::placeholder{color:#65676b}


.sf-post-stats{padding:8px 24px;font-size:14px;font-weight:600;color:#333}
/* Empty */
.sf-post-comments-link{padding:8px 24px 16px;font-size:14px;color:#8e8e8e;cursor:pointer}
.fb-empty{padding:60px;text-align:center}
.sf-post-comments-link:hover{color:#667eea}
.fb-empty-icon{font-size:60px;margin-bottom:16px}
.fb-empty-title{font-size:20px;font-weight:700;color:#050505;margin-bottom:8px}
.fb-empty-text{font-size:15px;color:#65676b}


.sf-comments-list{padding:0 24px 16px;display:none;max-height:250px;overflow-y:auto}
/* Modal */
.sf-comments-list.show{display:block}
.fb-modal{display:none;position:fixed;inset:0;background:rgba(255,255,255,0.8);z-index:9999;align-items:center;justify-content:center}
.sf-comment{display:flex;gap:12px;margin-bottom:14px}
.fb-modal.open{display:flex}
.sf-comment-avatar{width:36px;height:36px;border-radius:50%;overflow:hidden;flex-shrink:0}
.fb-modal-box{background:#fff;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,0.2);width:100%;max-width:500px}
.sf-comment-avatar img{width:100%;height:100%;object-fit:cover}
.fb-modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #ddd}
.sf-comment-bubble{background:#f5f7fa;padding:12px 16px;border-radius:18px;flex:1}
.fb-modal-title{font-size:20px;font-weight:700}
.sf-comment-author{font-weight:600;font-size:13px;color:#1a1a2e}
.fb-modal-close{width:36px;height:36px;border-radius:50%;background:#e4e6eb;border:none;font-size:20px;cursor:pointer}
.sf-comment-text{font-size:14px;color:#333;margin-top:4px;line-height:1.4}
.fb-modal-close:hover{background:#d8dadf}
.sf-comment-time{font-size:12px;color:#8e8e8e;margin-top:6px;margin-left:52px}
.fb-modal-body{padding:16px}
.fb-textarea{width:100%;min-height:120px;border:none;font-size:24px;resize:none;outline:none}
.fb-textarea::placeholder{color:#65676b}
.fb-modal-footer{padding:16px;border-top:1px solid #ddd}
.fb-modal-post-btn{width:100%;padding:12px;background:#1877f2;color:#fff;border:none;border-radius:6px;font-size:15px;font-weight:600;cursor:pointer}
.fb-modal-post-btn:disabled{background:#e4e6eb;color:#bcc0c4}
.fb-upload-area{border:1px solid #ddd;border-radius:8px;padding:8px;margin-top:12px}
.fb-upload-zone{background:#f7f8fa;border-radius:8px;padding:32px;text-align:center;cursor:pointer}
.fb-upload-zone:hover{background:#ebedf0}
.fb-upload-zone input{display:none}
.fb-upload-icon{font-size:40px;margin-bottom:8px}
.fb-upload-text{font-size:17px;font-weight:600;color:#050505}
.fb-upload-hint{font-size:12px;color:#65676b}
.fb-preview-img{width:100%;border-radius:8px;margin-top:12px;display:none}
.fb-preview-img.show{display:block}


.sf-comment-form{display:flex;gap:12px;padding:16px 24px;border-top:1px solid #f0f0f0;align-items:center}
@media(max-width:900px){
.sf-comment-input{flex:1;background:#f5f7fa;border:none;border-radius:24px;padding:12px 18px;font-size:14px;outline:none}
.fb-sidebar{display:none}
.sf-comment-input::placeholder{color:#8e8e8e}
.fb-main{padding:0 8px}
.sf-comment-input:focus{background:#eef1f5}
.fb-profile-header{flex-direction:column;align-items:center;text-align:center}
.sf-comment-submit{background:none;border:none;color:#667eea;font-weight:600;font-size:14px;cursor:pointer}
.fb-profile-pic{width:128px;height:128px}
.sf-comment-submit:hover{color:#764ba2}
.fb-profile-actions{justify-content:center}
 
}
/* Empty state */
.sf-empty{padding:80px 40px;text-align:center}
.sf-empty-visual{width:120px;height:120px;margin:0 auto 24px;background:linear-gradient(135deg,#f5f7fa 0%,#e4e8ec 100%);border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:48px}
.sf-empty-title{font-size:22px;font-weight:600;color:#1a1a2e;margin-bottom:8px}
.sf-empty-text{font-size:15px;color:#8e8e8e;max-width:280px;margin:0 auto}
 
/* Modal */
.sf-modal{display:none;position:fixed;inset:0;background:rgba(0,0,0,0.5);z-index:9999;align-items:center;justify-content:center;padding:20px;backdrop-filter:blur(8px)}
.sf-modal.open{display:flex}
.sf-modal-content{background:#fff;border-radius:20px;width:100%;max-width:480px;overflow:hidden;animation:modalIn 0.25s ease}
@keyframes modalIn{from{opacity:0;transform:scale(0.95)}to{opacity:1;transform:scale(1)}}
.sf-modal-header{display:flex;align-items:center;justify-content:space-between;padding:20px 24px;border-bottom:1px solid #eee}
.sf-modal-title{font-weight:600;font-size:18px;color:#1a1a2e}
.sf-modal-close{width:36px;height:36px;border-radius:50%;background:#f5f5f5;border:none;font-size:20px;cursor:pointer;color:#666}
.sf-modal-close:hover{background:#eee}
.sf-modal-body{padding:24px}
.sf-upload-zone{border:2px dashed #ddd;border-radius:16px;padding:48px 24px;text-align:center;cursor:pointer;transition:all 0.2s}
.sf-upload-zone:hover{border-color:#667eea;background:#f8f9ff}
.sf-upload-zone input{display:none}
.sf-upload-icon{font-size:48px;margin-bottom:12px}
.sf-upload-text{font-size:15px;color:#666}
.sf-upload-text b{color:#667eea}
.sf-url-input{width:100%;padding:14px 18px;border:2px solid #eee;border-radius:12px;font-size:15px;margin-top:20px;outline:none}
.sf-url-input:focus{border-color:#667eea}
.sf-url-input::placeholder{color:#aaa}
.sf-preview-thumb{width:100%;max-height:200px;object-fit:contain;border-radius:12px;margin-top:16px;display:none}
.sf-preview-thumb.show{display:block}
.sf-modal-buttons{display:flex;gap:12px;margin-top:24px}
.sf-modal-btn{flex:1;padding:14px;border-radius:12px;font-weight:600;font-size:15px;cursor:pointer;transition:all 0.2s}
.sf-modal-btn-cancel{background:#f5f5f5;color:#666;border:none}
.sf-modal-btn-cancel:hover{background:#eee}
.sf-modal-btn-confirm{background:linear-gradient(135deg,#667eea 0%,#764ba2 100%);color:#fff;border:none}
.sf-modal-btn-confirm:hover{transform:translateY(-1px);box-shadow:0 4px 12px rgba(102,126,234,0.3)}
`;
`;
$("<style>").text(css).appendTo("head");
$("<style>").text(css).appendTo("head");


var h='<div class="sf-container">';
var h='';
// Cover
h+='<div class="fb-cover-section"><div class="fb-cover-wrap">';
h+='<div class="fb-cover" id="cover-area">'+(ud.cover?'<img src="'+esc(ud.cover)+'">':'')+'<button class="fb-cover-btn" id="edit-cover">📷 Edit cover photo</button></div>';
h+='<div class="fb-profile-header">';
h+='<div class="fb-profile-pic-wrap"><div class="fb-profile-pic" id="profile-pic">'+av(ud.photo,user,64)+'</div><button class="fb-camera-btn" id="edit-pic">📷</button></div>';
h+='<div class="fb-profile-info"><div class="fb-profile-name">'+esc(user.replace(/_/g," "))+'</div><div class="fb-profile-stats"><span id="follower-count">0</span> followers · <span id="following-count">0</span> following</div>';
h+='<div class="fb-profile-friends"><div class="fb-friend-avatar"></div><div class="fb-friend-avatar"></div><div class="fb-friend-avatar"></div><div class="fb-friend-avatar"></div></div></div>';
h+='<div class="fb-profile-actions"><button class="fb-btn fb-btn-primary">➕ Add to story</button><button class="fb-btn fb-btn-secondary" id="edit-profile-btn">✏️ Edit profile</button><button class="fb-btn fb-btn-secondary">⋯</button></div>';
h+='</div>';
h+='<div class="fb-tabs-wrap"><div class="fb-tabs"><div class="fb-tab active">Posts</div><div class="fb-tab">About</div><div class="fb-tab">Friends</div><div class="fb-tab">Photos</div><div class="fb-tab">Videos</div><div class="fb-tab">More ▾</div></div></div>';
h+='</div></div>';


// Composer
// Main content
h+='<div class="sf-card sf-composer">';
h+='<div class="fb-main">';
h+='<div class="sf-composer-header"><div class="sf-avatar" id="my-avatar">'+av(ud.photo,user,20)+'</div>';
 
h+='<textarea class="sf-composer-input" id="post-text" placeholder="What\'s on your mind, '+esc(user.split(/[\s_]/)[0])+'?"></textarea></div>';
// Sidebar
h+='<div class="sf-preview-area" id="post-preview"><div class="sf-preview-wrap"></div></div>';
h+='<div class="fb-sidebar">';
h+='<div class="sf-location-tag" id="post-loc">📍 <span></span><button id="rm-loc">×</button></div>';
h+='<div class="fb-card"><div class="fb-card-header">Intro</div>';
h+='<div class="sf-composer-divider"></div>';
h+='<div id="intro-content">';
h+='<div class="sf-composer-actions"><div class="sf-action-buttons">';
if(ud.bio)h+='<div class="fb-intro-item" style="text-align:center;display:block;padding:16px">'+esc(ud.bio)+'</div>';
h+='<button class="sf-action-btn photo" id="btn-photo" title="Photo">🖼️</button>';
h+='</div>';
h+='<button class="sf-action-btn video" title="Video">🎬</button>';
h+='<button class="fb-intro-btn" id="add-bio">'+(ud.bio?'Edit bio':'Add bio')+'</button>';
h+='<button class="sf-action-btn location" id="btn-loc" title="Location">📍</button>';
h+='<div class="fb-intro-item"><span class="fb-intro-icon">🏠</span><span>Lives in <b>'+(ud.location||'Add location')+'</b></span></div>';
h+='<button class="sf-action-btn emoji" id="btn-emoji" title="Emoji">😊</button>';
h+='<div class="fb-intro-item"><span class="fb-intro-icon">📍</span><span>From <b>Wichita, Kansas</b></span></div>';
h+='<button class="sf-action-btn gif" title="GIF">GIF</button>';
h+='<button class="fb-intro-btn">Edit details</button>';
h+='</div><button class="sf-post-button" id="btn-post" disabled>Post</button></div>';
h+='</div>';
h+='</div>';
h+='</div>';


// Feed
// Feed
h+='<div class="fb-feed">';
h+='<div class="fb-card fb-composer">';
h+='<div class="fb-composer-top"><div class="fb-composer-avatar">'+av(ud.photo,user,16)+'</div>';
h+='<button class="fb-composer-input" id="open-composer">What\'s on your mind, '+esc(user.split(/[\s_]/)[0])+'?</button></div>';
h+='<div class="fb-composer-actions">';
h+='<button class="fb-composer-btn live"><span class="icon">📹</span> Live video</button>';
h+='<button class="fb-composer-btn photo" id="quick-photo"><span class="icon">🖼️</span> Photo/video</button>';
h+='<button class="fb-composer-btn feeling"><span class="icon">😊</span> Feeling/activity</button>';
h+='</div></div>';
h+='<div id="feed"></div>';
h+='<div id="feed"></div>';
h+='</div></div>';
// Composer Modal
h+='<div class="fb-modal" id="composer-modal"><div class="fb-modal-box">';
h+='<div class="fb-modal-header"><span class="fb-modal-title">Create post</span><button class="fb-modal-close" data-close="composer-modal">✕</button></div>';
h+='<div class="fb-modal-body">';
h+='<div style="display:flex;gap:12px;margin-bottom:16px"><div class="fb-composer-avatar">'+av(ud.photo,user,16)+'</div><div><div style="font-weight:600">'+esc(user)+'</div><div style="font-size:12px;color:#65676b">🌐 Public</div></div></div>';
h+='<textarea class="fb-textarea" id="post-text" placeholder="What\'s on your mind, '+esc(user.split(/[\s_]/)[0])+'?"></textarea>';
h+='<img class="fb-preview-img" id="modal-preview">';
h+='<div class="fb-upload-area"><div class="fb-upload-zone" id="modal-upload"><input type="file" accept="image/*"><div class="fb-upload-icon">🖼️</div><div class="fb-upload-text">Add photos/videos</div><div class="fb-upload-hint">or drag and drop</div></div></div>';
h+='</div>';
h+='</div>';
h+='<div class="fb-modal-footer"><button class="fb-modal-post-btn" id="submit-post" disabled>Post</button></div>';
h+='</div></div>';


// Photo Modal
// Edit Profile Modal
h+='<div class="sf-modal" id="photo-modal"><div class="sf-modal-content">';
h+='<div class="fb-modal" id="profile-modal"><div class="fb-modal-box">';
h+='<div class="sf-modal-header"><span class="sf-modal-title">Add Photo</span><button class="sf-modal-close" data-close="photo-modal">×</button></div>';
h+='<div class="fb-modal-header"><span class="fb-modal-title">Edit profile</span><button class="fb-modal-close" data-close="profile-modal"></button></div>';
h+='<div class="sf-modal-body"><div class="sf-upload-zone" id="photo-upload"><input type="file" accept="image/*"><div class="sf-upload-icon">📸</div><div class="sf-upload-text">Drag & drop or <b>browse</b></div></div>';
h+='<div class="fb-modal-body">';
h+='<input class="sf-url-input" id="photo-url" placeholder="Or paste image URL...">';
h+='<div style="margin-bottom:16px"><div style="font-weight:600;margin-bottom:8px">Bio</div><textarea class="fb-textarea" id="bio-input" style="font-size:15px;min-height:60px" placeholder="Describe yourself...">'+esc(ud.bio)+'</textarea></div>';
h+='<img class="sf-preview-thumb" id="photo-preview">';
h+='<div style="margin-bottom:16px"><div style="font-weight:600;margin-bottom:8px">Location</div><input type="text" id="location-input" value="'+esc(ud.location)+'" placeholder="Where do you live?" style="width:100%;padding:12px;border:1px solid #ddd;border-radius:6px;font-size:15px"></div>';
h+='<div class="sf-modal-buttons"><button class="sf-modal-btn sf-modal-btn-cancel" data-close="photo-modal">Cancel</button><button class="sf-modal-btn sf-modal-btn-confirm" id="confirm-photo">Add Photo</button></div></div></div></div>';
h+='<div style="margin-bottom:16px"><div style="font-weight:600;margin-bottom:8px">Profile photo</div><div class="fb-upload-zone" id="pic-upload" style="padding:16px"><input type="file" accept="image/*"><span>Click to upload</span></div><img class="fb-preview-img" id="pic-preview"></div>';
h+='<div><div style="font-weight:600;margin-bottom:8px">Cover photo</div><div class="fb-upload-zone" id="cover-upload" style="padding:16px"><input type="file" accept="image/*"><span>Click to upload</span></div><img class="fb-preview-img" id="cover-preview"></div>';
h+='</div>';
h+='<div class="fb-modal-footer"><button class="fb-modal-post-btn" id="save-profile">Save</button></div>';
h+='</div></div>';


$("#social-app").html(h);
$("#social-app").html(h);
Line 176: Line 231:
// Modal handlers
// Modal handlers
$app.on("click","[data-close]",function(){cm($(this).data("close"));});
$app.on("click","[data-close]",function(){cm($(this).data("close"));});
$app.on("click",".sf-modal",function(e){if($(e.target).hasClass("sf-modal"))cm(this.id);});
$app.on("click",".fb-modal",function(e){if($(e.target).hasClass("fb-modal"))cm(this.id);});


// Upload handler
// Composer
var photoFile=null;
var postFile=null;
$("#photo-upload").on("click",function(){$(this).find("input").click();});
$("#open-composer,#quick-photo").on("click",function(){om("composer-modal");});
$("#photo-upload input").on("change",function(){if(this.files[0]){photoFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#photo-preview").attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});
$("#modal-upload").on("click",function(){$(this).find("input").click();});
$("#photo-url").on("input",function(){var v=$(this).val();if(v)$("#photo-preview").attr("src",v).addClass("show");else if(!photoFile)$("#photo-preview").removeClass("show");});
$("#modal-upload input").on("change",function(){if(this.files[0]){postFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#modal-preview").attr("src",e.target.result).addClass("show");updPost();};r.readAsDataURL(this.files[0]);}});
$("#post-text").on("input",updPost);
function updPost(){$("#submit-post").prop("disabled",!$("#post-text").val().trim()&&!postFile&&!$("#modal-preview").hasClass("show"));}


$("#btn-photo").on("click",function(){photoFile=null;$("#photo-preview").removeClass("show");$("#photo-url").val("");$("#photo-upload input").val("");om("photo-modal");});
$("#submit-post").on("click",function(){
$("#confirm-photo").on("click",function(){
  var t=$("#post-text").val().trim();
  var url=$("#photo-url").val().trim();
  if(!t&&!postFile)return;
  if(url){pp.image=url;showImg(url);cm("photo-modal");}
  var $b=$(this).prop("disabled",true).text("Posting...");
   else if(photoFile){
  function doPost(imgUrl){
    upload(photoFile,"Post",function(){}).then(function(u){pp.image=u;showImg(u);cm("photo-modal");photoFile=null;});
    var p={action:"socialfeed",sfaction:"createpost",content:t||"(photo)"};
  }else{alert("Select or paste an image");}
    if(imgUrl)p.image_url=imgUrl;
    api.postWithToken("csrf",p).then(function(){
      cm("composer-modal");$("#post-text").val("");postFile=null;$("#modal-preview").removeClass("show");$b.prop("disabled",true).text("Post");loadFeed();
    });
  }
   if(postFile){upload(postFile,"Post",function(){}).then(doPost);}else{doPost();}
});
});
function showImg(u){$("#post-preview").addClass("show").find(".sf-preview-wrap").html('<img src="'+u+'"><button class="sf-preview-remove" id="rm-img">×</button>');upd();}
$app.on("click","#rm-img",function(){pp.image="";$("#post-preview").removeClass("show");upd();});


$("#btn-loc").on("click",function(){var l=prompt("Location:");if(l){pp.location=l;$("#post-loc").addClass("show").find("span").text(l);}});
// Profile edit
$app.on("click","#rm-loc",function(){pp.location="";$("#post-loc").removeClass("show");});
var picFile=null,coverFile=null;
$("#btn-emoji").on("click",function(){var e=prompt("Emoji:");if(e){var t=$("#post-text")[0];t.value+=e;t.focus();upd();}});
$("#edit-profile-btn,#edit-pic,#edit-cover,#add-bio").on("click",function(){om("profile-modal");});
$("#pic-upload").on("click",function(){$(this).find("input").click();});
$("#pic-upload input").on("change",function(){if(this.files[0]){picFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#pic-preview").attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});
$("#cover-upload").on("click",function(){$(this).find("input").click();});
$("#cover-upload input").on("change",function(){if(this.files[0]){coverFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#cover-preview").attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});
 
$("#save-profile").on("click",function(){
  var $b=$(this).prop("disabled",true).text("Saving...");
  ud.bio=$("#bio-input").val().trim();
  ud.location=$("#location-input").val().trim();
  localStorage.setItem("sf_bio_"+user,ud.bio);
  localStorage.setItem("sf_location_"+user,ud.location);


$("#post-text").on("input",upd);
  var saves=[];
function upd(){$("#btn-post").prop("disabled",!$("#post-text").val().trim()&&!pp.image);}
  if(picFile)saves.push(upload(picFile,"Pic",function(){}).then(function(u){ud.photo=u;localStorage.setItem("sf_photo_"+user,u);}));
  if(coverFile)saves.push(upload(coverFile,"Cover",function(){}).then(function(u){ud.cover=u;localStorage.setItem("sf_cover_"+user,u);}));


$("#btn-post").on("click",function(){
  $.when.apply($,saves).then(function(){
  var t=$("#post-text").val().trim();if(!t&&!pp.image)return;
    if(ud.photo)$("#profile-pic,.fb-composer-avatar").html(av(ud.photo,user,64));
  var $b=$(this).prop("disabled",true).text("Posting...");
    if(ud.cover)$("#cover-area").html('<img src="'+ud.cover+'"><button class="fb-cover-btn" id="edit-cover">📷 Edit cover photo</button>');
  var p={action:"socialfeed",sfaction:"createpost",content:t||"(media)"};
     $("#intro-content").html(ud.bio?'<div class="fb-intro-item" style="text-align:center;display:block;padding:16px">'+esc(ud.bio)+'</div>':'');
  if(pp.image)p.image_url=pp.image;
     $("#add-bio").text(ud.bio?'Edit bio':'Add bio');
  if(pp.location)p.location=pp.location;
     cm("profile-modal");$b.prop("disabled",false).text("Save");picFile=null;coverFile=null;
  api.postWithToken("csrf",p).then(function(){
  });
     $("#post-text").val("");pp={image:"",location:""};
     $("#post-preview,#post-loc").removeClass("show");
     $b.prop("disabled",true).text("Post");loadFeed();
  }).fail(function(){$b.prop("disabled",false).text("Post");alert("Error posting");});
});
});


// Post interactions
// Posts
$app.on("click",".sf-reaction-btn[data-id]",function(){api.postWithToken("csrf",{action:"socialfeed",sfaction:"react",post_id:$(this).data("id"),reaction_type:"like"}).then(loadFeed);});
$app.on("click",".fb-post-action[data-like]",function(){api.postWithToken("csrf",{action:"socialfeed",sfaction:"react",post_id:$(this).data("like"),reaction_type:"like"}).then(loadFeed);});
$app.on("click",".sf-post-menu[data-del]",function(){if(confirm("Delete this post?")){api.postWithToken("csrf",{action:"socialfeed",sfaction:"deletepost",post_id:$(this).data("del")}).then(loadFeed);}});
$app.on("click",".fb-post-menu[data-del]",function(){if(confirm("Delete post?")){api.postWithToken("csrf",{action:"socialfeed",sfaction:"deletepost",post_id:$(this).data("del")}).then(loadFeed);}});
$app.on("click",".sf-post-comments-link",function(){var id=$(this).data("id"),$c=$("#comments-"+id);$c.toggleClass("show");if($c.hasClass("show"))loadComments(id);});
$app.on("click",".fb-view-comments",function(){var id=$(this).data("id");$("#comments-"+id).toggleClass("show");if($("#comments-"+id).hasClass("show"))loadComments(id);});
$app.on("keypress",".sf-comment-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();});}}});
$app.on("keypress",".fb-comment-input",function(e){if(e.which===13){var $i=$(this),t=$i.val().trim(),id=$i.data("id");if(t){$i.val("");api.postWithToken("csrf",{action:"socialfeed",sfaction:"comment",post_id:id,content:t}).then(function(){loadComments(id);loadFeed();});}}});


function loadFeed(){
function loadFeed(){
   api.get({action:"socialfeed",sfaction:"getposts",limit:20}).then(function(r){
   api.get({action:"socialfeed",sfaction:"getposts",limit:20}).then(function(r){
     var posts=(r.socialfeed&&r.socialfeed.posts)||[];
     var posts=(r.socialfeed&&r.socialfeed.posts)||[];
     if(!posts.length){
     if(!posts.length){$("#feed").html('<div class="fb-card fb-empty"><div class="fb-empty-icon">📷</div><div class="fb-empty-title">No posts yet</div><div class="fb-empty-text">When you share photos, they\'ll appear here.</div></div>');return;}
      $("#feed").html('<div class="sf-card"><div class="sf-empty"><div class="sf-empty-visual">📷</div><div class="sf-empty-title">No posts yet</div><div class="sf-empty-text">Share your first post to get the conversation started!</div></div></div>');
     $("#follower-count").text(posts.length);
      return;
     }
     var h=posts.map(function(p){
     var h=posts.map(function(p){
       var pic=localStorage.getItem("sf_photo_"+p.username)||"";
       var pic=localStorage.getItem("sf_photo_"+p.username)||"";
       var likes=0;for(var k in p.reaction_counts)likes+=p.reaction_counts[k];
       var likes=0;for(var k in p.reaction_counts)likes+=p.reaction_counts[k];
       var media="";
       var media=p.image_url?'<div class="fb-post-media"><img src="'+esc(p.image_url)+'"></div>':"";
      if(p.image_url)media='<div class="sf-post-media"><img src="'+esc(p.image_url)+'"></div>';
       var del=p.username===user?'<button class="fb-post-menu" data-del="'+p.id+'"></button>':"";
      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":"";
       var liked=p.user_reaction==="like"?" liked":"";
       return '<div class="sf-card sf-post-card"><div class="sf-post-header"><div class="sf-post-avatar">'+av(pic,p.username,16)+'</div><div class="sf-post-info"><div class="sf-post-author">'+esc(p.username)+'</div><div class="sf-post-meta">'+ago(p.created)+'</div></div>'+del+'</div>'+(p.content&&p.content!=="(media)"?'<div class="sf-post-content">'+esc(p.content)+'</div>':'')+media+'<div class="sf-post-reactions"><button class="sf-reaction-btn'+liked+'" data-id="'+p.id+'">'+(liked?"❤️":"🤍")+'</button><button class="sf-reaction-btn">💬</button><button class="sf-reaction-btn">↗️</button><button class="sf-reaction-btn">🔖</button></div>'+(likes?'<div class="sf-post-stats">'+likes+' like'+(likes>1?'s':'')+'</div>':'')+(p.comments?'<div class="sf-post-comments-link" data-id="'+p.id+'">View '+p.comments+' comment'+(p.comments>1?'s':'')+'</div>':'')+'<div class="sf-comments-list" id="comments-'+p.id+'"></div><div class="sf-comment-form"><input class="sf-comment-input" data-id="'+p.id+'" placeholder="Write a comment..."><button class="sf-comment-submit">Post</button></div></div>';
       return '<div class="fb-card"><div class="fb-post-header"><div class="fb-post-avatar">'+av(pic,p.username,16)+'</div><div class="fb-post-meta"><div class="fb-post-author">'+esc(p.username)+'</div><div class="fb-post-time">'+ago(p.created)+' · 🌐</div></div>'+del+'</div>'+(p.content&&p.content!=="(photo)"?'<div class="fb-post-content">'+esc(p.content)+'</div>':'')+media+'<div class="fb-post-stats"><span>👍❤️ '+likes+'</span><span class="fb-view-comments" data-id="'+p.id+'" style="cursor:pointer">'+p.comments+' comments</span></div><div class="fb-post-actions"><button class="fb-post-action'+liked+'" data-like="'+p.id+'">'+(liked?'👍 Like':'🤍 Like')+'</button><button class="fb-post-action">💬 Comment</button><button class="fb-post-action">↗️ Share</button></div><div class="fb-post-comments" id="comments-'+p.id+'"></div><div class="fb-comment-form"><div class="fb-comment-avatar">'+av(ud.photo,user,12)+'</div><input class="fb-comment-input" data-id="'+p.id+'" placeholder="Write a comment..."></div></div>';
     }).join("");
     }).join("");
     $("#feed").html(h);
     $("#feed").html(h);
Line 247: Line 311:
     var h=cmts.map(function(c){
     var h=cmts.map(function(c){
       var pic=localStorage.getItem("sf_photo_"+c.username)||"";
       var pic=localStorage.getItem("sf_photo_"+c.username)||"";
       return '<div class="sf-comment"><div class="sf-comment-avatar">'+av(pic,c.username,12)+'</div><div class="sf-comment-bubble"><div class="sf-comment-author">'+esc(c.username)+'</div><div class="sf-comment-text">'+esc(c.content)+'</div></div></div><div class="sf-comment-time">'+ago(c.created)+'</div>';
       return '<div class="fb-comment"><div class="fb-comment-avatar">'+av(pic,c.username,12)+'</div><div class="fb-comment-bubble"><div class="fb-comment-author">'+esc(c.username)+'</div><div class="fb-comment-text">'+esc(c.content)+'</div></div></div>';
     }).join("");
     }).join("");
     $("#comments-"+id).html(h||'<div style="padding:12px 0;color:#8e8e8e;font-size:14px">No comments yet</div>');
     $("#comments-"+id).html(h||'<div style="padding:8px;color:#65676b">No comments yet</div>');
   });
   });
}
}

Revision as of 14:31, 4 February 2026

/* SocialFeed v8 - Facebook-style Profile */
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)||"",cover:localStorage.getItem("sf_cover_"+user)||"",bio:localStorage.getItem("sf_bio_"+user)||"",location:localStorage.getItem("sf_location_"+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"Just 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)+'">':'<div class="fb-avatar-ph" style="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=`
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
[class*="wikibox"]{display:none!important}
#social-app{font-family:'Segoe UI',Helvetica,Arial,sans-serif;background:#f0f2f5;min-height:100vh;margin:-20px;padding:0}
#social-app *{box-sizing:border-box;margin:0;padding:0}

/* Cover Section */
.fb-cover-section{background:#fff;box-shadow:0 1px 2px rgba(0,0,0,0.1)}
.fb-cover-wrap{max-width:940px;margin:0 auto}
.fb-cover{height:350px;background:linear-gradient(135deg,#1877f2,#42b72a);border-radius:0 0 8px 8px;position:relative;overflow:hidden}
.fb-cover img{width:100%;height:100%;object-fit:cover}
.fb-cover-btn{position:absolute;bottom:16px;right:16px;background:#fff;border:none;padding:8px 16px;border-radius:6px;font-weight:600;font-size:14px;cursor:pointer;display:flex;align-items:center;gap:8px;box-shadow:0 2px 4px rgba(0,0,0,0.1)}
.fb-cover-btn:hover{background:#f0f0f0}

/* Profile Header */
.fb-profile-header{display:flex;align-items:flex-end;padding:0 16px 16px;margin-top:-40px;position:relative}
.fb-profile-pic-wrap{position:relative;margin-right:16px}
.fb-profile-pic{width:168px;height:168px;border-radius:50%;border:4px solid #fff;overflow:hidden;background:#fff;cursor:pointer;box-shadow:0 2px 4px rgba(0,0,0,0.1)}
.fb-profile-pic img{width:100%;height:100%;object-fit:cover}
.fb-avatar-ph{width:100%;height:100%;background:linear-gradient(135deg,#1877f2,#42b72a);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:700}
.fb-camera-btn{position:absolute;bottom:8px;right:8px;width:36px;height:36px;border-radius:50%;background:#e4e6eb;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:18px}
.fb-camera-btn:hover{background:#d8dadf}

.fb-profile-info{flex:1;padding-bottom:16px}
.fb-profile-name{font-size:32px;font-weight:700;color:#050505}
.fb-profile-stats{font-size:15px;color:#65676b;margin-top:4px}
.fb-profile-friends{display:flex;margin-top:8px}
.fb-friend-avatar{width:32px;height:32px;border-radius:50%;border:2px solid #fff;margin-left:-8px;overflow:hidden;background:#e4e6eb}
.fb-friend-avatar:first-child{margin-left:0}

.fb-profile-actions{display:flex;gap:8px;padding-bottom:16px}
.fb-btn{padding:10px 20px;border-radius:6px;font-weight:600;font-size:15px;cursor:pointer;display:flex;align-items:center;gap:6px;border:none}
.fb-btn-primary{background:#1877f2;color:#fff}
.fb-btn-primary:hover{background:#166fe5}
.fb-btn-secondary{background:#e4e6eb;color:#050505}
.fb-btn-secondary:hover{background:#d8dadf}

/* Tabs */
.fb-tabs-wrap{border-top:1px solid #ddd;margin-top:4px}
.fb-tabs{display:flex;max-width:940px;margin:0 auto;padding:0 16px}
.fb-tab{padding:16px 20px;font-size:15px;font-weight:600;color:#65676b;cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-1px}
.fb-tab:hover{background:#f0f2f5;border-radius:8px 8px 0 0}
.fb-tab.active{color:#1877f2;border-bottom-color:#1877f2}

/* Main Content */
.fb-main{max-width:908px;margin:16px auto;display:flex;gap:16px;padding:0 16px}
.fb-sidebar{width:360px;flex-shrink:0}
.fb-feed{flex:1;min-width:0}

/* Cards */
.fb-card{background:#fff;border-radius:8px;box-shadow:0 1px 2px rgba(0,0,0,0.1);margin-bottom:16px}
.fb-card-header{padding:16px;font-size:20px;font-weight:700;color:#050505;display:flex;justify-content:space-between;align-items:center}
.fb-card-header a{font-size:14px;font-weight:500;color:#1877f2;text-decoration:none}

/* Intro Card */
.fb-intro-item{display:flex;align-items:center;gap:12px;padding:8px 16px;font-size:15px;color:#050505}
.fb-intro-icon{font-size:20px;color:#65676b;width:24px;text-align:center}
.fb-intro-btn{width:calc(100% - 32px);margin:8px 16px 16px;padding:10px;background:#e4e6eb;border:none;border-radius:6px;font-weight:600;font-size:15px;color:#050505;cursor:pointer}
.fb-intro-btn:hover{background:#d8dadf}

/* Composer */
.fb-composer{padding:16px}
.fb-composer-top{display:flex;gap:12px;padding-bottom:12px;border-bottom:1px solid #ced0d4}
.fb-composer-avatar{width:40px;height:40px;border-radius:50%;overflow:hidden}
.fb-composer-avatar img{width:100%;height:100%;object-fit:cover}
.fb-composer-input{flex:1;background:#f0f2f5;border:none;border-radius:20px;padding:10px 16px;font-size:17px;color:#050505;cursor:pointer;text-align:left}
.fb-composer-input:hover{background:#e4e6eb}
.fb-composer-input::placeholder{color:#65676b}
.fb-composer-actions{display:flex;padding-top:12px}
.fb-composer-btn{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border:none;background:none;border-radius:8px;font-size:15px;font-weight:600;color:#65676b;cursor:pointer}
.fb-composer-btn:hover{background:#f0f2f5}
.fb-composer-btn .icon{font-size:24px}
.fb-composer-btn.live .icon{color:#f3425f}
.fb-composer-btn.photo .icon{color:#45bd62}
.fb-composer-btn.feeling .icon{color:#f7b928}

/* Post */
.fb-post-header{display:flex;gap:12px;padding:16px}
.fb-post-avatar{width:40px;height:40px;border-radius:50%;overflow:hidden}
.fb-post-avatar img{width:100%;height:100%;object-fit:cover}
.fb-post-meta{flex:1}
.fb-post-author{font-weight:600;font-size:15px;color:#050505}
.fb-post-time{font-size:13px;color:#65676b}
.fb-post-menu{width:36px;height:36px;border-radius:50%;background:none;border:none;cursor:pointer;font-size:20px;color:#65676b}
.fb-post-menu:hover{background:#f0f2f5}
.fb-post-content{padding:0 16px 16px;font-size:15px;line-height:1.5;color:#050505}
.fb-post-media img{width:100%}
.fb-post-stats{display:flex;justify-content:space-between;padding:12px 16px;font-size:15px;color:#65676b;border-bottom:1px solid #ced0d4}
.fb-post-actions{display:flex;padding:4px 16px}
.fb-post-action{flex:1;display:flex;align-items:center;justify-content:center;gap:8px;padding:10px;border:none;background:none;border-radius:4px;font-size:15px;font-weight:600;color:#65676b;cursor:pointer}
.fb-post-action:hover{background:#f0f2f5}
.fb-post-action.liked{color:#1877f2}
.fb-post-comments{padding:8px 16px;border-top:1px solid #ced0d4;display:none}
.fb-post-comments.show{display:block}
.fb-comment{display:flex;gap:8px;margin-bottom:8px}
.fb-comment-avatar{width:32px;height:32px;border-radius:50%;overflow:hidden;flex-shrink:0}
.fb-comment-avatar img{width:100%;height:100%;object-fit:cover}
.fb-comment-bubble{background:#f0f2f5;padding:8px 12px;border-radius:18px}
.fb-comment-author{font-weight:600;font-size:13px;color:#050505}
.fb-comment-text{font-size:15px;color:#050505}
.fb-comment-form{display:flex;gap:8px;padding:8px 16px}
.fb-comment-input{flex:1;background:#f0f2f5;border:none;border-radius:20px;padding:8px 12px;font-size:15px;outline:none}
.fb-comment-input::placeholder{color:#65676b}

/* Empty */
.fb-empty{padding:60px;text-align:center}
.fb-empty-icon{font-size:60px;margin-bottom:16px}
.fb-empty-title{font-size:20px;font-weight:700;color:#050505;margin-bottom:8px}
.fb-empty-text{font-size:15px;color:#65676b}

/* Modal */
.fb-modal{display:none;position:fixed;inset:0;background:rgba(255,255,255,0.8);z-index:9999;align-items:center;justify-content:center}
.fb-modal.open{display:flex}
.fb-modal-box{background:#fff;border-radius:8px;box-shadow:0 2px 12px rgba(0,0,0,0.2);width:100%;max-width:500px}
.fb-modal-header{display:flex;align-items:center;justify-content:space-between;padding:16px 20px;border-bottom:1px solid #ddd}
.fb-modal-title{font-size:20px;font-weight:700}
.fb-modal-close{width:36px;height:36px;border-radius:50%;background:#e4e6eb;border:none;font-size:20px;cursor:pointer}
.fb-modal-close:hover{background:#d8dadf}
.fb-modal-body{padding:16px}
.fb-textarea{width:100%;min-height:120px;border:none;font-size:24px;resize:none;outline:none}
.fb-textarea::placeholder{color:#65676b}
.fb-modal-footer{padding:16px;border-top:1px solid #ddd}
.fb-modal-post-btn{width:100%;padding:12px;background:#1877f2;color:#fff;border:none;border-radius:6px;font-size:15px;font-weight:600;cursor:pointer}
.fb-modal-post-btn:disabled{background:#e4e6eb;color:#bcc0c4}
.fb-upload-area{border:1px solid #ddd;border-radius:8px;padding:8px;margin-top:12px}
.fb-upload-zone{background:#f7f8fa;border-radius:8px;padding:32px;text-align:center;cursor:pointer}
.fb-upload-zone:hover{background:#ebedf0}
.fb-upload-zone input{display:none}
.fb-upload-icon{font-size:40px;margin-bottom:8px}
.fb-upload-text{font-size:17px;font-weight:600;color:#050505}
.fb-upload-hint{font-size:12px;color:#65676b}
.fb-preview-img{width:100%;border-radius:8px;margin-top:12px;display:none}
.fb-preview-img.show{display:block}

@media(max-width:900px){
.fb-sidebar{display:none}
.fb-main{padding:0 8px}
.fb-profile-header{flex-direction:column;align-items:center;text-align:center}
.fb-profile-pic{width:128px;height:128px}
.fb-profile-actions{justify-content:center}
}
`;
$("<style>").text(css).appendTo("head");

var h='';
// Cover
h+='<div class="fb-cover-section"><div class="fb-cover-wrap">';
h+='<div class="fb-cover" id="cover-area">'+(ud.cover?'<img src="'+esc(ud.cover)+'">':'')+'<button class="fb-cover-btn" id="edit-cover">📷 Edit cover photo</button></div>';
h+='<div class="fb-profile-header">';
h+='<div class="fb-profile-pic-wrap"><div class="fb-profile-pic" id="profile-pic">'+av(ud.photo,user,64)+'</div><button class="fb-camera-btn" id="edit-pic">📷</button></div>';
h+='<div class="fb-profile-info"><div class="fb-profile-name">'+esc(user.replace(/_/g," "))+'</div><div class="fb-profile-stats"><span id="follower-count">0</span> followers · <span id="following-count">0</span> following</div>';
h+='<div class="fb-profile-friends"><div class="fb-friend-avatar"></div><div class="fb-friend-avatar"></div><div class="fb-friend-avatar"></div><div class="fb-friend-avatar"></div></div></div>';
h+='<div class="fb-profile-actions"><button class="fb-btn fb-btn-primary">➕ Add to story</button><button class="fb-btn fb-btn-secondary" id="edit-profile-btn">✏️ Edit profile</button><button class="fb-btn fb-btn-secondary">⋯</button></div>';
h+='</div>';
h+='<div class="fb-tabs-wrap"><div class="fb-tabs"><div class="fb-tab active">Posts</div><div class="fb-tab">About</div><div class="fb-tab">Friends</div><div class="fb-tab">Photos</div><div class="fb-tab">Videos</div><div class="fb-tab">More ▾</div></div></div>';
h+='</div></div>';

// Main content
h+='<div class="fb-main">';

// Sidebar
h+='<div class="fb-sidebar">';
h+='<div class="fb-card"><div class="fb-card-header">Intro</div>';
h+='<div id="intro-content">';
if(ud.bio)h+='<div class="fb-intro-item" style="text-align:center;display:block;padding:16px">'+esc(ud.bio)+'</div>';
h+='</div>';
h+='<button class="fb-intro-btn" id="add-bio">'+(ud.bio?'Edit bio':'Add bio')+'</button>';
h+='<div class="fb-intro-item"><span class="fb-intro-icon">🏠</span><span>Lives in <b>'+(ud.location||'Add location')+'</b></span></div>';
h+='<div class="fb-intro-item"><span class="fb-intro-icon">📍</span><span>From <b>Wichita, Kansas</b></span></div>';
h+='<button class="fb-intro-btn">Edit details</button>';
h+='</div>';
h+='</div>';

// Feed
h+='<div class="fb-feed">';
h+='<div class="fb-card fb-composer">';
h+='<div class="fb-composer-top"><div class="fb-composer-avatar">'+av(ud.photo,user,16)+'</div>';
h+='<button class="fb-composer-input" id="open-composer">What\'s on your mind, '+esc(user.split(/[\s_]/)[0])+'?</button></div>';
h+='<div class="fb-composer-actions">';
h+='<button class="fb-composer-btn live"><span class="icon">📹</span> Live video</button>';
h+='<button class="fb-composer-btn photo" id="quick-photo"><span class="icon">🖼️</span> Photo/video</button>';
h+='<button class="fb-composer-btn feeling"><span class="icon">😊</span> Feeling/activity</button>';
h+='</div></div>';
h+='<div id="feed"></div>';
h+='</div></div>';

// Composer Modal
h+='<div class="fb-modal" id="composer-modal"><div class="fb-modal-box">';
h+='<div class="fb-modal-header"><span class="fb-modal-title">Create post</span><button class="fb-modal-close" data-close="composer-modal">✕</button></div>';
h+='<div class="fb-modal-body">';
h+='<div style="display:flex;gap:12px;margin-bottom:16px"><div class="fb-composer-avatar">'+av(ud.photo,user,16)+'</div><div><div style="font-weight:600">'+esc(user)+'</div><div style="font-size:12px;color:#65676b">🌐 Public</div></div></div>';
h+='<textarea class="fb-textarea" id="post-text" placeholder="What\'s on your mind, '+esc(user.split(/[\s_]/)[0])+'?"></textarea>';
h+='<img class="fb-preview-img" id="modal-preview">';
h+='<div class="fb-upload-area"><div class="fb-upload-zone" id="modal-upload"><input type="file" accept="image/*"><div class="fb-upload-icon">🖼️</div><div class="fb-upload-text">Add photos/videos</div><div class="fb-upload-hint">or drag and drop</div></div></div>';
h+='</div>';
h+='<div class="fb-modal-footer"><button class="fb-modal-post-btn" id="submit-post" disabled>Post</button></div>';
h+='</div></div>';

// Edit Profile Modal
h+='<div class="fb-modal" id="profile-modal"><div class="fb-modal-box">';
h+='<div class="fb-modal-header"><span class="fb-modal-title">Edit profile</span><button class="fb-modal-close" data-close="profile-modal">✕</button></div>';
h+='<div class="fb-modal-body">';
h+='<div style="margin-bottom:16px"><div style="font-weight:600;margin-bottom:8px">Bio</div><textarea class="fb-textarea" id="bio-input" style="font-size:15px;min-height:60px" placeholder="Describe yourself...">'+esc(ud.bio)+'</textarea></div>';
h+='<div style="margin-bottom:16px"><div style="font-weight:600;margin-bottom:8px">Location</div><input type="text" id="location-input" value="'+esc(ud.location)+'" placeholder="Where do you live?" style="width:100%;padding:12px;border:1px solid #ddd;border-radius:6px;font-size:15px"></div>';
h+='<div style="margin-bottom:16px"><div style="font-weight:600;margin-bottom:8px">Profile photo</div><div class="fb-upload-zone" id="pic-upload" style="padding:16px"><input type="file" accept="image/*"><span>Click to upload</span></div><img class="fb-preview-img" id="pic-preview"></div>';
h+='<div><div style="font-weight:600;margin-bottom:8px">Cover photo</div><div class="fb-upload-zone" id="cover-upload" style="padding:16px"><input type="file" accept="image/*"><span>Click to upload</span></div><img class="fb-preview-img" id="cover-preview"></div>';
h+='</div>';
h+='<div class="fb-modal-footer"><button class="fb-modal-post-btn" id="save-profile">Save</button></div>';
h+='</div></div>';

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

// Modal handlers
$app.on("click","[data-close]",function(){cm($(this).data("close"));});
$app.on("click",".fb-modal",function(e){if($(e.target).hasClass("fb-modal"))cm(this.id);});

// Composer
var postFile=null;
$("#open-composer,#quick-photo").on("click",function(){om("composer-modal");});
$("#modal-upload").on("click",function(){$(this).find("input").click();});
$("#modal-upload input").on("change",function(){if(this.files[0]){postFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#modal-preview").attr("src",e.target.result).addClass("show");updPost();};r.readAsDataURL(this.files[0]);}});
$("#post-text").on("input",updPost);
function updPost(){$("#submit-post").prop("disabled",!$("#post-text").val().trim()&&!postFile&&!$("#modal-preview").hasClass("show"));}

$("#submit-post").on("click",function(){
  var t=$("#post-text").val().trim();
  if(!t&&!postFile)return;
  var $b=$(this).prop("disabled",true).text("Posting...");
  function doPost(imgUrl){
    var p={action:"socialfeed",sfaction:"createpost",content:t||"(photo)"};
    if(imgUrl)p.image_url=imgUrl;
    api.postWithToken("csrf",p).then(function(){
      cm("composer-modal");$("#post-text").val("");postFile=null;$("#modal-preview").removeClass("show");$b.prop("disabled",true).text("Post");loadFeed();
    });
  }
  if(postFile){upload(postFile,"Post",function(){}).then(doPost);}else{doPost();}
});

// Profile edit
var picFile=null,coverFile=null;
$("#edit-profile-btn,#edit-pic,#edit-cover,#add-bio").on("click",function(){om("profile-modal");});
$("#pic-upload").on("click",function(){$(this).find("input").click();});
$("#pic-upload input").on("change",function(){if(this.files[0]){picFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#pic-preview").attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});
$("#cover-upload").on("click",function(){$(this).find("input").click();});
$("#cover-upload input").on("change",function(){if(this.files[0]){coverFile=this.files[0];var r=new FileReader();r.onload=function(e){$("#cover-preview").attr("src",e.target.result).addClass("show");};r.readAsDataURL(this.files[0]);}});

$("#save-profile").on("click",function(){
  var $b=$(this).prop("disabled",true).text("Saving...");
  ud.bio=$("#bio-input").val().trim();
  ud.location=$("#location-input").val().trim();
  localStorage.setItem("sf_bio_"+user,ud.bio);
  localStorage.setItem("sf_location_"+user,ud.location);

  var saves=[];
  if(picFile)saves.push(upload(picFile,"Pic",function(){}).then(function(u){ud.photo=u;localStorage.setItem("sf_photo_"+user,u);}));
  if(coverFile)saves.push(upload(coverFile,"Cover",function(){}).then(function(u){ud.cover=u;localStorage.setItem("sf_cover_"+user,u);}));

  $.when.apply($,saves).then(function(){
    if(ud.photo)$("#profile-pic,.fb-composer-avatar").html(av(ud.photo,user,64));
    if(ud.cover)$("#cover-area").html('<img src="'+ud.cover+'"><button class="fb-cover-btn" id="edit-cover">📷 Edit cover photo</button>');
    $("#intro-content").html(ud.bio?'<div class="fb-intro-item" style="text-align:center;display:block;padding:16px">'+esc(ud.bio)+'</div>':'');
    $("#add-bio").text(ud.bio?'Edit bio':'Add bio');
    cm("profile-modal");$b.prop("disabled",false).text("Save");picFile=null;coverFile=null;
  });
});

// Posts
$app.on("click",".fb-post-action[data-like]",function(){api.postWithToken("csrf",{action:"socialfeed",sfaction:"react",post_id:$(this).data("like"),reaction_type:"like"}).then(loadFeed);});
$app.on("click",".fb-post-menu[data-del]",function(){if(confirm("Delete post?")){api.postWithToken("csrf",{action:"socialfeed",sfaction:"deletepost",post_id:$(this).data("del")}).then(loadFeed);}});
$app.on("click",".fb-view-comments",function(){var id=$(this).data("id");$("#comments-"+id).toggleClass("show");if($("#comments-"+id).hasClass("show"))loadComments(id);});
$app.on("keypress",".fb-comment-input",function(e){if(e.which===13){var $i=$(this),t=$i.val().trim(),id=$i.data("id");if(t){$i.val("");api.postWithToken("csrf",{action:"socialfeed",sfaction:"comment",post_id:id,content:t}).then(function(){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="fb-card fb-empty"><div class="fb-empty-icon">📷</div><div class="fb-empty-title">No posts yet</div><div class="fb-empty-text">When you share photos, they\'ll appear here.</div></div>');return;}
    $("#follower-count").text(posts.length);
    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=p.image_url?'<div class="fb-post-media"><img src="'+esc(p.image_url)+'"></div>':"";
      var del=p.username===user?'<button class="fb-post-menu" data-del="'+p.id+'">✕</button>':"";
      var liked=p.user_reaction==="like"?" liked":"";
      return '<div class="fb-card"><div class="fb-post-header"><div class="fb-post-avatar">'+av(pic,p.username,16)+'</div><div class="fb-post-meta"><div class="fb-post-author">'+esc(p.username)+'</div><div class="fb-post-time">'+ago(p.created)+' · 🌐</div></div>'+del+'</div>'+(p.content&&p.content!=="(photo)"?'<div class="fb-post-content">'+esc(p.content)+'</div>':'')+media+'<div class="fb-post-stats"><span>👍❤️ '+likes+'</span><span class="fb-view-comments" data-id="'+p.id+'" style="cursor:pointer">'+p.comments+' comments</span></div><div class="fb-post-actions"><button class="fb-post-action'+liked+'" data-like="'+p.id+'">'+(liked?'👍 Like':'🤍 Like')+'</button><button class="fb-post-action">💬 Comment</button><button class="fb-post-action">↗️ Share</button></div><div class="fb-post-comments" id="comments-'+p.id+'"></div><div class="fb-comment-form"><div class="fb-comment-avatar">'+av(ud.photo,user,12)+'</div><input class="fb-comment-input" data-id="'+p.id+'" placeholder="Write a comment..."></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="fb-comment"><div class="fb-comment-avatar">'+av(pic,c.username,12)+'</div><div class="fb-comment-bubble"><div class="fb-comment-author">'+esc(c.username)+'</div><div class="fb-comment-text">'+esc(c.content)+'</div></div></div>';
    }).join("");
    $("#comments-"+id).html(h||'<div style="padding:8px;color:#65676b">No comments yet</div>');
  });
}

loadFeed();
});
}