User:Docmoates/Social: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| Line 49: | Line 49: | ||
.sf-modal { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.6); z-index: 9999; align-items: center; justify-content: center; } | .sf-modal { display: none; position: fixed; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0,0,0,0.6); z-index: 9999; align-items: center; justify-content: center; } | ||
.sf-modal.active { display: flex; } | .sf-modal.active { display: flex; } | ||
.sf-modal-content { background: white; border-radius: 12px; padding: 24px; max-width: | .sf-modal-content { background: white; border-radius: 12px; padding: 24px; max-width: 450px; width: 90%; } | ||
.sf-modal-title { font-size: 20px; font-weight: 600; margin-bottom: 16px; } | .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-input { width: 100%; padding: 12px; border: 1px solid #ddd; border-radius: 8px; font-size: 14px; margin-bottom: 12px; } | ||
| Line 58: | Line 58: | ||
#image-preview { display: none; padding: 12px 20px; background: white; margin-bottom: 20px; border-radius: 12px; } | #image-preview { display: none; padding: 12px 20px; background: white; margin-bottom: 20px; border-radius: 12px; } | ||
#image-preview img { max-width: 100%; max-height: 200px; border-radius: 8px; } | #image-preview img { max-width: 100%; max-height: 200px; border-radius: 8px; } | ||
.sf-tabs { display: flex; border-bottom: 2px solid #e4e6eb; margin-bottom: 16px; } | |||
.sf-tab { flex: 1; padding: 12px; text-align: center; cursor: pointer; font-weight: 600; color: #65676b; border-bottom: 2px solid transparent; margin-bottom: -2px; } | |||
.sf-tab.active { color: #1877f2; border-bottom-color: #1877f2; } | |||
.sf-tab-content { display: none; } | |||
.sf-tab-content.active { display: block; } | |||
.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-upload-zone:hover { border-color: #1877f2; background: #f0f7ff; } | |||
.sf-upload-zone.dragover { border-color: #1877f2; background: #e3f2fd; } | |||
.sf-upload-icon { font-size: 48px; margin-bottom: 12px; } | |||
.sf-upload-text { color: #65676b; font-size: 14px; } | |||
.sf-upload-progress { display: none; margin-top: 12px; } | |||
.sf-progress-bar { height: 8px; background: #e4e6eb; border-radius: 4px; overflow: hidden; } | |||
.sf-progress-fill { height: 100%; background: #1877f2; width: 0%; transition: width 0.3s; } | |||
.sf-preview-thumb { max-width: 100%; max-height: 150px; border-radius: 8px; margin-top: 12px; } | |||
</style> | </style> | ||
| Line 90: | Line 104: | ||
<button class="sf-modal-btn sf-modal-btn-cancel" id="profile-cancel-btn">Cancel</button> | <button class="sf-modal-btn sf-modal-btn-cancel" id="profile-cancel-btn">Cancel</button> | ||
<button class="sf-modal-btn sf-modal-btn-save" id="profile-save-btn">Save</button> | <button class="sf-modal-btn sf-modal-btn-save" id="profile-save-btn">Save</button> | ||
</div> | |||
</div> | |||
</div> | |||
<div class="sf-modal" id="image-modal"> | |||
<div class="sf-modal-content"> | |||
<div class="sf-modal-title">Add Photo</div> | |||
<div class="sf-tabs"> | |||
<div class="sf-tab active" data-tab="upload">Upload</div> | |||
<div class="sf-tab" data-tab="url">From URL</div> | |||
</div> | |||
<div class="sf-tab-content active" id="tab-upload"> | |||
<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 class="sf-tab-content" id="tab-url"> | |||
<input type="text" class="sf-modal-input" id="image-url-input" placeholder="Paste image URL..."> | |||
<img class="sf-preview-thumb" id="url-preview" style="display:none"> | |||
</div> | |||
<div class="sf-modal-buttons"> | |||
<button class="sf-modal-btn sf-modal-btn-cancel" id="image-cancel-btn">Cancel</button> | |||
<button class="sf-modal-btn sf-modal-btn-save" id="image-add-btn">Add Image</button> | |||
</div> | </div> | ||
</div> | </div> | ||
| Line 100: | Line 144: | ||
var pendingImg=''; | var pendingImg=''; | ||
var api=new mw.Api(); | var api=new mw.Api(); | ||
var uploadedFile=null; | |||
function init(n){return n.split(/[\s_]+/).map(function(w){return w[0]||'';}).join('').substring(0,2).toUpperCase()||'?';} | function init(n){return n.split(/[\s_]+/).map(function(w){return w[0]||'';}).join('').substring(0,2).toUpperCase()||'?';} | ||
| Line 128: | Line 173: | ||
}); | }); | ||
// Image modal tabs | |||
document.querySelectorAll('.sf-tab').forEach(function(tab){ | |||
tab.addEventListener('click',function(){ | |||
document.querySelectorAll('.sf-tab').forEach(function(t){t.classList.remove('active');}); | |||
document.querySelectorAll('.sf-tab-content').forEach(function(c){c.classList.remove('active');}); | |||
tab.classList.add('active'); | |||
gel('tab-'+tab.dataset.tab).classList.add('active'); | |||
}); | |||
}); | |||
// Image modal | |||
gel('add-image-btn').addEventListener('click',function(){ | gel('add-image-btn').addEventListener('click',function(){ | ||
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(){ | |||
gel('image-modal').classList.remove('active'); | |||
}); | }); | ||
// File upload zone | |||
var uploadZone=gel('upload-zone'); | |||
var fileInput=gel('file-input'); | |||
uploadZone.addEventListener('click',function(){fileInput.click();}); | |||
uploadZone.addEventListener('dragover',function(e){e.preventDefault();uploadZone.classList.add('dragover');}); | |||
uploadZone.addEventListener('dragleave',function(){uploadZone.classList.remove('dragover');}); | |||
uploadZone.addEventListener('drop',function(e){ | |||
e.preventDefault(); | |||
uploadZone.classList.remove('dragover'); | |||
if(e.dataTransfer.files.length>0)handleFile(e.dataTransfer.files[0]); | |||
}); | |||
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); | |||
} | |||
// URL preview | |||
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'; | |||
} | |||
}); | |||
// Add image button | |||
gel('image-add-btn').addEventListener('click',function(){ | |||
var activeTab=document.querySelector('.sf-tab.active').dataset.tab; | |||
if(activeTab==='url'){ | |||
var url=gel('image-url-input').value.trim(); | |||
if(url){ | |||
pendingImg=url; | |||
gel('preview-img').src=url; | |||
gel('image-preview').style.display='block'; | |||
gel('image-modal').classList.remove('active'); | |||
}else{ | |||
alert('Please enter an image URL'); | |||
} | |||
}else{ | |||
if(uploadedFile){ | |||
uploadImage(uploadedFile); | |||
}else{ | |||
alert('Please select an image to upload'); | |||
} | |||
} | |||
}); | |||
function uploadImage(file){ | |||
gel('upload-progress').style.display='block'; | |||
gel('progress-fill').style.width='10%'; | |||
gel('upload-status').textContent='Preparing upload...'; | |||
var filename='SocialFeed_'+user+'_'+Date.now()+'.'+file.name.split('.').pop(); | |||
api.get({action:'query',meta:'tokens',type:'csrf'}).then(function(data){ | |||
gel('progress-fill').style.width='30%'; | |||
gel('upload-status').textContent='Uploading to wiki...'; | |||
var formData=new FormData(); | |||
formData.append('action','upload'); | |||
formData.append('filename',filename); | |||
formData.append('file',file); | |||
formData.append('token',data.query.tokens.csrftoken); | |||
formData.append('format','json'); | |||
formData.append('ignorewarnings','1'); | |||
var xhr=new XMLHttpRequest(); | |||
xhr.open('POST',mw.util.wikiScript('api'),true); | |||
xhr.upload.onprogress=function(e){ | |||
if(e.lengthComputable){ | |||
var pct=30+Math.round((e.loaded/e.total)*60); | |||
gel('progress-fill').style.width=pct+'%'; | |||
} | |||
}; | |||
xhr.onload=function(){ | |||
if(xhr.status===200){ | |||
var resp=JSON.parse(xhr.responseText); | |||
if(resp.upload){ | |||
if(resp.upload.imageinfo){ | |||
gel('progress-fill').style.width='100%'; | |||
gel('upload-status').textContent='Upload complete!'; | |||
pendingImg=resp.upload.imageinfo.url; | |||
gel('preview-img').src=pendingImg; | |||
gel('image-preview').style.display='block'; | |||
setTimeout(function(){gel('image-modal').classList.remove('active');},500); | |||
}else if(resp.upload.warnings){ | |||
gel('upload-status').textContent='Warning: '+JSON.stringify(resp.upload.warnings); | |||
} | |||
}else if(resp.error){ | |||
gel('upload-status').textContent='Error: '+resp.error.info; | |||
} | |||
}else{ | |||
gel('upload-status').textContent='Upload failed'; | |||
} | |||
}; | |||
xhr.onerror=function(){gel('upload-status').textContent='Upload failed';}; | |||
xhr.send(formData); | |||
}); | |||
} | |||
gel('remove-image-btn').addEventListener('click',function(){pendingImg='';gel('image-preview').style.display='none';}); | gel('remove-image-btn').addEventListener('click',function(){pendingImg='';gel('image-preview').style.display='none';}); | ||
Revision as of 02:49, 3 February 2026
Upload to wiki first, then paste URL
Uploading...