|
|
| Line 1: |
Line 1: |
| <html> | | <html> |
| <div id="social-feed-app"> | | <div id="sf-app"> |
| <style> | | <style> |
| #social-feed-app * { box-sizing: border-box; } | | #sf-app{max-width:680px;margin:0 auto;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;background:#f0f2f5;min-height:100vh;padding:20px} |
| #social-feed-app { max-width: 680px; margin: 0 auto; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, sans-serif; background: #f0f2f5; min-height: 100vh; padding: 20px; }
| | #sf-app *{box-sizing:border-box} |
| .sf-composer { background: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 20px; }
| | .sf-card{background:#fff;border-radius:12px;box-shadow:0 1px 3px rgba(0,0,0,.1);margin-bottom:16px} |
| .sf-composer-main { display: flex; padding: 16px 20px; gap: 12px; } | | .sf-avatar{width:44px;height:44px;border-radius:50%;background:linear-gradient(135deg,#667eea,#764ba2);display:flex;align-items:center;justify-content:center;color:#fff;font-weight:600;font-size:16px;cursor:pointer;overflow:hidden;flex-shrink:0} |
| .sf-avatar { width: 48px; height: 48px; border-radius: 50%; background: linear-gradient(135deg, #667eea, #764ba2); display: flex; align-items: center; justify-content: center; color: white; font-weight: 600; font-size: 18px; cursor: pointer; position: relative; overflow: hidden; flex-shrink: 0; }
| | .sf-avatar img{width:100%;height:100%;object-fit:cover} |
| .sf-avatar img { width: 100%; height: 100%; object-fit: cover; } | | .sf-avatar-sm{width:32px;height:32px;font-size:12px} |
| .sf-avatar-small { width: 36px; height: 36px; font-size: 14px; } | | .sf-btn{background:#1877f2;color:#fff;border:none;border-radius:8px;padding:8px 16px;font-weight:600;cursor:pointer} |
| .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: 0.2s; } | | .sf-btn:disabled{opacity:.5} |
| .sf-avatar:hover .sf-avatar-edit { opacity: 1; } | | .sf-btn-light{background:#e4e6eb;color:#050505} |
| .sf-composer-input { flex: 1; background: #f0f2f5; border: none; border-radius: 20px; padding: 14px 20px; font-size: 17px; resize: none; min-height: 80px; outline: none; font-family: inherit; } | | .sf-modal{display:none;position:fixed;inset:0;background:rgba(255,255,255,.85);backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);z-index:1000;align-items:center;justify-content:center} |
| .sf-composer-actions { display: flex; align-items: center; justify-content: space-between; padding: 12px 20px; border-top: 1px solid #e4e6eb; gap: 12px; } | | .sf-modal.open{display:flex} |
| .sf-action-buttons { display: flex; gap: 8px; position: relative; } | | .sf-modal-box{background:#fff;border-radius:12px;padding:20px;width:90%;max-width:420px;box-shadow:0 8px 32px rgba(0,0,0,.15)} |
| .sf-action-btn { width: 40px; height: 40px; border-radius: 8px; border: none; background: #f0f2f5; cursor: pointer; font-size: 18px; } | | .sf-modal-title{font-size:18px;font-weight:600;margin-bottom:16px} |
| .sf-action-btn:hover { background: #e4e6eb; } | | .sf-tabs{display:flex;border-bottom:2px solid #e4e6eb;margin-bottom:16px} |
| .sf-post-btn { background: linear-gradient(135deg, #1877f2, #0d65d9); color: white; border: none; border-radius: 8px; padding: 10px 24px; font-size: 15px; font-weight: 600; cursor: pointer; }
| | .sf-tab{flex:1;padding:10px;text-align:center;cursor:pointer;font-weight:600;color:#65676b;border-bottom:2px solid transparent;margin-bottom:-2px} |
| .sf-post-btn:disabled { opacity: 0.5; } | | .sf-tab.active{color:#1877f2;border-color:#1877f2} |
| .sf-post { background: white; border-radius: 12px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 16px; } | | .sf-tab-panel{display:none} |
| .sf-post-header { display: flex; align-items: center; padding: 16px; gap: 12px; } | | .sf-tab-panel.active{display:block} |
| .sf-post-user-info { flex: 1; } | | .sf-upload-area{border:2px dashed #ccd0d5;border-radius:8px;padding:32px;text-align:center;cursor:pointer;transition:.2s} |
| .sf-post-username { font-weight: 600; font-size: 15px; } | | .sf-upload-area:hover{border-color:#1877f2;background:#f0f7ff} |
| .sf-post-meta { font-size: 13px; color: #65676b; } | | .sf-upload-area.drag{border-color:#1877f2;background:#e7f3ff} |
| .sf-post-menu { background: none; border: none; font-size: 18px; color: #65676b; cursor: pointer; padding: 8px; border-radius: 50%; } | | .sf-input{width:100%;padding:10px 12px;border:1px solid #ccd0d5;border-radius:8px;font-size:14px;margin-bottom:12px} |
| .sf-post-menu:hover { background: #f0f2f5; } | | .sf-preview{max-width:100%;max-height:120px;border-radius:8px;margin-top:12px} |
| .sf-post-content { padding: 0 16px 16px; font-size: 15px; line-height: 1.5; white-space: pre-wrap; } | | .sf-progress{height:6px;background:#e4e6eb;border-radius:3px;margin-top:12px;overflow:hidden} |
| .sf-post-image { width: 100%; max-height: 500px; object-fit: cover; } | | .sf-progress-bar{height:100%;background:#1877f2;width:0;transition:width .3s} |
| .sf-post-video { width: 100%; max-height: 500px; }
| | .sf-composer{padding:16px} |
| .sf-post-location { padding: 8px 16px; font-size: 13px; color: #65676b; display: flex; align-items: center; gap: 4px; } | | .sf-composer-top{display:flex;gap:12px} |
| .sf-post-stats { display: flex; justify-content: space-between; padding: 12px 16px; font-size: 14px; color: #65676b; border-bottom: 1px solid #e4e6eb; } | | .sf-composer-input{flex:1;border:none;background:#f0f2f5;border-radius:20px;padding:12px 16px;font-size:15px;resize:none;min-height:44px;outline:none} |
| .sf-post-stats-left { display: flex; align-items: center; gap: 6px; } | | .sf-composer-actions{display:flex;justify-content:space-between;align-items:center;margin-top:12px;padding-top:12px;border-top:1px solid #e4e6eb} |
| .sf-reaction-icon { width: 20px; height: 20px; border-radius: 50%; background: #1877f2; color: white; display: inline-flex; align-items: center; justify-content: center; font-size: 12px; } | | .sf-composer-btns{display:flex;gap:4px} |
| .sf-post-actions { display: flex; padding: 4px 16px; } | | .sf-icon-btn{width:36px;height:36px;border:none;background:#f0f2f5;border-radius:8px;font-size:18px;cursor:pointer} |
| .sf-post-action { flex: 1; display: flex; align-items: center; justify-content: center; gap: 8px; padding: 12px; background: none; border: none; font-size: 15px; font-weight: 600; color: #65676b; cursor: pointer; border-radius: 8px; }
| | .sf-icon-btn:hover{background:#e4e6eb} |
| .sf-post-action:hover { background: #f0f2f5; } | | .sf-stories{display:flex;gap:12px;padding:16px;overflow-x:auto} |
| .sf-post-action.liked { color: #1877f2; } | | .sf-story{display:flex;flex-direction:column;align-items:center;gap:4px} |
| .sf-comments { padding: 12px 16px; background: #f7f8fa; } | | .sf-story-ring{width:60px;height:60px;border-radius:50%;padding:2px;background:linear-gradient(45deg,#f09433,#e6683c,#dc2743,#cc2366,#bc1888)} |
| .sf-comment { display: flex; gap: 8px; margin-bottom: 12px; } | | .sf-story-ring.add{background:#e4e6eb} |
| .sf-comment-bubble { background: white; border-radius: 18px; padding: 10px 14px; } | | .sf-story-inner{width:100%;height:100%;border-radius:50%;border:2px solid #fff;overflow:hidden;display:flex;align-items:center;justify-content:center;background:#f0f2f5;cursor:pointer} |
| .sf-comment-author { font-weight: 600; font-size: 13px; } | | .sf-story-inner img{width:100%;height:100%;object-fit:cover} |
| .sf-comment-text { font-size: 14px; } | | .sf-story-name{font-size:11px;color:#65676b;max-width:64px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} |
| .sf-add-comment { display: flex; gap: 8px; align-items: center; } | | .sf-post-header{display:flex;gap:10px;padding:12px 16px} |
| .sf-comment-input { flex: 1; background: white; border: none; border-radius: 20px; padding: 10px 16px; font-size: 14px; outline: none; } | | .sf-post-info{flex:1} |
| .sf-empty { text-align: center; padding: 60px 20px; background: white; border-radius: 12px; color: #65676b; } | | .sf-post-name{font-weight:600;font-size:14px} |
| .sf-empty-icon { font-size: 64px; margin-bottom: 16px; } | | .sf-post-meta{font-size:12px;color:#65676b} |
| .sf-empty-text { font-size: 18px; font-weight: 500; }
| | .sf-post-content{padding:0 16px 12px;font-size:15px;line-height:1.4;white-space:pre-wrap} |
| .sf-empty-sub { font-size: 14px; margin-top: 8px; color: #8a8d91; }
| | .sf-post-media img,.sf-post-media video,.sf-post-media iframe{width:100%;max-height:500px;object-fit:cover} |
| .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-post-location{padding:4px 16px 8px;font-size:12px;color:#65676b} |
| .sf-story-item { display: flex; flex-direction: column; align-items: center; gap: 6px; min-width: 80px; } | | .sf-post-stats{display:flex;justify-content:space-between;padding:8px 16px;font-size:13px;color:#65676b;border-bottom:1px solid #e4e6eb} |
| .sf-story-ring { width: 68px; height: 68px; border-radius: 50%; padding: 3px; background: linear-gradient(45deg, #f09433, #e6683c, #dc2743, #cc2366, #bc1888); } | | .sf-post-actions{display:flex;padding:4px 8px} |
| .sf-story-ring.no-story { background: #e4e6eb; }
| | .sf-post-action{flex:1;display:flex;align-items:center;justify-content:center;gap:6px;padding:8px;border:none;background:none;font-size:14px;font-weight:600;color:#65676b;cursor:pointer;border-radius:4px} |
| .sf-story-avatar { width: 100%; height: 100%; border-radius: 50%; border: 3px solid white; object-fit: cover; cursor: pointer; background: linear-gradient(135deg, #667eea, #764ba2); display: flex; align-items: center; justify-content: center; color: white; font-weight: 600; font-size: 20px; } | | .sf-post-action:hover{background:#f0f2f5} |
| .sf-story-avatar img { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; } | | .sf-post-action.liked{color:#1877f2} |
| .sf-story-name { font-size: 12px; color: #65676b; max-width: 80px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } | | .sf-comments{padding:8px 16px 12px;background:#f7f8fa} |
| .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-comment{display:flex;gap:8px;margin-bottom:8px} |
| .sf-modal { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(255,255,255,0.8); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); z-index: 9999; align-items: center; justify-content: center; } | | .sf-comment-bubble{background:#fff;border-radius:16px;padding:8px 12px} |
| .sf-modal.active { display: flex; }
| | .sf-comment-author{font-weight:600;font-size:12px} |
| .sf-modal-content { background: white; border-radius: 12px; padding: 24px; max-width: 450px; width: 90%; box-shadow: 0 8px 32px rgba(0,0,0,0.12); } | | .sf-comment-text{font-size:13px} |
| .sf-modal-title { font-size: 20px; font-weight: 600; margin-bottom: 16px; } | | .sf-comment-form{display:flex;gap:8px;margin-top:8px} |
| .sf-modal-input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; margin-bottom: 12px; } | | .sf-comment-input{flex:1;border:none;background:#fff;border-radius:18px;padding:8px 12px;font-size:13px;outline:none} |
| .sf-modal-buttons { display: flex; gap: 12px; justify-content: flex-end; } | | .sf-empty{text-align:center;padding:48px 20px;color:#65676b} |
| .sf-modal-btn { padding: 10px 20px; border-radius: 8px; border: none; font-weight: 600; cursor: pointer; }
| | .sf-empty-icon{font-size:48px;margin-bottom:12px} |
| .sf-modal-btn-cancel { background: #e4e6eb; } | | .sf-viewer{display:none;position:fixed;inset:0;background:#000;z-index:2000;align-items:center;justify-content:center} |
| .sf-modal-btn-save { background: #1877f2; color: white; } | | .sf-viewer.open{display:flex} |
| #image-preview { display: none; padding: 12px 20px; background: white; margin-bottom: 20px; border-radius: 12px; }
| | .sf-viewer img{max-width:100%;max-height:100%;object-fit:contain} |
| #image-preview img, #image-preview video { max-width: 100%; max-height: 200px; border-radius: 8px; }
| | .sf-viewer-close{position:absolute;top:16px;right:16px;width:40px;height:40px;border-radius:50%;border:none;background:rgba(255,255,255,.2);color:#fff;font-size:20px;cursor:pointer} |
| #location-preview { display: none; padding: 8px 20px; background: white; margin-bottom: 10px; border-radius: 8px; font-size: 14px; color: #65676b; } | | .sf-viewer-progress{position:absolute;top:8px;left:8px;right:8px;height:3px;background:rgba(255,255,255,.3);border-radius:2px} |
| .sf-tabs { display: flex; border-bottom: 2px solid #e4e6eb; margin-bottom: 16px; } | | .sf-viewer-progress span{display:block;height:100%;background:#fff;border-radius:2px;animation:progress 5s linear} |
| .sf-tab { flex: 1; padding: 12px; text-align: center; cursor: pointer; font-weight: 600; color: #65676b; border-bottom: 2px solid transparent; margin-bottom: -2px; } | | @keyframes progress{from{width:0}to{width:100%}} |
| .sf-tab.active { color: #1877f2; border-bottom-color: #1877f2; }
| | .sf-emoji-picker{position:absolute;bottom:44px;left:0;background:#fff;border-radius:12px;box-shadow:0 4px 16px rgba(0,0,0,.15);padding:12px;width:280px;z-index:100;display:none} |
| .sf-tab-content { display: none; }
| | .sf-emoji-picker.open{display:block} |
| .sf-tab-content.active { display: block; }
| | .sf-emoji-cats{display:flex;gap:2px;margin-bottom:8px;border-bottom:1px solid #e4e6eb;padding-bottom:8px} |
| .sf-upload-zone { border: 2px dashed #ccc; border-radius: 12px; padding: 40px 20px; text-align: center; cursor: pointer; transition: 0.2s; margin-bottom: 12px; }
| | .sf-emoji-cat{border:none;background:none;font-size:16px;padding:4px 8px;cursor:pointer;border-radius:4px;opacity:.5} |
| .sf-upload-zone:hover { border-color: #1877f2; background: #f0f7ff; }
| | .sf-emoji-cat:hover,.sf-emoji-cat.active{opacity:1;background:#f0f2f5} |
| .sf-upload-zone.dragover { border-color: #1877f2; background: #e3f2fd; }
| | .sf-emoji-list{display:grid;grid-template-columns:repeat(8,1fr);gap:2px;max-height:180px;overflow-y:auto} |
| .sf-upload-icon { font-size: 48px; margin-bottom: 12px; }
| | .sf-emoji-list button{border:none;background:none;font-size:20px;padding:4px;cursor:pointer;border-radius:4px} |
| .sf-upload-text { color: #65676b; font-size: 14px; }
| | .sf-emoji-list button:hover{background:#f0f2f5} |
| .sf-upload-progress { display: none; margin-top: 12px; }
| | .sf-pending{display:none;padding:8px 16px;margin-bottom:8px;background:#fff;border-radius:8px} |
| .sf-progress-bar { height: 8px; background: #e4e6eb; border-radius: 4px; overflow: hidden; }
| | .sf-pending.show{display:flex;align-items:center;gap:8px} |
| .sf-progress-fill { height: 100%; background: #1877f2; width: 0%; transition: width 0.3s; }
| | .sf-pending img,.sf-pending video{max-height:80px;border-radius:6px} |
| .sf-preview-thumb { max-width: 100%; max-height: 150px; border-radius: 8px; margin-top: 12px; }
| | .sf-del{margin-left:auto;border:none;background:none;color:#65676b;cursor:pointer} |
| .sf-emoji-picker { display: none; position: absolute; bottom: 50px; left: 50px; background: white; border-radius: 12px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); padding: 12px; width: 280px; z-index: 100; }
| |
| .sf-emoji-picker.active { display: block; }
| |
| .sf-emoji-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 4px; max-height: 200px; overflow-y: auto; }
| |
| .sf-emoji-btn { background: none; border: none; font-size: 22px; padding: 6px; cursor: pointer; border-radius: 6px; }
| |
| .sf-emoji-btn:hover { background: #f0f2f5; }
| |
| .sf-emoji-tabs { display: flex; gap: 4px; margin-bottom: 8px; border-bottom: 1px solid #e4e6eb; padding-bottom: 8px; }
| |
| .sf-emoji-tab { background: none; border: none; font-size: 18px; padding: 6px 10px; cursor: pointer; border-radius: 6px; opacity: 0.5; }
| |
| .sf-emoji-tab:hover, .sf-emoji-tab.active { opacity: 1; background: #f0f2f5; }
| |
| .sf-story-viewer { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: #000; z-index: 10000; }
| |
| .sf-story-viewer.active { display: flex; align-items: center; justify-content: center; }
| |
| .sf-story-viewer img { max-width: 100%; max-height: 100%; object-fit: contain; }
| |
| .sf-story-close { position: absolute; top: 20px; right: 20px; background: rgba(255,255,255,0.2); border: none; color: white; font-size: 24px; width: 40px; height: 40px; border-radius: 50%; cursor: pointer; }
| |
| .sf-story-progress { position: absolute; top: 10px; left: 10px; right: 10px; height: 3px; background: rgba(255,255,255,0.3); border-radius: 2px; }
| |
| .sf-story-progress-fill { height: 100%; background: white; border-radius: 2px; animation: storyProgress 5s linear forwards; }
| |
| @keyframes storyProgress { from { width: 0%; } to { width: 100%; } }
| |
| </style> | | </style> |
|
| |
|
| <div class="sf-stories" id="stories-container"> | | <div class="sf-card sf-stories" id="stories"></div> |
| <div class="sf-story-item">
| |
| <button class="sf-create-story" id="add-story-btn">+</button>
| |
| <span class="sf-story-name">Add Story</span>
| |
| </div>
| |
| </div> | |
|
| |
|
| <div class="sf-composer"> | | <div class="sf-card sf-composer"> |
| <div class="sf-composer-main"> | | <div class="sf-composer-top"> |
| <div class="sf-avatar" id="composer-avatar"><span id="avatar-text">?</span><div class="sf-avatar-edit">Edit</div></div> | | <div class="sf-avatar" id="my-avatar"></div> |
| <textarea class="sf-composer-input" id="post-content" placeholder="What is on your mind?"></textarea> | | <textarea class="sf-composer-input" id="post-text" placeholder="What's on your mind?"></textarea> |
| </div> | | </div> |
| | <div class="sf-pending" id="pending-media"></div> |
| | <div class="sf-pending" id="pending-location"></div> |
| <div class="sf-composer-actions"> | | <div class="sf-composer-actions"> |
| <div class="sf-action-buttons"> | | <div class="sf-composer-btns" style="position:relative"> |
| <button class="sf-action-btn" id="add-image-btn" title="Add Photo">🖼️</button> | | <button class="sf-icon-btn" id="btn-photo" title="Photo">🖼️</button> |
| <button class="sf-action-btn" id="add-emoji-btn" title="Add Emoji">😊</button> | | <button class="sf-icon-btn" id="btn-emoji" title="Emoji">😊</button> |
| <button class="sf-action-btn" id="add-video-btn" title="Add Video">🎬</button> | | <button class="sf-icon-btn" id="btn-video" title="Video">🎬</button> |
| <button class="sf-action-btn" id="add-location-btn" title="Add Location">📍</button> | | <button class="sf-icon-btn" id="btn-location" title="Location">📍</button> |
| <div class="sf-emoji-picker" id="emoji-picker"> | | <div class="sf-emoji-picker" id="emoji-picker"></div> |
| <div class="sf-emoji-tabs">
| |
| <button class="sf-emoji-tab active" data-cat="smileys">😀</button>
| |
| <button class="sf-emoji-tab" data-cat="gestures">👋</button>
| |
| <button class="sf-emoji-tab" data-cat="animals">🐱</button>
| |
| <button class="sf-emoji-tab" data-cat="food">🍕</button>
| |
| <button class="sf-emoji-tab" data-cat="activities">⚽</button>
| |
| <button class="sf-emoji-tab" data-cat="objects">💡</button>
| |
| <button class="sf-emoji-tab" data-cat="symbols">❤️</button>
| |
| </div>
| |
| <div class="sf-emoji-grid" id="emoji-grid"></div>
| |
| </div> | |
| </div> | | </div> |
| <button class="sf-post-btn" id="post-btn">Post</button> | | <button class="sf-btn" id="btn-post">Post</button> |
| </div> | | </div> |
| </div> | | </div> |
|
| |
|
| <div id="location-preview">📍 <span id="location-text"></span> <button id="remove-location-btn" style="margin-left:10px;padding:2px 8px;font-size:12px;">✕</button></div> | | <div id="feed"></div> |
| | |
| <div id="image-preview"><img id="preview-img"><video id="preview-video" controls style="display:none"></video><button id="remove-image-btn" style="margin-left:10px;padding:5px 10px;">Remove</button></div>
| |
| | |
| <div id="timeline-container"><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" id="modal-profile"> |
| <div class="sf-modal-content"> | | <div class="sf-modal-box"> |
| <div class="sf-modal-title">Set Profile Photo</div> | | <div class="sf-modal-title">Profile Photo</div> |
| <div class="sf-tabs"> | | <div class="sf-tabs"><div class="sf-tab active" data-t="p-upload">Upload</div><div class="sf-tab" data-t="p-url">URL</div></div> |
| <div class="sf-tab active" data-ptab="pupload">Upload</div> | | <div class="sf-tab-panel active" id="p-upload"> |
| <div class="sf-tab" data-ptab="purl">From URL</div> | | <div class="sf-upload-area" id="profile-drop"><div style="font-size:32px;margin-bottom:8px">📸</div><div style="color:#65676b">Click or drag image</div><input type="file" accept="image/*" style="display:none"></div> |
| </div> | | <div class="sf-progress" style="display:none"><div class="sf-progress-bar"></div></div> |
| <div class="sf-tab-content active" id="tab-pupload"> | | <img class="sf-preview" style="display:none"> |
| <div class="sf-upload-zone" id="profile-upload-zone"> | |
| <div class="sf-upload-icon">📸</div> | |
| <div class="sf-upload-text">Click to select or drag photo here</div> | |
| <input type="file" id="profile-file-input" accept="image/*" style="display:none"> | |
| </div> | |
| <div class="sf-upload-progress" id="profile-upload-progress"> | |
| <div class="sf-progress-bar"><div class="sf-progress-fill" id="profile-progress-fill"></div></div> | |
| <p style="font-size:12px;color:#65676b;margin-top:8px;" id="profile-upload-status">Uploading...</p>
| |
| </div> | |
| <img class="sf-preview-thumb" id="profile-upload-preview" style="display:none"> | |
| </div> | | </div> |
| <div class="sf-tab-content" id="tab-purl"> | | <div class="sf-tab-panel" id="p-url"> |
| <input type="text" class="sf-modal-input" id="profile-url-input" placeholder="Paste image URL..."> | | <input class="sf-input" placeholder="Paste image URL..." id="profile-url"> |
| <img class="sf-preview-thumb" id="profile-url-preview" style="display:none"> | | <img class="sf-preview" style="display:none"> |
| </div> | | </div> |
| <div class="sf-modal-buttons"> | | <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px"> |
| <button class="sf-modal-btn sf-modal-btn-cancel" id="profile-cancel-btn">Cancel</button> | | <button class="sf-btn sf-btn-light" onclick="closeModal('modal-profile')">Cancel</button> |
| <button class="sf-modal-btn sf-modal-btn-save" id="profile-save-btn">Save</button> | | <button class="sf-btn" id="profile-save">Save</button> |
| </div> | | </div> |
| </div> | | </div> |
| </div> | | </div> |
|
| |
|
| <div class="sf-modal" id="story-modal"> | | <div class="sf-modal" id="modal-photo"> |
| <div class="sf-modal-content"> | | <div class="sf-modal-box"> |
| <div class="sf-modal-title">Add Story</div> | | <div class="sf-modal-title">Add Photo</div> |
| <div class="sf-tabs"> | | <div class="sf-tabs"><div class="sf-tab active" data-t="i-upload">Upload</div><div class="sf-tab" data-t="i-url">URL</div></div> |
| <div class="sf-tab active" data-stab="supload">Upload</div> | | <div class="sf-tab-panel active" id="i-upload"> |
| <div class="sf-tab" data-stab="surl">From URL</div> | | <div class="sf-upload-area" id="photo-drop"><div style="font-size:32px;margin-bottom:8px">📤</div><div style="color:#65676b">Click or drag image</div><input type="file" accept="image/*" style="display:none"></div> |
| </div> | | <div class="sf-progress" style="display:none"><div class="sf-progress-bar"></div></div> |
| <div class="sf-tab-content active" id="tab-supload"> | | <img class="sf-preview" style="display:none"> |
| <div class="sf-upload-zone" id="story-upload-zone"> | |
| <div class="sf-upload-icon">📷</div> | |
| <div class="sf-upload-text">Click to select or drag image here</div> | |
| <input type="file" id="story-file-input" accept="image/*" style="display:none"> | |
| </div> | |
| <div class="sf-upload-progress" id="story-upload-progress"> | |
| <div class="sf-progress-bar"><div class="sf-progress-fill" id="story-progress-fill"></div></div> | |
| <p style="font-size:12px;color:#65676b;margin-top:8px;" id="story-upload-status">Uploading...</p>
| |
| </div> | |
| <img class="sf-preview-thumb" id="story-upload-preview" style="display:none"> | |
| </div> | | </div> |
| <div class="sf-tab-content" id="tab-surl"> | | <div class="sf-tab-panel" id="i-url"> |
| <input type="text" class="sf-modal-input" id="story-url-input" placeholder="Paste image URL..."> | | <input class="sf-input" placeholder="Paste image URL..." id="photo-url"> |
| <img class="sf-preview-thumb" id="story-url-preview" style="display:none"> | | <img class="sf-preview" style="display:none"> |
| </div> | | </div> |
| <div class="sf-modal-buttons"> | | <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px"> |
| <button class="sf-modal-btn sf-modal-btn-cancel" id="story-cancel-btn">Cancel</button> | | <button class="sf-btn sf-btn-light" onclick="closeModal('modal-photo')">Cancel</button> |
| <button class="sf-modal-btn sf-modal-btn-save" id="story-add-btn">Add Story</button> | | <button class="sf-btn" id="photo-add">Add</button> |
| </div> | | </div> |
| </div> | | </div> |
| </div> | | </div> |
|
| |
|
| <div class="sf-modal" id="image-modal"> | | <div class="sf-modal" id="modal-video"> |
| <div class="sf-modal-content"> | | <div class="sf-modal-box"> |
| <div class="sf-modal-title">Add Photo</div> | | <div class="sf-modal-title">Add Video</div> |
| <div class="sf-tabs"> | | <div class="sf-tabs"><div class="sf-tab active" data-t="v-upload">Upload</div><div class="sf-tab" data-t="v-url">URL</div></div> |
| <div class="sf-tab active" data-tab="upload">Upload</div> | | <div class="sf-tab-panel active" id="v-upload"> |
| <div class="sf-tab" data-tab="url">From URL</div> | | <div class="sf-upload-area" id="video-drop"><div style="font-size:32px;margin-bottom:8px">🎬</div><div style="color:#65676b">Click or drag video</div><input type="file" accept="video/*" style="display:none"></div> |
| </div> | | <div class="sf-progress" style="display:none"><div class="sf-progress-bar"></div></div> |
| <div class="sf-tab-content active" id="tab-upload"> | | <video class="sf-preview" controls style="display:none"></video> |
| <div class="sf-upload-zone" id="upload-zone"> | |
| <div class="sf-upload-icon">📤</div> | |
| <div class="sf-upload-text">Click to select or drag image here</div> | |
| <input type="file" id="file-input" accept="image/*" style="display:none"> | |
| </div> | |
| <div class="sf-upload-progress" id="upload-progress"> | |
| <div class="sf-progress-bar"><div class="sf-progress-fill" id="progress-fill"></div></div> | |
| <p style="font-size:12px;color:#65676b;margin-top:8px;" id="upload-status">Uploading...</p> | |
| </div>
| |
| <img class="sf-preview-thumb" id="upload-preview" style="display:none">
| |
| </div> | | </div> |
| <div class="sf-tab-content" id="tab-url"> | | <div class="sf-tab-panel" id="v-url"> |
| <input type="text" class="sf-modal-input" id="image-url-input" placeholder="Paste image URL..."> | | <input class="sf-input" placeholder="YouTube, Vimeo, or direct URL..." id="video-url"> |
| <img class="sf-preview-thumb" id="url-preview" style="display:none">
| |
| </div> | | </div> |
| <div class="sf-modal-buttons"> | | <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px"> |
| <button class="sf-modal-btn sf-modal-btn-cancel" id="image-cancel-btn">Cancel</button> | | <button class="sf-btn sf-btn-light" onclick="closeModal('modal-video')">Cancel</button> |
| <button class="sf-modal-btn sf-modal-btn-save" id="image-add-btn">Add Image</button> | | <button class="sf-btn" id="video-add">Add</button> |
| </div> | | </div> |
| </div> | | </div> |
| </div> | | </div> |
|
| |
|
| <div class="sf-modal" id="video-modal"> | | <div class="sf-modal" id="modal-story"> |
| <div class="sf-modal-content"> | | <div class="sf-modal-box"> |
| <div class="sf-modal-title">Add Video</div> | | <div class="sf-modal-title">Add Story</div> |
| <div class="sf-tabs"> | | <div class="sf-tabs"><div class="sf-tab active" data-t="s-upload">Upload</div><div class="sf-tab" data-t="s-url">URL</div></div> |
| <div class="sf-tab active" data-vtab="vupload">Upload</div> | | <div class="sf-tab-panel active" id="s-upload"> |
| <div class="sf-tab" data-vtab="vurl">From URL</div> | | <div class="sf-upload-area" id="story-drop"><div style="font-size:32px;margin-bottom:8px">📷</div><div style="color:#65676b">Click or drag image</div><input type="file" accept="image/*" style="display:none"></div> |
| </div> | | <div class="sf-progress" style="display:none"><div class="sf-progress-bar"></div></div> |
| <div class="sf-tab-content active" id="tab-vupload"> | | <img class="sf-preview" style="display:none"> |
| <div class="sf-upload-zone" id="video-upload-zone"> | |
| <div class="sf-upload-icon">🎬</div> | |
| <div class="sf-upload-text">Click to select or drag video here</div> | |
| <input type="file" id="video-file-input" accept="video/*" style="display:none"> | |
| </div> | |
| <div class="sf-upload-progress" id="video-upload-progress"> | |
| <div class="sf-progress-bar"><div class="sf-progress-fill" id="video-progress-fill"></div></div> | |
| <p style="font-size:12px;color:#65676b;margin-top:8px;" id="video-upload-status">Uploading...</p>
| |
| </div> | |
| <video class="sf-preview-thumb" id="video-upload-preview" controls style="display:none;max-height:150px;"></video> | |
| </div> | | </div> |
| <div class="sf-tab-content" id="tab-vurl"> | | <div class="sf-tab-panel" id="s-url"> |
| <input type="text" class="sf-modal-input" id="video-url-input" placeholder="Paste video URL (YouTube, Vimeo, or direct link)..."> | | <input class="sf-input" placeholder="Paste image URL..." id="story-url"> |
| <p style="font-size:12px;color:#65676b;margin-bottom:12px;">Supports YouTube, Vimeo, or direct video URLs</p>
| |
| </div> | | </div> |
| <div class="sf-modal-buttons"> | | <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px"> |
| <button class="sf-modal-btn sf-modal-btn-cancel" id="video-cancel-btn">Cancel</button> | | <button class="sf-btn sf-btn-light" onclick="closeModal('modal-story')">Cancel</button> |
| <button class="sf-modal-btn sf-modal-btn-save" id="video-add-btn">Add Video</button> | | <button class="sf-btn" id="story-add">Add Story</button> |
| </div> | | </div> |
| </div> | | </div> |
| </div> | | </div> |
|
| |
|
| <div class="sf-modal" id="location-modal"> | | <div class="sf-modal" id="modal-location"> |
| <div class="sf-modal-content"> | | <div class="sf-modal-box"> |
| <div class="sf-modal-title">Add Location</div> | | <div class="sf-modal-title">Add Location</div> |
| <button class="sf-modal-btn sf-modal-btn-save" id="detect-location-btn" style="width:100%;margin-bottom:12px;">📍 Use Current Location</button> | | <button class="sf-btn" id="detect-loc" style="width:100%;margin-bottom:12px">📍 Use Current Location</button> |
| <p style="text-align:center;color:#65676b;margin-bottom:12px;">— or —</p> | | <div style="text-align:center;color:#65676b;margin-bottom:12px">— or —</div> |
| <input type="text" class="sf-modal-input" id="location-input" placeholder="Enter location manually..."> | | <input class="sf-input" placeholder="Enter location..." id="loc-input"> |
| <div class="sf-modal-buttons"> | | <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:16px"> |
| <button class="sf-modal-btn sf-modal-btn-cancel" id="location-cancel-btn">Cancel</button> | | <button class="sf-btn sf-btn-light" onclick="closeModal('modal-location')">Cancel</button> |
| <button class="sf-modal-btn sf-modal-btn-save" id="location-add-btn">Add Location</button> | | <button class="sf-btn" id="loc-add">Add</button> |
| </div> | | </div> |
| </div> | | </div> |
| </div> | | </div> |
|
| |
|
| <div class="sf-story-viewer" id="story-viewer"> | | <div class="sf-viewer" id="story-viewer"> |
| <div class="sf-story-progress"><div class="sf-story-progress-fill" id="story-progress-bar"></div></div> | | <div class="sf-viewer-progress"><span></span></div> |
| <button class="sf-story-close" id="story-close-btn">✕</button> | | <button class="sf-viewer-close">✕</button> |
| <img id="story-viewer-img" src=""> | | <img src=""> |
| </div> | | </div> |
|
| |
|
| <script> | | <script> |
| $(function(){
| | (function(){ |
| $.when(mw.loader.using(['mediawiki.api','mediawiki.util'])).then(function(){ | | var $=window.jQuery,mw=window.mw; |
| var apiBase=mw.util.wikiScript('api'); | | if(!$||!mw){console.error('jQuery or mw not found');return;} |
| | |
| | $.when(mw.loader.using(['mediawiki.api','mediawiki.util']),$.ready).then(function(){ |
| | var api=new mw.Api(); |
| | var apiUrl=mw.util.wikiScript('api'); |
| var user=mw.config.get('wgUserName')||'Guest'; | | var user=mw.config.get('wgUserName')||'Guest'; |
| var api=new mw.Api();
| | var photo=localStorage.getItem('sfphoto_'+user)||''; |
| | | var pending={img:'',video:'',loc:''}; |
| var photo=localStorage.getItem('sf_photo_'+user)||''; | | var uploads={profile:null,photo:null,video:null,story:null}; |
| var pendingImg=''; | |
| var pendingVideo='';
| |
| var pendingLocation='';
| |
| var uploadedFile=null; | |
| var mediaType='image';
| |
|
| |
|
| var emojis={ | | var emojis={ |
| smileys:['😀','😃','😄','😁','😅','😂','🤣','😊','😇','🙂','😉','😌','😍','🥰','😘','😋','😛','😜','🤪','😝','🤑','🤗','🤭','🤫','🤔','🤐','🤨','😐','😑','😶','😏','😒','🙄','😬','😮','🤯','😳','🥺','😢','😭','😤','😠','😡','🤬','😈','👿','💀','☠️','💩','🤡','👹','👺','👻','👽','🤖'],
| | '😀':['😀','😃','😄','😁','😅','😂','🤣','😊','😇','🙂','😉','😍','🥰','😘','😋','😛','😜','🤪','😎','🤩','🥳','😏','😒','😞','😔','😟','😕','🙁','😣','😖','😫','😩','🥺','😢','😭','😤','😠','😡','🤬','😈','👿','💀','💩','🤡','👻','👽','🤖','😺','😸','😹','😻','😼','😽','🙀','😿','😾'], |
| gestures:['👋','🤚','🖐️','✋','🖖','👌','🤌','🤏','✌️','🤞','🤟','🤘','🤙','👈','👉','👆','👇','☝️','👍','👎','✊','👊','🤛','🤜','👏','🙌','👐','🤲','🤝','🙏','✍️','💪','🦵','🦶','👂','👃','🧠','🫀','🫁','🦷','🦴','👀','👁️','👅','👄'],
| | '👋':['👋','🤚','🖐','✋','🖖','👌','🤌','🤏','✌','🤞','🤟','🤘','🤙','👈','👉','👆','🖕','👇','☝','👍','👎','✊','👊','🤛','🤜','👏','🙌','👐','🤲','🤝','🙏','✍','💪','🦾','🦿','🦵','🦶','👂','🦻','👃','👀','👁','👅','👄','💋','🧠','🫀','🫁','🦷','🦴'], |
| animals:['🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🐨','🐯','🦁','🐮','🐷','🐸','🐵','🐔','🐧','🐦','🐤','🦆','🦅','🦉','🦇','🐺','🐗','🐴','🦄','🐝','🐛','🦋','🐌','🐞','🐜','🦟','🐢','🐍','🦎','🦂','🦀','🦑','🐙','🦐','🐠','🐟','🐬','🐳','🦈','🐊','🐅','🐆','🦓','🦍','🐘','🦛','🦏'],
| | '🐶':['🐶','🐱','🐭','🐹','🐰','🦊','🐻','🐼','🐨','🐯','🦁','🐮','🐷','🐸','🐵','🐔','🐧','🐦','🐤','🦆','🦅','🦉','🦇','🐺','🐗','🐴','🦄','🐝','🐛','🦋','🐌','🐞','🐜','🦟','🐢','🐍','🦎','🦂','🦀','🦑','🐙','🦐','🐠','🐟','🐬','🐳','🦈','🐊','🐅','🐆','🦓','🦍','🐘','🦛','🦏','🐪','🦒','🦘','🐃','🐂','🐄','🐎','🐖','🐏','🐑','🦙','🐐','🦌','🐕','🐩','🦮','🐈','🐓','🦃','🦚','🦜','🦢','🦩','🐇','🦝','🦨','🦡','🦫','🦦','🦥','🐁','🐀','🐿','🦔'], |
| food:['🍎','🍊','🍋','🍌','🍉','🍇','🍓','🫐','🍈','🍒','🍑','🥭','🍍','🥥','🥝','🍅','🥑','🥦','🥬','🥒','🌶️','🫑','🌽','🥕','🫒','🧄','🧅','🥔','🍠','🥐','🥯','🍞','🥖','🥨','🧀','🥚','🍳','🧈','🥞','🧇','🥓','🥩','🍗','🍖','🌭','🍔','🍟','🍕','🥪','🥙','🌮','🌯','🥗','🍝','🍜','🍲','🍛','🍣','🍱','🥟','🍤','🍙','🍚','🍘','🍥','🍢','🍡','🍧','🍨','🍦','🥧','🧁','🍰','🎂','🍮','🍭','🍬','🍫','🍿','🍩','🍪'],
| | '🍎':['🍎','🍊','🍋','🍌','🍉','🍇','🍓','🫐','🍈','🍒','🍑','🥭','🍍','🥥','🥝','🍅','🥑','🥦','🥬','🥒','🌶','🫑','🌽','🥕','🧄','🧅','🥔','🍠','🥐','🥯','🍞','🥖','🥨','🧀','🥚','🍳','🧈','🥞','🧇','🥓','🥩','🍗','🍖','🌭','🍔','🍟','🍕','🥪','🥙','🧆','🌮','🌯','🥗','🥘','🥫','🍝','🍜','🍲','🍛','🍣','🍱','🥟','🍤','🍙','🍚','🍘','🍥','🥠','🍢','🍡','🍧','🍨','🍦','🥧','🧁','🍰','🎂','🍮','🍭','🍬','🍫','🍿','🍩','🍪','🌰','🥜','🍯','🥛','🍼','☕','🍵','🧃','🥤','🧋','🍶','🍺','🍻','🥂','🍷','🥃','🍸','🍹','🧉','🍾','🧊'], |
| activities:['⚽','🏀','🏈','⚾','🥎','🎾','🏐','🏉','🥏','🎱','🏓','🏸','🏒','🏑','🥍','🏏','🥅','⛳','🏹','🎣','🥊','🥋','🎽','🛹','🛷','⛸️','🥌','🎿','⛷️','🏂','🏋️','🤼','🤸','🤺','⛹️','🤾','🏌️','🏇','🧘','🏄','🏊','🤽','🚣','🧗','🚴','🚵','🎖️','🏆','🥇','🥈','🥉','🏅','🎪','🤹','🎭','🎨','🎬','🎤','🎧','🎼','🎹','🥁','🎷','🎺','🎸','🎻','🎲','♟️','🎯','🎳','🎮','🎰'],
| | '⚽':['⚽','🏀','🏈','⚾','🥎','🎾','🏐','🏉','🥏','🎱','🪀','🏓','🏸','🏒','🏑','🥍','🏏','🪃','🥅','⛳','🪁','🏹','🎣','🤿','🥊','🥋','🎽','🛹','🛼','🛷','⛸','🥌','🎿','⛷','🏂','🪂','🏋','🤼','🤸','⛹','🤺','🤾','🏌','🏇','🧘','🏄','🏊','🤽','🚣','🧗','🚵','🚴','🏆','🥇','🥈','🥉','🏅','🎖','🏵','🎗','🎫','🎟','🎪','🎭','🎨','🎬','🎤','🎧','🎼','🎹','🥁','🪘','🎷','🎺','🪗','🎸','🪕','🎻','🎲','♟','🎯','🎳','🎮','🎰','🧩'], |
| objects:['💡','🔦','🕯️','📱','💻','🖥️','🖨️','⌨️','🖱️','💾','💿','📀','📷','📸','📹','🎥','📽️','📞','☎️','📟','📠','📺','📻','🎙️','🎚️','🎛️','🧭','⏱️','⏲️','⏰','🕰️','⌛','⏳','📡','🔋','🔌','💰','💵','💴','💶','💷','💳','💎','⚖️','🧰','🔧','🔨','🛠️','⛏️','🔩','⚙️','🧱','🔫','💣','🔪','🗡️','⚔️','🛡️','🚬','⚰️','⚱️','🏺','🔮','📿','🧿','💈','⚗️','🔭','🔬','🕳️','🩹','🩺','💊','💉','🧬','🦠','🧫','🧪','🌡️','🧹','🧺','🧻','🚽','🚿','🛁','🧼','🧽','🧴','🛎️','🔑','🗝️','🚪','🛋️','🛏️','🧸','🖼️','🛍️','🛒','🎁','🎈','🎏','🎀','🎊','🎉','🎎','🏮','🎐','🧧','✉️','📩','📨','📧','💌','📥','📤','📦','🏷️','📪','📫','📬','📭','📮','📯','📜','📃','📄','📑','🧾','📊','📈','📉','📆','📅','🗑️','📋','📁','📂','📰','📓','📔','📒','📕','📗','📘','📙','📚','📖','🔖','🔗','📎','📐','📏','🧮','📌','📍','✂️','🖊️','🖋️','✒️','🖌️','🖍️','📝','✏️','🔍','🔎','🔏','🔐','🔒','🔓'],
| | '❤️':['❤️','🧡','💛','💚','💙','💜','🖤','🤍','🤎','💔','❣️','💕','💞','💓','💗','💖','💘','💝','💟','☮️','✝️','☪️','🕉️','☸️','✡️','🔯','🕎','☯️','☦️','🛐','⛎','♈','♉','♊','♋','♌','♍','♎','♏','♐','♑','♒','♓','🆔','⚛️','🉑','☢️','☣️','📴','📳','🈶','🈚','🈸','🈺','🈷️','✴️','🆚','💮','🉐','㊙️','㊗️','🈴','🈵','🈹','🈲','🅰️','🅱️','🆎','🆑','🅾️','🆘','❌','⭕','🛑','⛔','📛','🚫','💯','💢','♨️','🚷','🚯','🚳','🚱','🔞','📵','🚭','❗','❕','❓','❔','‼️','⁉️','🔅','🔆','〽️','⚠️','🚸','🔱','⚜️','🔰','♻️','✅','🈯','💹','❇️','✳️','❎','🌐','💠'] |
| symbols:['❤️','🧡','💛','💚','💙','💜','🖤','🤍','🤎','💔','❣️','💕','💞','💓','💗','💖','💘','💝','💟','☮️','✝️','☪️','🕉️','☸️','✡️','🔯','🕎','☯️','☦️','🛐','⛎','♈','♉','♊','♋','♌','♍','♎','♏','♐','♑','♒','♓','🆔','⚛️','☢️','☣️','📴','📳','✴️','🆚','💮','㊙️','㊗️','🅰️','🅱️','🆎','🆑','🅾️','🆘','❌','⭕','🛑','⛔','📛','🚫','💯','💢','♨️','🚷','🚯','🚳','🚱','🔞','📵','🚭','❗','❕','❓','❔','‼️','⁉️','🔅','🔆','〽️','⚠️','🚸','🔱','⚜️','🔰','♻️','✅','💹','❇️','✳️','❎','🌐','💠','Ⓜ️','🌀','💤','🏧','🚾','♿','🅿️','🈳','🈂️','🛂','🛃','🛄','🛅','🚹','🚺','🚼','⚧️','🚻','🚮','🎦','📶','🔣','ℹ️','🔤','🔡','🔠','🆖','🆗','🆙','🆒','🆕','🆓','0️⃣','1️⃣','2️⃣','3️⃣','4️⃣','5️⃣','6️⃣','7️⃣','8️⃣','9️⃣','🔟','🔢','#️⃣','*️⃣','⏏️','▶️','⏸️','⏯️','⏹️','⏺️','⏭️','⏮️','⏩','⏪','⏫','⏬','◀️','🔼','🔽','➡️','⬅️','⬆️','⬇️','↗️','↘️','↙️','↖️','↕️','↔️','↪️','↩️','⤴️','⤵️','🔀','🔁','🔂','🔄','🔃','🎵','🎶','➕','➖','➗','✖️','🟰','♾️','💲','💱','™️','©️','®️','〰️','➰','➿','🔚','🔙','🔛','🔝','🔜','✔️','☑️','🔘','🔴','🟠','🟡','🟢','🔵','🟣','⚫','⚪','🟤','🔺','🔻','🔸','🔹','🔶','🔷','🔳','🔲','▪️','▫️','◾','◽','◼️','◻️','🟥','🟧','🟨','🟩','🟦','🟪','⬛','⬜','🟫','🔈','🔇','🔉','🔊','🔔','🔕','📣','📢','💬','💭','🗯️','♠️','♣️','♥️','♦️','🃏','🎴','🀄']
| |
| }; | | }; |
|
| |
|
| function init(n){return n.split(/[\s_]+/).map(function(w){return w[0]||'';}).join('').substring(0,2).toUpperCase()||'?';} | | function initials(n){return(n||'?').split(/[\s_]+/).map(function(w){return w[0]||'';}).join('').substring(0,2).toUpperCase()||'?';} |
| function esc(t){var d=document.createElement('div');d.textContent=t;return d.innerHTML;} | | function esc(s){var d=document.createElement('div');d.textContent=s;return d.innerHTML;} |
| function ago(d){var s=Math.floor((Date.now()-d)/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 timeAgo(d){var s=Math.floor((Date.now()-new Date(d))/1e3);if(s<60)return'now';if(s<3600)return Math.floor(s/60)+'m';if(s<86400)return Math.floor(s/3600)+'h';return Math.floor(s/86400)+'d';} |
| function gel(id){return document.getElementById(id);}
| |
|
| |
|
| function apiGet(params){ | | function renderAvatar(el,name,pic){ |
| return api.get(params);
| | el=$(el); |
| | if(pic)el.html('<img src="'+pic+'">'); |
| | else el.text(initials(name)); |
| } | | } |
|
| |
|
| function apiPost(params){ | | function openModal(id){$('#'+id).addClass('open');} |
| return api.postWithToken('csrf',params);
| | window.closeModal=function(id){$('#'+id).removeClass('open');} |
| } | |
|
| |
|
| function getToken(){ | | function setupTabs(container){ |
| return api.getToken('csrf');
| | $(container).on('click','.sf-tab',function(){ |
| | var t=$(this),panel=$('#'+t.data('t')); |
| | t.siblings().removeClass('active');t.addClass('active'); |
| | panel.siblings('.sf-tab-panel').removeClass('active');panel.addClass('active'); |
| | }); |
| } | | } |
|
| |
|
| function uploadFile(file,prefix,onProgress,onDone,onError){ | | function setupUpload(dropId,type,onFile){ |
| api.getToken('csrf').then(function(token){
| | var drop=$('#'+dropId),input=drop.find('input'),progress=drop.siblings('.sf-progress'),bar=progress.find('.sf-progress-bar'),preview=drop.siblings('.sf-preview'); |
| var filename=prefix+'_'+user+'_'+Date.now()+'.'+file.name.split('.').pop();
| | drop.on('click',function(){input.click();}); |
| var formData=new FormData();
| | drop.on('dragover',function(e){e.preventDefault();drop.addClass('drag');}); |
| formData.append('action','upload');
| | drop.on('dragleave drop',function(){drop.removeClass('drag');}); |
| formData.append('filename',filename);
| | drop.on('drop',function(e){e.preventDefault();if(e.originalEvent.dataTransfer.files[0])handleFile(e.originalEvent.dataTransfer.files[0]);}); |
| formData.append('file',file);
| | input.on('change',function(){if(this.files[0])handleFile(this.files[0]);}); |
| formData.append('token',token);
| | function handleFile(f){ |
| formData.append('format','json');
| | uploads[type]=f; |
| formData.append('ignorewarnings','1');
| | if(f.type.startsWith('image/')){ |
| $.ajax({
| | var r=new FileReader(); |
| url:apiBase,
| | r.onload=function(e){preview.attr('src',e.target.result).show();}; |
| type:'POST',
| | r.readAsDataURL(f); |
| data:formData,
| | }else if(f.type.startsWith('video/')){ |
| processData:false,
| | preview.attr('src',URL.createObjectURL(f)).show(); |
| contentType:false,
| |
| xhr:function(){var x=$.ajaxSettings.xhr();if(x.upload){x.upload.addEventListener('progress',function(e){if(e.lengthComputable)onProgress(Math.round(e.loaded/e.total*100));});}return x;},
| |
| success:function(resp){
| |
| if(resp.upload){
| |
| if(resp.upload.imageinfo){onDone(resp.upload.imageinfo.url);} | |
| else if(resp.upload.warnings){onError('Warning: '+JSON.stringify(resp.upload.warnings));}
| |
| else{onError('Upload issue');}
| |
| }else if(resp.error){onError(resp.error.info);} | |
| else{onError('Unknown error');}
| |
| },
| |
| error:function(xhr,status,err){onError('Upload failed: '+err);}
| |
| });
| |
| }).catch(function(e){onError('Token error: '+e);});
| |
| } | | } |
| | | if(onFile)onFile(f); |
| function setAv(){
| |
| var el=gel('composer-avatar');
| |
| if(!el)return; | |
| el.innerHTML=photo?'<img src="'+photo+'">':init(user);
| |
| el.innerHTML+='<div class="sf-avatar-edit">Edit</div>';
| |
| } | | } |
| setAv();
| | return{ |
| var postContent=gel('post-content');
| | reset:function(){uploads[type]=null;preview.hide();progress.hide();bar.css('width',0);input.val('');}, |
| if(postContent)postContent.placeholder='What is on your mind, '+user+'?';
| | progress:function(p){progress.show();bar.css('width',p+'%');}, |
| | | done:function(){bar.css('width','100%');} |
| // Profile modal tabs
| |
| var uploadedProfileFile=null;
| |
| document.querySelectorAll('[data-ptab]').forEach(function(tab){
| |
| tab.addEventListener('click',function(){
| |
| document.querySelectorAll('[data-ptab]').forEach(function(t){t.classList.remove('active');});
| |
| document.querySelectorAll('#profile-modal .sf-tab-content').forEach(function(c){c.classList.remove('active');});
| |
| tab.classList.add('active');
| |
| gel('tab-'+tab.dataset.ptab).classList.add('active');
| |
| });
| |
| });
| |
| | |
| gel('composer-avatar').addEventListener('click',function(){
| |
| gel('profile-url-input').value=photo;
| |
| gel('profile-upload-preview').style.display='none';
| |
| gel('profile-url-preview').style.display='none';
| |
| gel('profile-upload-progress').style.display='none';
| |
| uploadedProfileFile=null;
| |
| gel('profile-modal').classList.add('active');
| |
| });
| |
| gel('profile-cancel-btn').addEventListener('click',function(){gel('profile-modal').classList.remove('active');});
| |
| | |
| var profileUploadZone=gel('profile-upload-zone');
| |
| var profileFileInput=gel('profile-file-input');
| |
| profileUploadZone.addEventListener('click',function(){profileFileInput.click();});
| |
| profileUploadZone.addEventListener('dragover',function(e){e.preventDefault();profileUploadZone.classList.add('dragover');});
| |
| profileUploadZone.addEventListener('dragleave',function(){profileUploadZone.classList.remove('dragover');});
| |
| profileUploadZone.addEventListener('drop',function(e){
| |
| e.preventDefault();
| |
| profileUploadZone.classList.remove('dragover');
| |
| if(e.dataTransfer.files.length>0)handleProfileFile(e.dataTransfer.files[0]);
| |
| }); | |
| profileFileInput.addEventListener('change',function(){
| |
| if(profileFileInput.files.length>0)handleProfileFile(profileFileInput.files[0]);
| |
| });
| |
| | |
| function handleProfileFile(file){ | |
| if(!file.type.startsWith('image/')){alert('Please select an image file');return;}
| |
| uploadedProfileFile=file;
| |
| var reader=new FileReader();
| |
| reader.onload=function(e){
| |
| gel('profile-upload-preview').src=e.target.result;
| |
| gel('profile-upload-preview').style.display='block';
| |
| }; | | }; |
| reader.readAsDataURL(file);
| |
| } | | } |
|
| |
|
| gel('profile-url-input').addEventListener('input',function(){
| | function uploadToWiki(file,prefix,onProgress){ |
| var url=this.value.trim(); | | return api.getToken('csrf').then(function(token){ |
| if(url){
| | var fname=prefix+'_'+user+'_'+Date.now()+'.'+(file.name.split('.').pop()||'jpg'); |
| gel('profile-url-preview').src=url;
| | var fd=new FormData(); |
| gel('profile-url-preview').style.display='block';
| | fd.append('action','upload');fd.append('filename',fname);fd.append('file',file); |
| }else{
| | fd.append('token',token);fd.append('format','json');fd.append('ignorewarnings','1'); |
| gel('profile-url-preview').style.display='none';
| | return $.ajax({ |
| | url:apiUrl,type:'POST',data:fd,processData:false,contentType:false, |
| | xhr:function(){ |
| | var x=$.ajaxSettings.xhr(); |
| | if(x.upload)x.upload.onprogress=function(e){if(e.lengthComputable&&onProgress)onProgress(Math.round(e.loaded/e.total*100));}; |
| | return x; |
| } | | } |
| }); | | }); |
| | | }).then(function(r){ |
| gel('profile-save-btn').addEventListener('click',function(){
| | if(r.upload&&r.upload.imageinfo)return r.upload.imageinfo.url; |
| var activeTab=document.querySelector('[data-ptab].active').dataset.ptab;
| | throw new Error(r.error?r.error.info:'Upload failed'); |
| if(activeTab==='purl'){ | |
| photo=gel('profile-url-input').value.trim();
| |
| localStorage.setItem('sf_photo_'+user,photo);
| |
| setAv();
| |
| gel('profile-modal').classList.remove('active');
| |
| }else{
| |
| if(uploadedProfileFile){
| |
| gel('profile-upload-progress').style.display='block';
| |
| gel('profile-progress-fill').style.width='10%';
| |
| gel('profile-upload-status').textContent='Uploading...';
| |
| uploadFile(uploadedProfileFile,'ProfilePhoto',function(pct){
| |
| gel('profile-progress-fill').style.width=pct+'%';
| |
| },function(url){
| |
| gel('profile-progress-fill').style.width='100%';
| |
| gel('profile-upload-status').textContent='Done!';
| |
| photo=url;
| |
| localStorage.setItem('sf_photo_'+user,photo);
| |
| setAv();
| |
| setTimeout(function(){gel('profile-modal').classList.remove('active');},500);
| |
| },function(err){
| |
| gel('profile-upload-status').textContent='Error: '+err;
| |
| }); | | }); |
| }else{
| |
| alert('Please select an image to upload');
| |
| }
| |
| } | | } |
| });
| |
|
| |
| // Story modal tabs
| |
| var uploadedStoryFile=null;
| |
| document.querySelectorAll('[data-stab]').forEach(function(tab){
| |
| tab.addEventListener('click',function(){
| |
| document.querySelectorAll('[data-stab]').forEach(function(t){t.classList.remove('active');});
| |
| document.querySelectorAll('#story-modal .sf-tab-content').forEach(function(c){c.classList.remove('active');});
| |
| tab.classList.add('active');
| |
| gel('tab-'+tab.dataset.stab).classList.add('active');
| |
| });
| |
| });
| |
|
| |
|
| gel('add-story-btn').addEventListener('click',function(){
| | // Init avatar |
| gel('story-url-input').value='';
| | renderAvatar('#my-avatar',user,photo); |
| gel('story-upload-preview').style.display='none';
| | $('#my-avatar').on('click',function(){ |
| gel('story-url-preview').style.display='none';
| | uploads.profile=null; |
| gel('story-upload-progress').style.display='none';
| | $('#p-upload .sf-preview').hide();$('#p-url .sf-preview').hide(); |
| uploadedStoryFile=null;
| | $('#profile-url').val(photo); |
| gel('story-modal').classList.add('active');
| | if(photo)$('#p-url .sf-preview').attr('src',photo).show(); |
| | openModal('modal-profile'); |
| }); | | }); |
| gel('story-cancel-btn').addEventListener('click',function(){gel('story-modal').classList.remove('active');});
| |
|
| |
|
| var storyUploadZone=gel('story-upload-zone');
| | // Profile modal |
| var storyFileInput=gel('story-file-input'); | | setupTabs('#modal-profile'); |
| storyUploadZone.addEventListener('click',function(){storyFileInput.click();});
| | var profileUp=setupUpload('profile-drop','profile'); |
| storyUploadZone.addEventListener('dragover',function(e){e.preventDefault();storyUploadZone.classList.add('dragover');});
| | $('#profile-url').on('input',function(){ |
| storyUploadZone.addEventListener('dragleave',function(){storyUploadZone.classList.remove('dragover');});
| | var u=$(this).val().trim(); |
| storyUploadZone.addEventListener('drop',function(e){
| | $('#p-url .sf-preview').attr('src',u).toggle(!!u); |
| e.preventDefault();
| |
| storyUploadZone.classList.remove('dragover');
| |
| if(e.dataTransfer.files.length>0)handleStoryFile(e.dataTransfer.files[0]);
| |
| }); | | }); |
| storyFileInput.addEventListener('change',function(){
| | $('#profile-save').on('click',function(){ |
| if(storyFileInput.files.length>0)handleStoryFile(storyFileInput.files[0]); | | var activeTab=$('#modal-profile .sf-tab.active').data('t'); |
| | if(activeTab==='p-url'){ |
| | photo=$('#profile-url').val().trim(); |
| | localStorage.setItem('sfphoto_'+user,photo); |
| | renderAvatar('#my-avatar',user,photo); |
| | closeModal('modal-profile'); |
| | }else if(uploads.profile){ |
| | uploadToWiki(uploads.profile,'Profile',profileUp.progress).then(function(url){ |
| | profileUp.done(); |
| | photo=url;localStorage.setItem('sfphoto_'+user,photo); |
| | renderAvatar('#my-avatar',user,photo); |
| | setTimeout(function(){closeModal('modal-profile');profileUp.reset();},500); |
| | }).catch(function(e){alert('Upload error: '+e);}); |
| | }else{alert('Select an image');} |
| }); | | }); |
|
| |
|
| function handleStoryFile(file){
| | // Photo modal |
| if(!file.type.startsWith('image/')){alert('Please select an image file');return;}
| | setupTabs('#modal-photo'); |
| uploadedStoryFile=file;
| | var photoUp=setupUpload('photo-drop','photo'); |
| var reader=new FileReader();
| | $('#photo-url').on('input',function(){$('#i-url .sf-preview').attr('src',$(this).val()).toggle(!!$(this).val());}); |
| reader.onload=function(e){
| | $('#photo-add').on('click',function(){ |
| gel('story-upload-preview').src=e.target.result;
| | var activeTab=$('#modal-photo .sf-tab.active').data('t'); |
| gel('story-upload-preview').style.display='block';
| | if(activeTab==='i-url'){ |
| };
| | var u=$('#photo-url').val().trim(); |
| reader.readAsDataURL(file);
| | if(u){setPendingMedia('img',u);closeModal('modal-photo');} |
| } | | else alert('Enter URL'); |
| | | }else if(uploads.photo){ |
| gel('story-url-input').addEventListener('input',function(){
| | uploadToWiki(uploads.photo,'SocialPhoto',photoUp.progress).then(function(url){ |
| var url=this.value.trim(); | | photoUp.done();setPendingMedia('img',url); |
| if(url){ | | setTimeout(function(){closeModal('modal-photo');photoUp.reset();},500); |
| gel('story-url-preview').src=url;
| | }).catch(function(e){alert('Upload error: '+e);}); |
| gel('story-url-preview').style.display='block';
| | }else alert('Select an image'); |
| }else{ | |
| gel('story-url-preview').style.display='none';
| |
| } | |
| }); | | }); |
|
| |
|
| gel('story-add-btn').addEventListener('click',function(){
| | // Video modal |
| var activeTab=document.querySelector('[data-stab].active').dataset.stab; | | setupTabs('#modal-video'); |
| if(activeTab==='surl'){ | | var videoUp=setupUpload('video-drop','video'); |
| var url=gel('story-url-input').value.trim(); | | $('#video-add').on('click',function(){ |
| if(url){ | | var activeTab=$('#modal-video .sf-tab.active').data('t'); |
| createStory(url);
| | if(activeTab==='v-url'){ |
| }else{
| | var u=$('#video-url').val().trim(); |
| alert('Please enter an image URL'); | | if(u){setPendingMedia('video',u);closeModal('modal-video');} |
| }
| | else alert('Enter URL'); |
| }else{ | | }else if(uploads.video){ |
| if(uploadedStoryFile){ | | uploadToWiki(uploads.video,'SocialVideo',videoUp.progress).then(function(url){ |
| gel('story-upload-progress').style.display='block';
| | videoUp.done();setPendingMedia('video',url); |
| gel('story-progress-fill').style.width='10%';
| | setTimeout(function(){closeModal('modal-video');videoUp.reset();},500); |
| gel('story-upload-status').textContent='Uploading...';
| | }).catch(function(e){alert('Upload error: '+e);}); |
| uploadFile(uploadedStoryFile,'Story',function(pct){
| | }else alert('Select a video'); |
| gel('story-progress-fill').style.width=pct+'%';
| |
| },function(url){
| |
| gel('story-progress-fill').style.width='100%';
| |
| gel('story-upload-status').textContent='Done!';
| |
| setTimeout(function(){ | |
| gel('story-modal').classList.remove('active');
| |
| createStory(url);
| |
| },500); | |
| },function(err){ | |
| gel('story-upload-status').textContent='Error: '+err;
| |
| }); | |
| }else{ | |
| alert('Please select an image to upload'); | |
| }
| |
| }
| |
| }); | | }); |
|
| |
|
| function createStory(imageUrl){
| | // Story modal |
| getToken().then(function(token){
| | setupTabs('#modal-story'); |
| return apiPost({action:'socialfeed',sfaction:'createstory',image_url:imageUrl,token:token});
| | var storyUp=setupUpload('story-drop','story'); |
| }).then(function(d){
| | $('#story-url').on('input',function(){$('#s-url .sf-preview').attr('src',$(this).val()).toggle(!!$(this).val());}); |
| if(d.error){alert('Error: '+d.error.info);return;}
| | $('#story-add').on('click',function(){ |
| loadStories();
| | var activeTab=$('#modal-story .sf-tab.active').data('t'); |
| gel('story-modal').classList.remove('active');
| | function postStory(url){ |
| }).catch(function(e){alert('Error creating story');});
| | api.postWithToken('csrf',{action:'socialfeed',sfaction:'createstory',image_url:url}).then(function(){ |
| }
| | closeModal('modal-story');storyUp.reset();$('#story-url').val('');loadStories(); |
| | | }).catch(function(e){alert('Error: '+e);}); |
| function loadStories(){ | |
| apiGet({action:'socialfeed',sfaction:'getstories'}).then(function(d){
| |
| renderStories((d.socialfeed?d.socialfeed.stories:[])||[]);
| |
| }).catch(function(){}); | |
| } | | } |
| | | if(activeTab==='s-url'){ |
| function renderStories(stories){
| | var u=$('#story-url').val().trim(); |
| var container=gel('stories-container'); | | if(u)postStory(u);else alert('Enter URL'); |
| var h='<div class="sf-story-item"><button class="sf-create-story" id="add-story-btn">+</button><span class="sf-story-name">Add Story</span></div>';
| | }else if(uploads.story){ |
| stories.forEach(function(s){
| | uploadToWiki(uploads.story,'Story',storyUp.progress).then(function(url){ |
| var pic=localStorage.getItem('sf_photo_'+s.username)||'';
| | storyUp.done();setTimeout(function(){postStory(url);},500); |
| var av=pic?'<img src="'+pic+'">':init(s.username);
| | }).catch(function(e){alert('Upload error: '+e);}); |
| h+='<div class="sf-story-item"><div class="sf-story-ring"><div class="sf-story-avatar" data-story="'+s.image_url+'">'+av+'</div></div><span class="sf-story-name">'+esc(s.username)+'</span></div>';
| | }else alert('Select an image'); |
| }); | | }); |
| container.innerHTML=h;
| |
|
| |
|
| gel('add-story-btn').addEventListener('click',function(){
| | // Location modal |
| gel('story-url-input').value='';
| | $('#detect-loc').on('click',function(){ |
| gel('story-upload-preview').style.display='none';
| | var btn=$(this);btn.text('Detecting...'); |
| gel('story-url-preview').style.display='none';
| | if(navigator.geolocation){ |
| gel('story-upload-progress').style.display='none';
| | navigator.geolocation.getCurrentPosition(function(p){ |
| uploadedStoryFile=null;
| | $.getJSON('https://nominatim.openstreetmap.org/reverse?format=json&lat='+p.coords.latitude+'&lon='+p.coords.longitude,function(d){ |
| gel('story-modal').classList.add('active');
| | $('#loc-input').val((d.display_name||'').split(',').slice(0,3).join(',')||p.coords.latitude+','+p.coords.longitude); |
| });
| | btn.text('📍 Use Current Location'); |
| | | }).fail(function(){$('#loc-input').val(p.coords.latitude+','+p.coords.longitude);btn.text('📍 Use Current Location');}); |
| container.querySelectorAll('[data-story]').forEach(function(el){
| | },function(){alert('Location unavailable');btn.text('📍 Use Current Location');}); |
| el.addEventListener('click',function(){
| | }else alert('Geolocation not supported'); |
| gel('story-viewer-img').src=el.dataset.story;
| |
| gel('story-viewer').classList.add('active');
| |
| gel('story-progress-bar').style.animation='none';
| |
| setTimeout(function(){gel('story-progress-bar').style.animation='storyProgress 5s linear forwards';},10);
| |
| setTimeout(function(){gel('story-viewer').classList.remove('active');},5000);
| |
| }); | | }); |
| | $('#loc-add').on('click',function(){ |
| | var loc=$('#loc-input').val().trim(); |
| | if(loc){pending.loc=loc;$('#pending-location').addClass('show').html('📍 '+esc(loc)+'<button class="sf-del">✕</button>');closeModal('modal-location');} |
| | else alert('Enter location'); |
| }); | | }); |
| } | | $('#pending-location').on('click','.sf-del',function(){pending.loc='';$('#pending-location').removeClass('show').empty();}); |
|
| |
|
| gel('story-close-btn').addEventListener('click',function(){gel('story-viewer').classList.remove('active');});
| | // Buttons |
| gel('story-viewer').addEventListener('click',function(e){if(e.target===this)this.classList.remove('active');});
| | $('#btn-photo').on('click',function(){$('#photo-url').val('');$('#i-url .sf-preview').hide();photoUp.reset();openModal('modal-photo');}); |
| | $('#btn-video').on('click',function(){$('#video-url').val('');videoUp.reset();openModal('modal-video');}); |
| | $('#btn-location').on('click',function(){$('#loc-input').val('');openModal('modal-location');}); |
|
| |
|
| // Emoji picker | | // Emoji picker |
| function renderEmojis(cat){ | | var picker=$('#emoji-picker'),cats=Object.keys(emojis); |
| var grid=gel('emoji-grid');
| | picker.html('<div class="sf-emoji-cats">'+cats.map(function(c,i){return'<button class="sf-emoji-cat'+(i===0?' active':'')+'" data-c="'+c+'">'+c+'</button>';}).join('')+'</div><div class="sf-emoji-list"></div>'); |
| grid.innerHTML='';
| | function showEmojis(cat){picker.find('.sf-emoji-list').html(emojis[cat].map(function(e){return'<button>'+e+'</button>';}).join(''));} |
| (emojis[cat]||[]).forEach(function(em){ | | showEmojis(cats[0]); |
| var btn=document.createElement('button');
| | picker.on('click','.sf-emoji-cat',function(){picker.find('.sf-emoji-cat').removeClass('active');$(this).addClass('active');showEmojis($(this).data('c'));}); |
| btn.className='sf-emoji-btn';
| | picker.on('click','.sf-emoji-list button',function(){var ta=$('#post-text')[0],e=$(this).text(),s=ta.selectionStart,v=ta.value;ta.value=v.slice(0,s)+e+v.slice(ta.selectionEnd);ta.selectionStart=ta.selectionEnd=s+e.length;ta.focus();}); |
| btn.textContent=em;
| | $('#btn-emoji').on('click',function(e){e.stopPropagation();picker.toggleClass('open');}); |
| btn.addEventListener('click',function(){
| | $(document).on('click',function(e){if(!$(e.target).closest('#emoji-picker,#btn-emoji').length)picker.removeClass('open');}); |
| var ta=gel('post-content'); | |
| var start=ta.selectionStart;
| |
| var end=ta.selectionEnd;
| |
| ta.value=ta.value.substring(0,start)+em+ta.value.substring(end); | |
| ta.selectionStart=ta.selectionEnd=start+em.length; | |
| ta.focus(); | |
| }); | |
| grid.appendChild(btn);
| |
| });
| |
| }
| |
| | |
| document.querySelectorAll('.sf-emoji-tab').forEach(function(tab){
| |
| tab.addEventListener('click',function(){
| |
| document.querySelectorAll('.sf-emoji-tab').forEach(function(t){t.classList.remove('active');});
| |
| tab.classList.add('active');
| |
| renderEmojis(tab.dataset.cat);
| |
| }); | |
| });
| |
| | |
| gel('add-emoji-btn').addEventListener('click',function(e){
| |
| e.stopPropagation(); | |
| var picker=gel('emoji-picker');
| |
| picker.classList.toggle('active');
| |
| if(picker.classList.contains('active'))renderEmojis('smileys');
| |
| }); | |
|
| |
|
| document.addEventListener('click',function(e){
| | // Pending media |
| if(!(e.target.closest('.sf-emoji-picker')||e.target.closest('#add-emoji-btn'))){
| | function setPendingMedia(type,url){ |
| gel('emoji-picker').classList.remove('active');
| | pending.img=pending.video=''; |
| | pending[type==='img'?'img':'video']=url; |
| | var html=type==='img'?'<img src="'+url+'">':'<video src="'+url+'" style="max-height:80px"></video>'; |
| | $('#pending-media').addClass('show').html(html+'<button class="sf-del">✕</button>'); |
| } | | } |
| });
| | $('#pending-media').on('click','.sf-del',function(){pending.img=pending.video='';$('#pending-media').removeClass('show').empty();}); |
| | |
| // Video modal tabs
| |
| var uploadedVideoFile=null;
| |
| document.querySelectorAll('[data-vtab]').forEach(function(tab){
| |
| tab.addEventListener('click',function(){
| |
| document.querySelectorAll('[data-vtab]').forEach(function(t){t.classList.remove('active');});
| |
| document.querySelectorAll('#video-modal .sf-tab-content').forEach(function(c){c.classList.remove('active');});
| |
| tab.classList.add('active');
| |
| gel('tab-'+tab.dataset.vtab).classList.add('active');
| |
| });
| |
| }); | |
|
| |
|
| gel('add-video-btn').addEventListener('click',function(){
| | // Post |
| gel('video-url-input').value='';
| | $('#btn-post').on('click',function(){ |
| gel('video-upload-preview').style.display='none';
| | var txt=$('#post-text').val().trim(); |
| gel('video-upload-progress').style.display='none';
| | if(!txt&&!pending.img&&!pending.video){alert('Write something or add media');return;} |
| uploadedVideoFile=null;
| | var btn=$(this);btn.prop('disabled',true).text('Posting...'); |
| gel('video-modal').classList.add('active');
| | var params={action:'socialfeed',sfaction:'createpost',content:txt||'(media)'}; |
| | if(pending.img)params.image_url=pending.img; |
| | if(pending.video)params.video_url=pending.video; |
| | if(pending.loc)params.location=pending.loc; |
| | api.postWithToken('csrf',params).then(function(){ |
| | $('#post-text').val('');pending={img:'',video:'',loc:''}; |
| | $('#pending-media,#pending-location').removeClass('show').empty(); |
| | btn.prop('disabled',false).text('Post'); |
| | loadPosts(); |
| | }).catch(function(e){alert('Error: '+e);btn.prop('disabled',false).text('Post');}); |
| }); | | }); |
| gel('video-cancel-btn').addEventListener('click',function(){gel('video-modal').classList.remove('active');});
| |
|
| |
|
| var videoUploadZone=gel('video-upload-zone');
| | // Load posts |
| var videoFileInput=gel('video-file-input');
| | function loadPosts(){ |
| | | api.get({action:'socialfeed',sfaction:'getposts',limit:20}).then(function(r){ |
| videoUploadZone.addEventListener('click',function(){videoFileInput.click();});
| | var posts=(r.socialfeed&&r.socialfeed.posts)||[]; |
| videoUploadZone.addEventListener('dragover',function(e){e.preventDefault();videoUploadZone.classList.add('dragover');});
| | if(!posts.length){$('#feed').html('<div class="sf-card sf-empty"><div class="sf-empty-icon">📝</div><div>No posts yet</div></div>');return;} |
| videoUploadZone.addEventListener('dragleave',function(){videoUploadZone.classList.remove('dragover');});
| | var html=posts.map(function(p){ |
| videoUploadZone.addEventListener('drop',function(e){
| | var pic=localStorage.getItem('sfphoto_'+p.username)||''; |
| e.preventDefault();
| | var av=pic?'<img src="'+pic+'">':initials(p.username); |
| videoUploadZone.classList.remove('dragover');
| | var total=0;for(var k in p.reaction_counts)total+=p.reaction_counts[k]; |
| if(e.dataTransfer.files.length>0)handleVideoFile(e.dataTransfer.files[0]);
| | var media=''; |
| });
| | if(p.image_url)media='<div class="sf-post-media"><img src="'+p.image_url+'"></div>'; |
| videoFileInput.addEventListener('change',function(){
| | if(p.video_url){ |
| if(videoFileInput.files.length>0)handleVideoFile(videoFileInput.files[0]); | | if(p.video_url.match(/youtube|youtu\.be/)){ |
| });
| | var id=(p.video_url.match(/(?:v=|youtu\.be\/)([^&]+)/)||[])[1]; |
| | | if(id)media='<div class="sf-post-media"><iframe src="https://www.youtube.com/embed/'+id+'" frameborder="0" allowfullscreen style="height:315px"></iframe></div>'; |
| function handleVideoFile(file){
| | }else media='<div class="sf-post-media"><video src="'+p.video_url+'" controls></video></div>'; |
| if(!file.type.startsWith('video/')){alert('Please select a video file');return;}
| |
| uploadedVideoFile=file;
| |
| var url=URL.createObjectURL(file); | |
| gel('video-upload-preview').src=url;
| |
| gel('video-upload-preview').style.display='block';
| |
| }
| |
| | |
| gel('video-add-btn').addEventListener('click',function(){
| |
| var activeTab=document.querySelector('[data-vtab].active').dataset.vtab; | |
| if(activeTab==='vurl'){
| |
| var url=gel('video-url-input').value.trim(); | |
| if(url){ | |
| pendingVideo=url;
| |
| pendingImg='';
| |
| mediaType='video';
| |
| gel('preview-img').style.display='none';
| |
| gel('preview-video').style.display='block';
| |
| if(url.includes('youtube.com')||url.includes('youtu.be')){ | |
| var vid=url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&]+)/); | |
| if(vid)gel('preview-video').poster='https://img.youtube.com/vi/'+vid[1]+'/0.jpg'; | |
| gel('preview-video').src='';
| |
| }else{
| |
| gel('preview-video').src=url;
| |
| }
| |
| gel('image-preview').style.display='block';
| |
| gel('video-modal').classList.remove('active');
| |
| }else{
| |
| alert('Please enter a video URL');
| |
| }
| |
| }else{ | |
| if(uploadedVideoFile){
| |
| gel('video-upload-progress').style.display='block';
| |
| gel('video-progress-fill').style.width='10%';
| |
| gel('video-upload-status').textContent='Uploading...';
| |
| uploadFile(uploadedVideoFile,'SocialVideo',function(pct){
| |
| gel('video-progress-fill').style.width=pct+'%';
| |
| },function(url){
| |
| gel('video-progress-fill').style.width='100%';
| |
| gel('video-upload-status').textContent='Done!';
| |
| pendingVideo=url;
| |
| pendingImg='';
| |
| mediaType='video';
| |
| gel('preview-img').style.display='none';
| |
| gel('preview-video').src=url;
| |
| gel('preview-video').style.display='block';
| |
| gel('image-preview').style.display='block';
| |
| setTimeout(function(){gel('video-modal').classList.remove('active');},500);
| |
| },function(err){
| |
| gel('video-upload-status').textContent='Error: '+err;
| |
| });
| |
| }else{
| |
| alert('Please select a video to upload');
| |
| }
| |
| }
| |
| });
| |
| | |
| // Location modal | |
| gel('add-location-btn').addEventListener('click',function(){
| |
| gel('location-input').value='';
| |
| gel('location-modal').classList.add('active');
| |
| });
| |
| gel('location-cancel-btn').addEventListener('click',function(){gel('location-modal').classList.remove('active');});
| |
| gel('detect-location-btn').addEventListener('click',function(){
| |
| if(navigator.geolocation){
| |
| this.textContent='Detecting...';
| |
| var btn=this;
| |
| navigator.geolocation.getCurrentPosition(function(pos){
| |
| fetch('https://nominatim.openstreetmap.org/reverse?format=json&lat='+pos.coords.latitude+'&lon='+pos.coords.longitude).then(function(r){return r.json();}).then(function(d){
| |
| var loc=d.display_name||pos.coords.latitude+', '+pos.coords.longitude;
| |
| loc=loc.split(',').slice(0,3).join(',');
| |
| gel('location-input').value=loc;
| |
| btn.textContent='📍 Use Current Location';
| |
| }).catch(function(){
| |
| gel('location-input').value=pos.coords.latitude+', '+pos.coords.longitude;
| |
| btn.textContent='📍 Use Current Location';
| |
| });
| |
| },function(){
| |
| alert('Could not get location');
| |
| btn.textContent='📍 Use Current Location';
| |
| });
| |
| }else{
| |
| alert('Geolocation not supported');
| |
| } | | } |
| });
| | var loc=p.location?'<div class="sf-post-location">📍 '+esc(p.location)+'</div>':''; |
| gel('location-add-btn').addEventListener('click',function(){
| | var del=p.username===user?'<button class="sf-del" data-del="'+p.id+'" style="font-size:16px">🗑️</button>':''; |
| var loc=gel('location-input').value.trim();
| | return'<div class="sf-card"><div class="sf-post-header"><div class="sf-avatar sf-avatar-sm">'+av+'</div><div class="sf-post-info"><div class="sf-post-name">'+esc(p.username)+'</div><div class="sf-post-meta">'+timeAgo(p.created)+' · 🌐</div></div>'+del+'</div><div class="sf-post-content">'+esc(p.content)+'</div>'+loc+media+'<div class="sf-post-stats"><div>'+(total?'👍 '+total:'')+'</div><div>'+p.comments+' comments</div></div><div class="sf-post-actions"><button class="sf-post-action'+(p.user_reaction==='like'?' liked':'')+'" data-like="'+p.id+'">👍 Like</button><button class="sf-post-action" data-cmt="'+p.id+'">💬 Comment</button><button class="sf-post-action">↗️ Share</button></div><div class="sf-comments" id="cmt-'+p.id+'" style="display:none"></div></div>'; |
| if(loc){
| | }).join(''); |
| pendingLocation=loc;
| | $('#feed').html(html); |
| gel('location-text').textContent=loc;
| | }).catch(function(){$('#feed').html('<div class="sf-card sf-empty"><div class="sf-empty-icon">😕</div><div>Error loading posts</div></div>');}); |
| gel('location-preview').style.display='block';
| |
| gel('location-modal').classList.remove('active');
| |
| }else{ | |
| alert('Please enter a location');
| |
| } | | } |
| });
| |
| gel('remove-location-btn').addEventListener('click',function(){
| |
| pendingLocation='';
| |
| gel('location-preview').style.display='none';
| |
| });
| |
|
| |
|
| // Image modal tabs
| | $('#feed').on('click','[data-del]',function(){ |
| document.querySelectorAll('[data-tab]').forEach(function(tab){
| | if(confirm('Delete this post?'))api.postWithToken('csrf',{action:'socialfeed',sfaction:'deletepost',post_id:$(this).data('del')}).then(loadPosts); |
| tab.addEventListener('click',function(){
| |
| document.querySelectorAll('[data-tab]').forEach(function(t){t.classList.remove('active');});
| |
| document.querySelectorAll('#image-modal .sf-tab-content').forEach(function(c){c.classList.remove('active');});
| |
| tab.classList.add('active');
| |
| gel('tab-'+tab.dataset.tab).classList.add('active');
| |
| }); | |
| }); | | }); |
| | | $('#feed').on('click','[data-like]',function(){ |
| gel('add-image-btn').addEventListener('click',function(){
| | api.postWithToken('csrf',{action:'socialfeed',sfaction:'react',post_id:$(this).data('like'),reaction_type:'like'}).then(loadPosts); |
| gel('image-modal').classList.add('active');
| |
| gel('image-url-input').value='';
| |
| gel('url-preview').style.display='none';
| |
| gel('upload-preview').style.display='none';
| |
| gel('upload-progress').style.display='none';
| |
| uploadedFile=null;
| |
| }); | | }); |
| gel('image-cancel-btn').addEventListener('click',function(){
| | $('#feed').on('click','[data-cmt]',function(){ |
| gel('image-modal').classList.remove('active');
| | var id=$(this).data('cmt'),box=$('#cmt-'+id); |
| | if(box.is(':visible')){box.hide();}else{box.show();loadComments(id);} |
| }); | | }); |
|
| |
|
| var uploadZone=gel('upload-zone');
| | function loadComments(id){ |
| var fileInput=gel('file-input');
| | api.get({action:'socialfeed',sfaction:'getcomments',post_id:id}).then(function(r){ |
| | | var cmts=(r.socialfeed&&r.socialfeed.comments)||[]; |
| uploadZone.addEventListener('click',function(){fileInput.click();});
| | var myPic=photo?'<img src="'+photo+'">':initials(user); |
| uploadZone.addEventListener('dragover',function(e){e.preventDefault();uploadZone.classList.add('dragover');});
| | var html=cmts.map(function(c){ |
| uploadZone.addEventListener('dragleave',function(){uploadZone.classList.remove('dragover');});
| | var pic=localStorage.getItem('sfphoto_'+c.username)||''; |
| uploadZone.addEventListener('drop',function(e){
| | var av=pic?'<img src="'+pic+'">':initials(c.username); |
| e.preventDefault();
| | return'<div class="sf-comment"><div class="sf-avatar sf-avatar-sm">'+av+'</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>'; |
| uploadZone.classList.remove('dragover');
| | }).join(''); |
| if(e.dataTransfer.files.length>0)handleFile(e.dataTransfer.files[0]);
| | html+='<div class="sf-comment-form"><div class="sf-avatar sf-avatar-sm">'+myPic+'</div><input class="sf-comment-input" data-pid="'+id+'" placeholder="Write a comment..."></div>'; |
| }); | | $('#cmt-'+id).html(html); |
| fileInput.addEventListener('change',function(){
| |
| if(fileInput.files.length>0)handleFile(fileInput.files[0]);
| |
| }); | | }); |
|
| |
| function handleFile(file){
| |
| if(!file.type.startsWith('image/')){alert('Please select an image file');return;}
| |
| uploadedFile=file;
| |
| var reader=new FileReader();
| |
| reader.onload=function(e){
| |
| gel('upload-preview').src=e.target.result;
| |
| gel('upload-preview').style.display='block';
| |
| };
| |
| reader.readAsDataURL(file);
| |
| }
| |
|
| |
| gel('image-url-input').addEventListener('input',function(){
| |
| var url=this.value.trim();
| |
| if(url){
| |
| gel('url-preview').src=url;
| |
| gel('url-preview').style.display='block';
| |
| }else{
| |
| gel('url-preview').style.display='none';
| |
| } | | } |
| });
| |
|
| |
|
| gel('image-add-btn').addEventListener('click',function(){
| | $('#feed').on('keypress','.sf-comment-input',function(e){ |
| var activeTab=document.querySelector('[data-tab].active').dataset.tab;
| | if(e.which===13){ |
| if(activeTab==='url'){
| | var input=$(this),txt=input.val().trim(),pid=input.data('pid'); |
| var url=gel('image-url-input').value.trim(); | | if(txt){ |
| if(url){
| | input.val(''); |
| pendingImg=url;
| | api.postWithToken('csrf',{action:'socialfeed',sfaction:'comment',post_id:pid,content:txt}).then(function(){loadComments(pid);loadPosts();}); |
| pendingVideo='';
| |
| mediaType='image';
| |
| gel('preview-img').src=url;
| |
| gel('preview-img').style.display='block';
| |
| gel('preview-video').style.display='none';
| |
| gel('image-preview').style.display='block';
| |
| gel('image-modal').classList.remove('active');
| |
| }else{
| |
| alert('Please enter an image URL');
| |
| }
| |
| }else{
| |
| if(uploadedFile){ | |
| gel('upload-progress').style.display='block';
| |
| gel('progress-fill').style.width='10%';
| |
| gel('upload-status').textContent='Uploading...';
| |
| uploadFile(uploadedFile,'SocialFeed',function(pct){
| |
| gel('progress-fill').style.width=pct+'%';
| |
| },function(url){ | |
| gel('progress-fill').style.width='100%';
| |
| gel('upload-status').textContent='Done!';
| |
| pendingImg=url;
| |
| pendingVideo='';
| |
| mediaType='image';
| |
| gel('preview-img').src=url;
| |
| gel('preview-img').style.display='block';
| |
| gel('preview-video').style.display='none';
| |
| gel('image-preview').style.display='block';
| |
| setTimeout(function(){gel('image-modal').classList.remove('active');},500);
| |
| },function(err){
| |
| gel('upload-status').textContent='Error: '+err;
| |
| });
| |
| }else{ | |
| alert('Please select an image to upload');
| |
| } | | } |
| } | | } |
| }); | | }); |
|
| |
|
| gel('remove-image-btn').addEventListener('click',function(){
| | // Stories |
| pendingImg='';
| | function loadStories(){ |
| pendingVideo='';
| | api.get({action:'socialfeed',sfaction:'getstories'}).then(function(r){ |
| gel('image-preview').style.display='none';
| | var stories=(r.socialfeed&&r.socialfeed.stories)||[]; |
| });
| | var html='<div class="sf-story"><div class="sf-story-ring add"><div class="sf-story-inner" id="add-story">+</div></div><div class="sf-story-name">Add</div></div>'; |
| | | html+=stories.map(function(s){ |
| gel('post-btn').addEventListener('click',function(){
| | var pic=localStorage.getItem('sfphoto_'+s.username)||''; |
| var c=gel('post-content').value.trim();
| | var av=pic?'<img src="'+pic+'">':initials(s.username); |
| if(!(c||pendingImg||pendingVideo)){alert('Write something or add media');return;}
| | return'<div class="sf-story"><div class="sf-story-ring"><div class="sf-story-inner" data-simg="'+s.image_url+'">'+av+'</div></div><div class="sf-story-name">'+esc(s.username)+'</div></div>'; |
| var btn=this;btn.disabled=true;btn.textContent='Posting...';
| | }).join(''); |
| | | $('#stories').html(html); |
| getToken().then(function(token){
| | }).catch(function(){}); |
| var params={action:'socialfeed',sfaction:'createpost',content:c||'(media)',token:token};
| |
| if(pendingImg)params.image_url=pendingImg;
| |
| if(pendingVideo)params.video_url=pendingVideo;
| |
| if(pendingLocation)params.location=pendingLocation;
| |
| return apiPost(params);
| |
| }).then(function(d){ | |
| if(d.error){alert('Error: '+d.error.info);btn.disabled=false;btn.textContent='Post';return;}
| |
| gel('post-content').value='';
| |
| pendingImg='';pendingVideo='';pendingLocation='';
| |
| gel('image-preview').style.display='none';
| |
| gel('location-preview').style.display='none';
| |
| btn.disabled=false;btn.textContent='Post';
| |
| load();
| |
| }).catch(function(e){alert('Error: '+e);btn.disabled=false;btn.textContent='Post';});
| |
| });
| |
| | |
| function load(){
| |
| apiGet({action:'socialfeed',sfaction:'getposts',limit:20}).then(function(d){
| |
| if(d.socialfeed)render(d.socialfeed.posts||[]);
| |
| else render([]);
| |
| }).catch(function(err){
| |
| console.log('Load error:',err);
| |
| gel('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 render(posts){
| | $('#stories').on('click','#add-story',function(){ |
| var c=gel('timeline-container');
| | $('#story-url').val('');$('#s-url .sf-preview').hide();storyUp.reset();openModal('modal-story'); |
| if(!posts.length){c.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!</div></div>';return;}
| |
| var h='';
| |
| posts.forEach(function(p){
| |
| var t=ago(new Date(p.created));
| |
| var total=0;for(var k in p.reaction_counts)total+=p.reaction_counts[k];
| |
| var pic=localStorage.getItem('sf_photo_'+p.username)||'';
| |
| var av=pic?'<img src="'+pic+'">':init(p.username);
| |
| h+='<div class="sf-post"><div class="sf-post-header"><div class="sf-avatar sf-avatar-small">'+av+'</div><div class="sf-post-user-info"><div class="sf-post-username">'+esc(p.username)+'</div><div class="sf-post-meta">'+t+' · 🌐</div></div>';
| |
| if(p.username===user)h+='<button class="sf-post-menu" data-del="'+p.id+'">🗑️</button>';
| |
| h+='</div><div class="sf-post-content">'+esc(p.content)+'</div>';
| |
| if(p.location)h+='<div class="sf-post-location">📍 '+esc(p.location)+'</div>';
| |
| if(p.image_url)h+='<img class="sf-post-image" src="'+p.image_url+'">';
| |
| if(p.video_url){
| |
| if(p.video_url.includes('youtube.com')||p.video_url.includes('youtu.be')){
| |
| var vid=p.video_url.match(/(?:youtube\.com\/watch\?v=|youtu\.be\/)([^&]+)/);
| |
| if(vid)h+='<iframe class="sf-post-video" src="https://www.youtube.com/embed/'+vid[1]+'" frameborder="0" allowfullscreen style="width:100%;height:315px;"></iframe>';
| |
| }else{
| |
| h+='<video class="sf-post-video" src="'+p.video_url+'" controls></video>';
| |
| }
| |
| }
| |
| h+='<div class="sf-post-stats"><div class="sf-post-stats-left">';
| |
| if(total>0)h+='<span class="sf-reaction-icon">👍</span><span>'+total+'</span>';
| |
| h+='</div><span>'+p.comments+' comments</span></div>';
| |
| h+='<div class="sf-post-actions"><button class="sf-post-action'+(p.user_reaction==='like'?' liked':'')+'" data-like="'+p.id+'">👍 Like</button><button class="sf-post-action" data-cmt="'+p.id+'">💬 Comment</button><button class="sf-post-action">↗️ Share</button></div>';
| |
| h+='<div class="sf-comments" id="cmt-'+p.id+'" style="display:none"></div></div>';
| |
| }); | | }); |
| c.innerHTML=h;
| | $('#stories').on('click','[data-simg]',function(){ |
| c.querySelectorAll('[data-del]').forEach(function(b){b.addEventListener('click',function(){if(confirm('Delete?')){getToken().then(function(t){return apiPost({action:'socialfeed',sfaction:'deletepost',post_id:b.dataset.del,token:t});}).then(load);}});});
| | var viewer=$('#story-viewer'),img=$(this).data('simg'); |
| c.querySelectorAll('[data-like]').forEach(function(b){b.addEventListener('click',function(){getToken().then(function(t){return apiPost({action:'socialfeed',sfaction:'react',post_id:b.dataset.like,reaction_type:'like',token:t});}).then(load);});});
| | viewer.find('img').attr('src',img); |
| c.querySelectorAll('[data-cmt]').forEach(function(b){b.addEventListener('click',function(){var box=gel('cmt-'+b.dataset.cmt);if(box.style.display==='none'){box.style.display='block';loadCmt(b.dataset.cmt);}else{box.style.display='none';}});});
| | viewer.addClass('open'); |
| }
| | viewer.find('.sf-viewer-progress span').css('animation','none'); |
| | | setTimeout(function(){viewer.find('.sf-viewer-progress span').css('animation','progress 5s linear');},10); |
| function loadCmt(id){
| | setTimeout(function(){viewer.removeClass('open');},5000); |
| var box=gel('cmt-'+id);
| |
| apiGet({action:'socialfeed',sfaction:'getcomments',post_id:id}).then(function(d){
| |
| var cmts=(d.socialfeed?d.socialfeed.comments:[])||[];
| |
| var h='';
| |
| cmts.forEach(function(cm){var pic=localStorage.getItem('sf_photo_'+cm.username)||'';var av=pic?'<img src="'+pic+'">':init(cm.username);h+='<div class="sf-comment"><div class="sf-avatar sf-avatar-small">'+av+'</div><div class="sf-comment-bubble"><div class="sf-comment-author">'+esc(cm.username)+'</div><div class="sf-comment-text">'+esc(cm.content)+'</div></div></div>';});
| |
| var myPic=photo?'<img src="'+photo+'">':init(user);
| |
| h+='<div class="sf-add-comment"><div class="sf-avatar sf-avatar-small">'+myPic+'</div><input class="sf-comment-input" id="cinput-'+id+'" placeholder="Write a comment..."></div>';
| |
| box.innerHTML=h;
| |
| gel('cinput-'+id).addEventListener('keypress',function(e){if(e.key==='Enter'){var v=this.value.trim();if(v){this.value='';getToken().then(function(t){return apiPost({action:'socialfeed',sfaction:'comment',post_id:id,content:v,token:t});}).then(function(){loadCmt(id);load();});}}});
| |
| }); | | }); |
| } | | $('#story-viewer').on('click',function(e){if($(e.target).is('.sf-viewer,.sf-viewer-close'))$(this).removeClass('open');}); |
|
| |
|
| load();
| | // Init |
| | loadPosts(); |
| loadStories(); | | loadStories(); |
| }); | | }); |
| }); | | })(); |
| </script> | | </script> |
| </div> | | </div> |
| </html> | | </html> |