Spaces:
Running
Running
Download src/miniweb/app/static/miniweb-share.js from sparklabuofu/MiniWeb-demo: direct link, hf CLI and curl.
- Browser
- Download file 11.2 kB
-
https://huggingface.co/spaces/sparklabuofu/MiniWeb-demo/resolve/main/src/miniweb/app/static/miniweb-share.js
- Command line
-
hf download hf://spaces/sparklabuofu/MiniWeb-demo/src/miniweb/app/static/miniweb-share.js
-
curl -L -o miniweb-share.js https://huggingface.co/spaces/sparklabuofu/MiniWeb-demo/resolve/main/src/miniweb/app/static/miniweb-share.js
11.2 kB
| /* MiniWeb cross-site Share. | |
| * Opens a modal to share the current page to other MiniWeb sites — ForumHub, | |
| * PixShare (multimedia posting), and Messages — which actually create the | |
| * content there. The user picks a target, then edits the post before sending | |
| * (and, for Messages, chooses which chat to send it to). Plus a copyable link. | |
| * | |
| * Usage: | |
| * window.MiniWebShare.open({ title: '...', url: '...' }) | |
| * or add [data-miniweb-share] to any button (optionally data-share-title / | |
| * data-share-url) and it opens automatically on click. | |
| */ | |
| (function () { | |
| 'use strict'; | |
| var TARGETS = [ | |
| { key: 'forum', label: 'ForumHub', sub: 'Post to a community', endpoint: '/sites/forums/api/share', icon: '💬', color: '#ff4500' }, | |
| { key: 'pix', label: 'PixShare', sub: 'Share to your feed', endpoint: '/sites/multimedia-posting/api/share', icon: '📷', color: '#8e44ad' }, | |
| { key: 'msg', label: 'Messages', sub: 'Send to a chat', endpoint: '/sites/instant-messaging/api/share', icon: '✉️', color: '#0b93f6', recipients: '/sites/instant-messaging/api/share_targets' }, | |
| ]; | |
| var current = { title: '', url: '' }; | |
| var overlay = null; | |
| function css() { | |
| if (document.getElementById('_mws-css')) return; | |
| var s = document.createElement('style'); s.id = '_mws-css'; | |
| s.textContent = | |
| '._mws-ov{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:1000000;display:flex;align-items:center;justify-content:center;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif}' + | |
| '._mws-win{background:#fff;color:#111;border-radius:12px;width:min(430px,92vw);box-shadow:0 16px 48px rgba(0,0,0,.3);overflow:hidden}' + | |
| '._mws-hd{display:flex;align-items:center;gap:10px;padding:15px 18px;border-bottom:1px solid #eee}' + | |
| '._mws-hd b{font-size:15px;flex:1}' + | |
| '._mws-x{border:none;background:none;font-size:22px;line-height:1;color:#888;cursor:pointer;padding:0}' + | |
| '._mws-back{border:none;background:none;font-size:20px;line-height:1;color:#555;cursor:pointer;padding:0 2px}' + | |
| '._mws-body{padding:14px 18px 18px}' + | |
| '._mws-tgt{display:flex;align-items:center;gap:12px;width:100%;text-align:left;background:#fff;border:1px solid #e5e7eb;border-radius:10px;padding:11px 14px;margin-bottom:9px;cursor:pointer;font-family:inherit}' + | |
| '._mws-tgt:hover{background:#f8fafc;border-color:#cbd5e1}' + | |
| '._mws-ic{width:38px;height:38px;border-radius:9px;display:flex;align-items:center;justify-content:center;font-size:18px;color:#fff;flex-shrink:0}' + | |
| '._mws-tt{flex:1;min-width:0}' + | |
| '._mws-tl{display:block;font-weight:700;font-size:.92rem;color:#111}' + | |
| '._mws-ts{display:block;font-size:.78rem;color:#6b7280}' + | |
| '._mws-chev{color:#9ca3af;font-size:18px}' + | |
| '._mws-lbl{font-size:.72rem;font-weight:700;color:#6b7280;text-transform:uppercase;letter-spacing:.03rem;margin:4px 0 6px}' + | |
| '._mws-field{margin-bottom:11px}' + | |
| '._mws-field label{display:block;font-size:.74rem;font-weight:700;color:#6b7280;margin-bottom:4px}' + | |
| '._mws-in,._mws-ta,._mws-sel{width:100%;border:1px solid #d1d5db;border-radius:8px;padding:9px 11px;font-size:.9rem;font-family:inherit;color:#111;background:#fff;outline:none}' + | |
| '._mws-in:focus,._mws-ta:focus,._mws-sel:focus{border-color:#2563eb;box-shadow:0 0 0 3px rgba(37,99,235,.12)}' + | |
| '._mws-ta{resize:vertical;min-height:74px;line-height:1.45}' + | |
| '._mws-linkrow{display:flex;align-items:center;gap:7px;font-size:.78rem;color:#6b7280;background:#f3f4f6;border-radius:8px;padding:8px 11px;margin-bottom:12px;overflow:hidden}' + | |
| '._mws-linkrow span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}' + | |
| '._mws-go{width:100%;background:#111827;color:#fff;border:none;border-radius:9px;padding:11px;font-weight:700;font-size:.92rem;cursor:pointer;font-family:inherit}' + | |
| '._mws-go:hover{background:#000}' + | |
| '._mws-go:disabled{opacity:.6;cursor:default}' + | |
| '._mws-st{font-size:.82rem;font-weight:700;text-align:center;margin-top:11px;color:#16a34a}' + | |
| '._mws-st a{color:#2563eb}' + | |
| '._mws-link{display:flex;gap:8px;align-items:center;background:#f3f4f6;border:1px solid #e5e7eb;border-radius:8px;padding:5px 5px 5px 12px;margin-top:6px}' + | |
| '._mws-link input{flex:1;border:none;background:none;font-size:.82rem;color:#374151;outline:none;min-width:0}' + | |
| '._mws-copy{background:#111827;color:#fff;border:none;border-radius:6px;padding:7px 15px;font-weight:700;font-size:.8rem;cursor:pointer;white-space:nowrap}'; | |
| document.head.appendChild(s); | |
| } | |
| function close() { if (overlay) { overlay.remove(); overlay = null; } } | |
| function el(tag, cls, html) { | |
| var e = document.createElement(tag); | |
| if (cls) e.className = cls; | |
| if (html != null) e.innerHTML = html; | |
| return e; | |
| } | |
| function shortUrl(u) { | |
| try { var a = document.createElement('a'); a.href = u; return a.host + a.pathname; } | |
| catch (e) { return u; } | |
| } | |
| // ---- Screen 1: pick a target ------------------------------------------ | |
| function renderPicker(hd, body) { | |
| hd.innerHTML = ''; | |
| hd.appendChild(el('b', null, 'Share to MiniWeb')); | |
| var x = el('button', '_mws-x', '×'); x.onclick = close; hd.appendChild(x); | |
| body.innerHTML = ''; | |
| body.appendChild(el('div', '_mws-lbl', 'Share to a site')); | |
| TARGETS.forEach(function (t) { | |
| var b = el('button', '_mws-tgt'); | |
| b.type = 'button'; | |
| b.innerHTML = '<span class="_mws-ic" style="background:' + t.color + '">' + t.icon + '</span>' + | |
| '<span class="_mws-tt"><span class="_mws-tl">' + t.label + '</span><span class="_mws-ts">' + t.sub + '</span></span>' + | |
| '<span class="_mws-chev">›</span>'; | |
| b.addEventListener('click', function () { renderCompose(hd, body, t); }); | |
| body.appendChild(b); | |
| }); | |
| body.appendChild(el('div', '_mws-lbl', 'Or copy link')).style.marginTop = '12px'; | |
| var link = el('div', '_mws-link'); | |
| var input = el('input'); input.readOnly = true; input.value = current.url; | |
| input.addEventListener('click', function () { this.select(); }); | |
| var copy = el('button', '_mws-copy', 'Copy'); | |
| copy.addEventListener('click', function () { | |
| navigator.clipboard.writeText(current.url).then(function () { | |
| copy.textContent = 'Copied!'; setTimeout(function () { copy.textContent = 'Copy'; }, 1500); | |
| }).catch(function () { input.select(); }); | |
| }); | |
| link.appendChild(input); link.appendChild(copy); body.appendChild(link); | |
| } | |
| // ---- Screen 2: edit + send -------------------------------------------- | |
| function renderCompose(hd, body, t) { | |
| hd.innerHTML = ''; | |
| var back = el('button', '_mws-back', '←'); | |
| back.title = 'Back'; | |
| back.onclick = function () { renderPicker(hd, body); }; | |
| hd.appendChild(back); | |
| hd.appendChild(el('b', null, 'Share to ' + t.label)); | |
| var x = el('button', '_mws-x', '×'); x.onclick = close; hd.appendChild(x); | |
| body.innerHTML = ''; | |
| var fields = {}; // key -> input element | |
| function addField(key, label, kind, value) { | |
| var wrap = el('div', '_mws-field'); | |
| wrap.appendChild(el('label', null, label)); | |
| var inp; | |
| if (kind === 'textarea') { inp = el('textarea', '_mws-ta'); inp.value = value || ''; } | |
| else if (kind === 'select') { inp = el('select', '_mws-sel'); } | |
| else { inp = el('input', '_mws-in'); inp.type = 'text'; inp.value = value || ''; } | |
| wrap.appendChild(inp); body.appendChild(wrap); | |
| fields[key] = inp; | |
| return inp; | |
| } | |
| if (t.key === 'forum') { | |
| addField('title', 'Title', 'text', current.title); | |
| addField('text', 'Add text (optional)', 'textarea', ''); | |
| } else if (t.key === 'pix') { | |
| addField('title', 'Caption', 'textarea', current.title); | |
| } else if (t.key === 'msg') { | |
| var sel = addField('conversation_id', 'To', 'select'); | |
| sel.innerHTML = '<option>Loading chats…</option>'; sel.disabled = true; | |
| addField('text', 'Message', 'textarea', current.title + '\n' + current.url); | |
| fetch(t.recipients).then(function (r) { return r.json(); }).then(function (d) { | |
| sel.innerHTML = ''; | |
| var list = (d && d.targets) || []; | |
| if (!list.length) { sel.innerHTML = '<option value="">No chats available</option>'; return; } | |
| list.forEach(function (c) { | |
| var o = document.createElement('option'); o.value = c.id; o.textContent = c.name; sel.appendChild(o); | |
| }); | |
| sel.disabled = false; | |
| }).catch(function () { sel.innerHTML = '<option value="">Could not load chats</option>'; }); | |
| } | |
| // Link line (read-only context) | |
| var lr = el('div', '_mws-linkrow', '🔗 <span>' + shortUrl(current.url) + '</span>'); | |
| body.appendChild(lr); | |
| var status = el('div', '_mws-st'); status.style.display = 'none'; | |
| var go = el('button', '_mws-go', 'Share to ' + t.label); | |
| go.addEventListener('click', function () { | |
| var payload = { title: current.title, url: current.url, text: '' }; | |
| Object.keys(fields).forEach(function (k) { payload[k] = fields[k].value; }); | |
| go.disabled = true; status.style.display = 'block'; status.style.color = '#6b7280'; status.textContent = 'Sharing…'; | |
| fetch(t.endpoint, { | |
| method: 'POST', headers: { 'Content-Type': 'application/json' }, | |
| body: JSON.stringify(payload) | |
| }).then(function (r) { return r.json(); }).then(function (d) { | |
| if (d && d.ok) { | |
| status.style.color = '#16a34a'; | |
| status.innerHTML = '✓ Shared to ' + t.label + ' · <a href="' + d.view_url + '">View</a>'; | |
| go.textContent = 'Shared'; | |
| } else { | |
| status.style.color = '#dc2626'; | |
| status.textContent = (d && d.error) ? d.error : 'Failed to share'; | |
| go.disabled = false; | |
| } | |
| }).catch(function () { | |
| status.style.color = '#dc2626'; status.textContent = 'Failed to share'; go.disabled = false; | |
| }); | |
| }); | |
| body.appendChild(go); | |
| body.appendChild(status); | |
| // Focus the first editable field. | |
| var first = fields.title || fields.text; | |
| if (first) { first.focus(); if (first.select) first.select(); } | |
| } | |
| function open(opts) { | |
| opts = opts || {}; | |
| current.title = opts.title || document.title || 'Shared link'; | |
| current.url = opts.url || window.location.href; | |
| css(); close(); | |
| overlay = el('div', '_mws-ov'); | |
| overlay.addEventListener('click', function (e) { if (e.target === overlay) close(); }); | |
| var win = el('div', '_mws-win'); | |
| var hd = el('div', '_mws-hd'); | |
| var body = el('div', '_mws-body'); | |
| win.appendChild(hd); win.appendChild(body); overlay.appendChild(win); | |
| document.body.appendChild(overlay); | |
| renderPicker(hd, body); | |
| } | |
| document.addEventListener('keydown', function (e) { if (e.key === 'Escape') close(); }); | |
| // Auto-bind declarative triggers. | |
| document.addEventListener('click', function (e) { | |
| var t = e.target.closest('[data-miniweb-share]'); | |
| if (!t) return; | |
| e.preventDefault(); | |
| open({ title: t.getAttribute('data-share-title') || undefined, | |
| url: t.getAttribute('data-share-url') || undefined }); | |
| }); | |
| window.MiniWebShare = { open: open }; | |
| })(); | |