User:Docmoates/Social: Difference between revisions

From XMethod Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 28: Line 28:
     border-radius: 50%;
     border-radius: 50%;
     object-fit: cover;
     object-fit: cover;
     background: #e4e6eb;
     background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    color: white;
    font-weight: 600;
    font-size: 18px;
    flex-shrink: 0;
    cursor: pointer;
    position: relative;
    overflow: hidden;
}
}
.sf-avatar-small { width: 36px; height: 36px; }
.sf-avatar img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
}
.sf-avatar-small { width: 36px; height: 36px; font-size: 14px; }
.sf-avatar-edit {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: rgba(0,0,0,0.6);
    color: white;
    font-size: 10px;
    padding: 2px;
    text-align: center;
    opacity: 0;
    transition: opacity 0.2s;
}
.sf-avatar:hover .sf-avatar-edit { opacity: 1; }
.sf-composer-input {
.sf-composer-input {
     flex: 1;
     flex: 1;
Line 116: Line 146:
.sf-empty-text { font-size: 18px; font-weight: 500; }
.sf-empty-text { font-size: 18px; font-weight: 500; }
.sf-empty-sub { font-size: 14px; margin-top: 8px; color: #8a8d91; }
.sf-empty-sub { font-size: 14px; margin-top: 8px; color: #8a8d91; }
.sf-loading { text-align: center; padding: 40px; color: #65676b; }
.sf-stories { display: flex; gap: 12px; padding: 16px; background: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; overflow-x: auto; }
.sf-stories { display: flex; gap: 12px; padding: 16px; background: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; overflow-x: auto; }
.sf-story { display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; }
.sf-story { display: flex; flex-direction: column; align-items: center; gap: 8px; cursor: pointer; }
Line 124: Line 153:
.sf-create-story { width: 68px; height: 68px; border-radius: 50%; background: #e4e6eb; display: flex; align-items: center; justify-content: center; font-size: 28px; color: #1877f2; cursor: pointer; border: none; }
.sf-create-story { width: 68px; height: 68px; border-radius: 50%; background: #e4e6eb; display: flex; align-items: center; justify-content: center; font-size: 28px; color: #1877f2; cursor: pointer; border: none; }
.sf-create-story:hover { background: #d8dadf; }
.sf-create-story:hover { background: #d8dadf; }
.sf-modal { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.6); z-index: 1000; align-items: center; justify-content: center; }
.sf-modal.active { display: flex; }
.sf-modal-content { background: white; border-radius: 12px; padding: 24px; max-width: 400px; width: 90%; }
.sf-modal-title { font-size: 20px; font-weight: 600; margin-bottom: 16px; }
.sf-modal-input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; margin-bottom: 12px; }
.sf-modal-buttons { display: flex; gap: 12px; justify-content: flex-end; }
.sf-modal-btn { padding: 10px 20px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; }
.sf-modal-btn-cancel { background: #e4e6eb; color: #050505; }
.sf-modal-btn-save { background: #1877f2; color: white; }
</style>
</style>


Line 135: Line 173:
<div class="sf-composer">
<div class="sf-composer">
     <div class="sf-composer-main">
     <div class="sf-composer-main">
         <img class="sf-avatar" id="composer-avatar" src="https://docmoates.com/images/thumb/8/8b/Docmoates_Profile.jpeg/120px-Docmoates_Profile.jpeg" alt="">
         <div class="sf-avatar" id="composer-avatar" onclick="openProfileModal()">
            <span id="avatar-initials"></span>
            <div class="sf-avatar-edit">Edit</div>
        </div>
         <textarea class="sf-composer-input" id="post-content" placeholder="What is on your mind?"></textarea>
         <textarea class="sf-composer-input" id="post-content" placeholder="What is on your mind?"></textarea>
     </div>
     </div>
     <div class="sf-composer-actions">
     <div class="sf-composer-actions">
         <div class="sf-action-buttons">
         <div class="sf-action-buttons">
             <button class="sf-action-btn" title="Photo">🖼️</button>
             <button class="sf-action-btn" title="Add Image" onclick="promptImage()">🖼️</button>
             <button class="sf-action-btn" title="Emoji">😊</button>
             <button class="sf-action-btn" title="Emoji">😊</button>
             <button class="sf-action-btn" title="GIF">🎬</button>
             <button class="sf-action-btn" title="GIF">🎬</button>
Line 146: Line 187:
         </div>
         </div>
         <button class="sf-post-btn" id="post-btn">Post</button>
         <button class="sf-post-btn" id="post-btn">Post</button>
    </div>
</div>
<div id="image-preview" style="display:none; padding: 0 20px 16px; background: white; margin-top: -20px; border-radius: 0 0 12px 12px;">
    <div style="position: relative; display: inline-block;">
        <img id="preview-img" style="max-width: 100%; max-height: 300px; border-radius: 8px;">
        <button onclick="removeImage()" style="position: absolute; top: 8px; right: 8px; background: rgba(0,0,0,0.6); color: white; border: none; border-radius: 50%; width: 28px; height: 28px; cursor: pointer;">×</button>
     </div>
     </div>
</div>
</div>


<div id="timeline-container">
<div id="timeline-container">
     <div class="sf-loading">Loading...</div>
     <div class="sf-empty">
        <div class="sf-empty-icon">📝</div>
        <div class="sf-empty-text">No posts yet</div>
        <div class="sf-empty-sub">Be the first to share something!</div>
    </div>
</div>
 
<div class="sf-modal" id="profile-modal">
    <div class="sf-modal-content">
        <div class="sf-modal-title">Set Profile Photo</div>
        <input type="text" class="sf-modal-input" id="profile-url-input" placeholder="Enter image URL...">
        <p style="font-size: 12px; color: #65676b; margin: 0 0 12px;">Tip: Upload an image to your wiki, then paste the URL here</p>
        <div class="sf-modal-buttons">
            <button class="sf-modal-btn sf-modal-btn-cancel" onclick="closeProfileModal()">Cancel</button>
            <button class="sf-modal-btn sf-modal-btn-save" onclick="saveProfilePhoto()">Save</button>
        </div>
    </div>
</div>
</div>


<script>
<script>
(function() {
(function() {
     var currentUser = mw.config.get("wgUserName");
     var currentUser = mw.config.get("wgUserName") || "Guest";
    var profilePhoto = localStorage.getItem("sf_profile_photo_" + currentUser) || "";
    var pendingImageUrl = "";
      
      
     if (currentUser) {
     function getInitials(name) {
         document.getElementById("post-content").placeholder = "What is on your mind, " + currentUser + "?";
         return name.split(/[\s_]+/).map(function(w) { return w[0]; }).join("").substring(0,2).toUpperCase();
     }
     }
   
    function setAvatar(container, photo, name) {
        if (photo) {
            container.innerHTML = "<img src=\"" + photo + "\" onerror=\"this.parentNode.innerHTML= + getInitials(name) + \"><div class=\"sf-avatar-edit\">Edit</div>";
        } else {
            container.innerHTML = getInitials(name) + "<div class=\"sf-avatar-edit\">Edit</div>";
        }
    }
   
    // Initialize
    var composerAvatar = document.getElementById("composer-avatar");
    setAvatar(composerAvatar, profilePhoto, currentUser);
    document.getElementById("post-content").placeholder = "What is on your mind, " + currentUser + "?";
      
      
     document.getElementById("post-btn").addEventListener("click", createPost);
     document.getElementById("post-btn").addEventListener("click", createPost);
      
      
     loadPosts();
     loadPosts();
     loadStories();
      
    window.openProfileModal = function() {
        document.getElementById("profile-modal").classList.add("active");
        document.getElementById("profile-url-input").value = profilePhoto;
    };
   
    window.closeProfileModal = function() {
        document.getElementById("profile-modal").classList.remove("active");
    };
   
    window.saveProfilePhoto = function() {
        var url = document.getElementById("profile-url-input").value.trim();
        profilePhoto = url;
        localStorage.setItem("sf_profile_photo_" + currentUser, url);
        setAvatar(composerAvatar, profilePhoto, currentUser);
        closeProfileModal();
    };
   
    window.promptImage = function() {
        var url = prompt("Enter image URL:");
        if (url) {
            pendingImageUrl = url;
            document.getElementById("preview-img").src = url;
            document.getElementById("image-preview").style.display = "block";
        }
    };
   
    window.removeImage = function() {
        pendingImageUrl = "";
        document.getElementById("image-preview").style.display = "none";
    };
      
      
     function loadPosts() {
     function loadPosts() {
Line 173: Line 282:
         }).done(function(data) {
         }).done(function(data) {
             renderPosts(data.socialfeed.posts || []);
             renderPosts(data.socialfeed.posts || []);
         }).fail(function() {
         }).fail(function(code, data) {
             document.getElementById("timeline-container").innerHTML = "<div class=\"sf-empty\"><div class=\"sf-empty-icon\">😕</div><div class=\"sf-empty-text\">Could not load posts</div></div>";
            console.error("API Error:", code, data);
             document.getElementById("timeline-container").innerHTML = "<div class=\"sf-empty\"><div class=\"sf-empty-icon\">📝</div><div class=\"sf-empty-text\">No posts yet</div><div class=\"sf-empty-sub\">Be the first to share something!</div></div>";
         });
         });
    }
   
    function loadStories() {
        new mw.Api().get({
            action: "socialfeed",
            sfaction: "getstories"
        }).done(function(data) {
            renderStories(data.socialfeed.stories || []);
        });
    }
   
    function renderStories(stories) {
        var container = document.getElementById("stories-container");
        var html = "<div class=\"sf-story\"><button class=\"sf-create-story\">+</button><span class=\"sf-story-name\">Add Story</span></div>";
        stories.forEach(function(s) {
            html += "<div class=\"sf-story\"><div class=\"sf-story-ring\"><img class=\"sf-story-avatar\" src=\"" + s.image_url + "\"></div><span class=\"sf-story-name\">" + s.username + "</span></div>";
        });
        container.innerHTML = html;
     }
     }
      
      
Line 207: Line 299:
             var totalReactions = 0;
             var totalReactions = 0;
             for (var k in post.reaction_counts) totalReactions += post.reaction_counts[k];
             for (var k in post.reaction_counts) totalReactions += post.reaction_counts[k];
            var userPhoto = localStorage.getItem("sf_profile_photo_" + post.username) || "";
            var avatarContent = userPhoto ? "<img src=\"" + userPhoto + "\">" : getInitials(post.username);
           
             html += "<div class=\"sf-post\" data-id=\"" + post.id + "\">";
             html += "<div class=\"sf-post\" data-id=\"" + post.id + "\">";
             html += "<div class=\"sf-post-header\"><img class=\"sf-avatar\" src=\"https://docmoates.com/images/thumb/8/8b/Docmoates_Profile.jpeg/120px-Docmoates_Profile.jpeg\"><div class=\"sf-post-user-info\"><div class=\"sf-post-username\">" + post.username + "</div><div class=\"sf-post-meta\">" + timeAgo + " · 🌐</div></div>";
             html += "<div class=\"sf-post-header\"><div class=\"sf-avatar sf-avatar-small\">" + avatarContent + "</div><div class=\"sf-post-user-info\"><div class=\"sf-post-username\">" + escapeHtml(post.username) + "</div><div class=\"sf-post-meta\">" + timeAgo + " · 🌐</div></div>";
             if (post.username === currentUser) html += "<button class=\"sf-post-menu\" onclick=\"deletePost(" + post.id + ")\">🗑️</button>";
             if (post.username === currentUser) html += "<button class=\"sf-post-menu\" onclick=\"deletePost(" + post.id + ")\">🗑️</button>";
             html += "</div>";
             html += "</div>";
Line 216: Line 311:
             if (totalReactions > 0) {
             if (totalReactions > 0) {
                 html += "<div class=\"sf-reaction-icons\">";
                 html += "<div class=\"sf-reaction-icons\">";
                 if (post.reaction_counts.like) html += "<span class=\"sf-reaction-icon like\">👍</span>";
                 if (post.reaction_counts && post.reaction_counts.like) html += "<span class=\"sf-reaction-icon like\">👍</span>";
                 if (post.reaction_counts.love) html += "<span class=\"sf-reaction-icon love\">❤️</span>";
                 if (post.reaction_counts && post.reaction_counts.love) html += "<span class=\"sf-reaction-icon love\">❤️</span>";
                 html += "</div><span>" + totalReactions + "</span>";
                 html += "</div><span>" + totalReactions + "</span>";
             }
             }
Line 232: Line 327:
     window.createPost = function() {
     window.createPost = function() {
         var content = document.getElementById("post-content").value.trim();
         var content = document.getElementById("post-content").value.trim();
         if (!content) return;
         if (!content && !pendingImageUrl) return;
         document.getElementById("post-btn").disabled = true;
         document.getElementById("post-btn").disabled = true;
         new mw.Api().postWithToken("csrf", {
          
        var params = {
             action: "socialfeed",
             action: "socialfeed",
             sfaction: "createpost",
             sfaction: "createpost",
             content: content
             content: content || "(photo)"
         }).done(function() {
         };
        if (pendingImageUrl) params.image_url = pendingImageUrl;
       
        new mw.Api().postWithToken("csrf", params).done(function() {
             document.getElementById("post-content").value = "";
             document.getElementById("post-content").value = "";
            pendingImageUrl = "";
            document.getElementById("image-preview").style.display = "none";
             document.getElementById("post-btn").disabled = false;
             document.getElementById("post-btn").disabled = false;
             loadPosts();
             loadPosts();
         }).fail(function(c, d) {
         }).fail(function(c, d) {
             alert("Error: " + (d.error ? d.error.info : c));
             alert("Error: " + (d && d.error ? d.error.info : c));
             document.getElementById("post-btn").disabled = false;
             document.getElementById("post-btn").disabled = false;
         });
         });
Line 269: Line 370:
             var html = "";
             var html = "";
             comments.forEach(function(cm) {
             comments.forEach(function(cm) {
                 html += "<div class=\"sf-comment\"><img class=\"sf-avatar sf-avatar-small\" src=\"https://i.pravatar.cc/150\"><div class=\"sf-comment-bubble\"><div class=\"sf-comment-author\">" + cm.username + "</div><div class=\"sf-comment-text\">" + escapeHtml(cm.content) + "</div></div></div>";
                var cPhoto = localStorage.getItem("sf_profile_photo_" + cm.username) || "";
                var cAvatar = cPhoto ? "<img src=\"" + cPhoto + "\">" : getInitials(cm.username);
                 html += "<div class=\"sf-comment\"><div class=\"sf-avatar sf-avatar-small\">" + cAvatar + "</div><div class=\"sf-comment-bubble\"><div class=\"sf-comment-author\">" + escapeHtml(cm.username) + "</div><div class=\"sf-comment-text\">" + escapeHtml(cm.content) + "</div></div></div>";
             });
             });
             html += "<div class=\"sf-add-comment\"><img class=\"sf-avatar sf-avatar-small\" src=\"https://docmoates.com/images/thumb/8/8b/Docmoates_Profile.jpeg/120px-Docmoates_Profile.jpeg\"><input class=\"sf-comment-input\" placeholder=\"Write a comment...\" onkeypress=\"if(event.key===Enter)addComment(" + id + ",this)\"></div>";
            var myPhoto = profilePhoto ? "<img src=\"" + profilePhoto + "\">" : getInitials(currentUser);
             html += "<div class=\"sf-add-comment\"><div class=\"sf-avatar sf-avatar-small\">" + myPhoto + "</div><input class=\"sf-comment-input\" placeholder=\"Write a comment...\" onkeypress=\"if(event.key===String.fromCharCode(13))addComment(" + id + ",this)\"></div>";
             c.innerHTML = html;
             c.innerHTML = html;
         });
         });

Revision as of 21:35, 2 February 2026

Add Story
Edit
📝
No posts yet
Be the first to share something!
Set Profile Photo

Tip: Upload an image to your wiki, then paste the URL here