chat widget cleanup

This commit is contained in:
2025-10-09 22:06:29 -04:00
parent 7a165d2cf4
commit 36f1a0d86d
5 changed files with 1762 additions and 181 deletions

View File

@@ -77,11 +77,11 @@
</div> </div>
<script src="http://localhost:9000/nostr-chat-widget.js" <script src="https://btcforplebs.com/nostr-chat-widget-mini.js"
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b" data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
data-brand-name="Chat with BTCforPlebs" data-brand-name="Chat with BTCforPlebs"
data-color="#8e30eb" data-color="#fdad01"
data-color-secondary="#fdad01"> data-color-secondary="#222222">
</script> </script>
<script> <script>

View File

@@ -1,15 +1,13 @@
/** /**
* Nostr Chat Widget - Embeddable Version * Nostr Chat Widget - Embeddable Version (Glassmorphism Design)
* *
* HOST THIS FILE on your server (e.g., https://btcforplebs.com/chat-widget.js) * EMBED IT WITH:
* * <script src="https://btcforplebs.com/nostr-chat-widget.js"
* USERS EMBED IT WITH: * data-nostr-pubkey="YOUR_PUBKEY_HEX_FORMAT"
* <script src="https://btcforplebs.com/nostr-chat-widget.js" * data-brand-name="My Company"
data-nostr-pubkey="YOUR_PUBKEY" * data-color="#8e30eb"
data-brand-name="My Company" * data-color-secondary="#ff8c00">
data-color="#8e30eb"> * </script>
data-color-secondary="#ff8c00">
</script>
*/ */
(function() { (function() {
@@ -18,35 +16,79 @@
// Get configuration from script tag // Get configuration from script tag
const scriptTag = document.currentScript; const scriptTag = document.currentScript;
const csPubkey = scriptTag.getAttribute('data-nostr-pubkey') || 'PUBKEY_TO_RECEICE_MESSAGES'; const csPubkey = scriptTag.getAttribute('data-nostr-pubkey') || 'PUBKEY_TO_RECEICE_MESSAGES';
const brandName = scriptTag.getAttribute('data-brand-name') || 'Support Team'; const brandName = scriptTag.getAttribute('data-brand-name') || 'Support Team Messaging';
const primaryColor = scriptTag.getAttribute('data-color-primary') || '#fdad01'; const primaryColor = scriptTag.getAttribute('data-color') || '#fdad01';
const secondaryColor = scriptTag.getAttribute('data-color-secondary') || '#ff8c00'; const secondaryColor = scriptTag.getAttribute('data-color-secondary') || '#000000';
// Default relay configuration // Default relay configuration
const DEFAULT_RELAYS = [ const DEFAULT_RELAYS = [
'wss://relay.damus.io', 'wss://relay.damus.io',
'wss://relay.primal.net', 'wss://relay.primal.net',
'wss://nos.lol', 'wss://nos.lol',
'wss://relay.btcforplebs.com', 'wss://relay.btcforplebs.com'
'wss://relay.logemedia.com'
]; ];
// Inject Tailwind CSS // Add viewport meta tag for mobile optimization
const tailwindLink = document.createElement('link'); let viewportMeta = document.querySelector('meta[name="viewport"]');
tailwindLink.href = 'https://cdn.tailwindcss.com'; if (!viewportMeta) {
tailwindLink.rel = 'stylesheet'; viewportMeta = document.createElement('meta');
document.head.appendChild(tailwindLink); viewportMeta.name = 'viewport';
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';
document.head.appendChild(viewportMeta);
}
// Inject custom styles // Inject Tailwind CSS
const tailwindScript = document.createElement('script');
tailwindScript.src = 'https://cdn.tailwindcss.com';
document.head.appendChild(tailwindScript);
// Inject custom styles with glassmorphism
const style = document.createElement('style'); const style = document.createElement('style');
style.textContent = ` style.textContent = `
.safe-area-bottom { .safe-area-bottom {
padding-bottom: max(1rem, env(safe-area-inset-bottom)) !important; padding-bottom: env(safe-area-inset-bottom);
} }
#nostr-chat-widget-root > div { #nostr-chat-widget-root > div {
pointer-events: auto !important; pointer-events: auto !important;
z-index: 99999 !important; z-index: 99999 !important;
} }
.glass-morphism {
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.15);
}
.glass-morphism-light {
background: rgba(255, 255, 255, 0.03);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
}
.glass-input {
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.glass-input:focus {
background: rgba(255, 255, 255, 0.25);
border: 1px solid rgba(255, 255, 255, 0.4);
}
.glass-input::placeholder {
color: rgba(255, 255, 255, 0.6);
}
@media (max-width: 640px) {
#nostr-chat-widget-root .chat-window-mobile {
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
bottom: 0 !important;
width: 100% !important;
height: 100% !important;
max-height: 100vh !important;
border-radius: 0 !important;
}
}
`; `;
document.head.appendChild(style); document.head.appendChild(style);
@@ -83,7 +125,8 @@
relays: ${JSON.stringify(DEFAULT_RELAYS)}, relays: ${JSON.stringify(DEFAULT_RELAYS)},
csPubkey: '${csPubkey}', csPubkey: '${csPubkey}',
brandName: '${brandName}', brandName: '${brandName}',
primaryColor: '${primaryColor}' primaryColor: '${primaryColor}',
secondaryColor: '${secondaryColor}'
}; };
let state = { let state = {
@@ -243,6 +286,18 @@
if (!state.inputMessage.trim()) return; if (!state.inputMessage.trim()) return;
const messageText = state.inputMessage; const messageText = state.inputMessage;
state.inputMessage = '';
// Show message immediately (optimistic UI)
const tempMessage = {
id: 'temp_' + Date.now(),
text: messageText,
sender: 'user',
timestamp: new Date().toISOString()
};
state.messages.push(tempMessage);
render();
scrollToBottom();
try { try {
console.log('🔐 Encrypting and sending...'); console.log('🔐 Encrypting and sending...');
@@ -282,16 +337,12 @@
console.log(\`✓ Published to \${published}/\${state.relays.length} relays\`); console.log(\`✓ Published to \${published}/\${state.relays.length} relays\`);
const message = { // Update temp message with real ID
id: event.id, const msgIndex = state.messages.findIndex(m => m.id === tempMessage.id);
text: messageText, if (msgIndex !== -1) {
sender: 'user', state.messages[msgIndex].id = event.id;
timestamp: new Date().toISOString() }
}; saveMessages();
addMessage('user', messageText, message);
state.inputMessage = '';
render();
} catch (error) { } catch (error) {
console.error('Error sending:', error); console.error('Error sending:', error);
@@ -346,7 +397,8 @@
container.innerHTML = \` container.innerHTML = \`
<div class="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-[99999]"> <div class="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-[99999]">
<button onclick="window.NostrChat.open()" <button onclick="window.NostrChat.open()"
class="bg-gradient-to-br from-[\${CONFIG.primaryColor}] to-[#ff8c00] hover:from-[#ff8c00] hover:to-[\${CONFIG.primaryColor}] text-white rounded-full p-4 sm:p-5 shadow-2xl transition-all transform hover:scale-110 active:scale-95" style="background: linear-gradient(to bottom right, \${CONFIG.primaryColor}, \${CONFIG.secondaryColor});"
class="hover:opacity-90 text-white rounded-full p-4 sm:p-5 shadow-2xl transition-all transform hover:scale-110 active:scale-95"
aria-label="Open chat" aria-label="Open chat"
> >
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="sm:w-7 sm:h-7"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="sm:w-7 sm:h-7">
@@ -359,15 +411,15 @@
} }
container.innerHTML = \` container.innerHTML = \`
<div class="fixed inset-4 sm:inset-auto sm:bottom-6 sm:right-6 z-[99999]"> <div class="fixed inset-0 sm:inset-auto sm:bottom-6 sm:right-6 z-[99999]">
<div class="bg-white rounded-2xl shadow-2xl w-full h-full sm:w-96 sm:h-[600px] max-w-full flex flex-col overflow-hidden"> <div class="glass-morphism chat-window-mobile rounded-none sm:rounded-2xl shadow-2xl w-full h-full sm:w-96 sm:h-[600px] max-w-full flex flex-col overflow-hidden">
<div class="bg-gradient-to-br from-[\${CONFIG.primaryColor}] to-[#ff8c00] text-white p-4 sm:p-5"> <div style="background: linear-gradient(to bottom right, \${CONFIG.primaryColor}, \${CONFIG.secondaryColor});" class="text-white p-3.5 sm:p-4">
<div class="flex justify-between items-center"> <div class="flex justify-between items-center">
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<h3 class="font-bold text-base sm:text-lg">\${CONFIG.brandName}</h3> <h3 class="font-bold text-base sm:text-lg">\${CONFIG.brandName}</h3>
<div class="flex items-center gap-2 mt-1"> <div class="flex items-center gap-2 mt-0.5">
<div class="w-2 h-2 rounded-full flex-shrink-0 \${state.connected ? 'bg-green-400 animate-pulse' : 'bg-red-400'}"></div> <div class="w-2 h-2 rounded-full flex-shrink-0 \${state.connected ? 'bg-green-400 animate-pulse' : 'bg-red-400'}"></div>
<span class="text-xs text-orange-100 truncate"> <span class="text-xs text-white/80 truncate">
\${state.connected ? \`P2P E2EE • \${state.relays.length} relays\` : 'Connecting...'} \${state.connected ? \`P2P E2EE • \${state.relays.length} relays\` : 'Connecting...'}
</span> </span>
</div> </div>
@@ -385,9 +437,9 @@
</div> </div>
</div> </div>
<div id="nostr-messages" class="flex-1 overflow-y-auto p-3 sm:p-4 space-y-3 bg-gradient-to-b from-gray-50 to-white"> <div id="nostr-messages" class="flex-1 overflow-y-auto p-3 sm:p-3.5 space-y-3 glass-morphism-light">
\${state.messages.length === 0 ? \` \${state.messages.length === 0 ? \`
<div class="text-center text-gray-400 mt-8"> <div class="text-center text-white/60 mt-8">
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" class="mx-auto mb-3 opacity-50"> <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1" class="mx-auto mb-3 opacity-50">
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path> <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
</svg> </svg>
@@ -397,7 +449,7 @@
if (msg.sender === 'system') { if (msg.sender === 'system') {
return \` return \`
<div class="flex justify-center"> <div class="flex justify-center">
<div class="bg-orange-50 text-orange-700 text-xs px-3 py-2 rounded-full border border-orange-200"> <div class="bg-orange-100/40 backdrop-blur-sm text-orange-800 text-xs px-3 py-2 rounded-full border border-orange-300/50">
\${escapeHtml(msg.text)} \${escapeHtml(msg.text)}
</div> </div>
</div> </div>
@@ -406,10 +458,10 @@
return \` return \`
<div class="flex justify-end"> <div class="flex justify-end">
<div class="max-w-[85%] sm:max-w-xs"> <div class="max-w-[85%] sm:max-w-xs">
<div class="bg-gradient-to-br from-[\${CONFIG.primaryColor}] to-[#ff8c00] text-white rounded-2xl rounded-tr-sm px-3 py-2 sm:px-4 sm:py-3 shadow-md text-sm sm:text-base"> <div style="background: linear-gradient(to bottom right, \${CONFIG.primaryColor}, \${CONFIG.secondaryColor});" class="text-white rounded-2xl rounded-tr-sm px-3 py-2 sm:px-4 sm:py-3 shadow-md text-sm sm:text-base">
\${escapeHtml(msg.text)} \${escapeHtml(msg.text)}
</div> </div>
<div class="text-xs text-gray-400 mt-1 text-right">\${formatTime(msg.timestamp)}</div> <div class="text-xs text-white/60 mt-1 text-right">Sent \${formatTime(msg.timestamp)}</div>
</div> </div>
</div> </div>
\`; \`;
@@ -417,11 +469,10 @@
return \` return \`
<div class="flex justify-start"> <div class="flex justify-start">
<div class="max-w-[85%] sm:max-w-xs"> <div class="max-w-[85%] sm:max-w-xs">
<div class="bg-white border border-gray-200 text-gray-800 rounded-2xl rounded-tl-sm px-3 py-2 sm:px-4 sm:py-3 shadow-md text-sm sm:text-base"> <div style="background: linear-gradient(to bottom right, #9ca3af, #6b7280);" class="text-white rounded-2xl rounded-tl-sm px-3 py-2 sm:px-4 sm:py-3 shadow-md text-sm sm:text-base">
<div class="text-xs font-semibold" style="color: \${CONFIG.primaryColor}">\${CONFIG.brandName}</div>
\${escapeHtml(msg.text)} \${escapeHtml(msg.text)}
</div> </div>
<div class="text-xs text-gray-400 mt-1">\${formatTime(msg.timestamp)}</div> <div class="text-xs text-white/60 mt-1">\${formatTime(msg.timestamp)}</div>
</div> </div>
</div> </div>
\`; \`;
@@ -430,21 +481,21 @@
}).join('')} }).join('')}
</div> </div>
<div class="border-t bg-white p-3 sm:p-4 pb-safe"> <div class="p-3 sm:p-3.5 mb-2 flex-shrink-0 safe-area-bottom">
<div class="flex gap-2"> <div class="glass-input rounded-xl p-2 flex gap-2 items-center">
<input <input
id="nostr-message-input" id="nostr-message-input"
type="text" type="text"
value="\${escapeHtml(state.inputMessage)}" value="\${escapeHtml(state.inputMessage)}"
placeholder="Type your message..." placeholder="Type your message..."
class="flex-1 px-3 py-2 sm:px-4 sm:py-3 border border-gray-300 rounded-xl focus:outline-none focus:ring-2 text-sm sm:text-base" class="flex-1 bg-transparent px-2 py-1.5 focus:outline-none text-sm sm:text-base text-white placeholder-white/60"
style="focus:ring-color: \${CONFIG.primaryColor}"
\${!state.connected ? 'disabled' : ''} \${!state.connected ? 'disabled' : ''}
> >
<button <button
onclick="window.NostrChat.send()" onclick="window.NostrChat.send()"
\${!state.connected || !state.inputMessage.trim() ? 'disabled' : ''} \${!state.connected || !state.inputMessage.trim() ? 'disabled' : ''}
class="bg-gradient-to-br from-[\${CONFIG.primaryColor}] to-[#ff8c00] hover:from-[#ff8c00] hover:to-[\${CONFIG.primaryColor}] disabled:from-gray-400 disabled:to-gray-400 text-white px-4 py-2 sm:px-5 sm:py-3 rounded-xl transition-all disabled:cursor-not-allowed active:scale-95 flex-shrink-0" style="background: linear-gradient(to bottom right, \${CONFIG.primaryColor}, \${CONFIG.secondaryColor});"
class="hover:opacity-90 disabled:opacity-40 text-white p-2 rounded-lg transition-all disabled:cursor-not-allowed active:scale-95 flex-shrink-0"
aria-label="Send message" aria-label="Send message"
> >
<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
@@ -508,7 +559,6 @@
document.body.appendChild(widgetScript); document.body.appendChild(widgetScript);
})(); })();
/*! /*!
* fill-range <https://github.com/jonschlinkert/fill-range> * fill-range <https://github.com/jonschlinkert/fill-range>
* *
@@ -594,4 +644,4 @@ Check your Browserslist config to be sure that your targets are set up correctly
https://github.com/postcss/autoprefixer#readme https://github.com/postcss/autoprefixer#readme
https://github.com/browserslist/browserslist#readme https://github.com/browserslist/browserslist#readme
`))}gv.exports=Dr;function Dr(...r){let e;if(r.length===1&&V5(r[0])?(e=r[0],r=void 0):r.length===0||r.length===1&&!r[0]?r=void 0:r.length<=2&&(Array.isArray(r[0])||!r[0])?(e=r[1],r=r[0]):typeof r[r.length-1]=="object"&&(e=r.pop()),e||(e={}),e.browser)throw new Error("Change `browser` option to `overrideBrowserslist` in Autoprefixer");if(e.browserslist)throw new Error("Change `browserslist` option to `overrideBrowserslist` in Autoprefixer");e.overrideBrowserslist?r=e.overrideBrowserslist:e.browsers&&(typeof console!="undefined"&&console.warn&&(of.red?console.warn(of.red(mv.replace(/`[^`]+`/g,n=>of.yellow(n.slice(1,-1))))):console.warn(mv)),r=e.browsers);let t={ignoreUnknownVersions:e.ignoreUnknownVersions,stats:e.stats,env:e.env};function i(n){let s=hv,a=new F5(s.browsers,r,n,t),o=a.selected.join(", ")+JSON.stringify(e);return lf.has(o)||lf.set(o,new j5(s.prefixes,a,e)),lf.get(o)}return{postcssPlugin:"autoprefixer",prepare(n){let s=i({from:n.opts.from,env:e.env});return{OnceExit(a){H5(n,s),e.remove!==!1&&s.processor.remove(a,n),e.add!==!1&&s.processor.add(a,n)}}},info(n){return n=n||{},n.from=n.from||m.cwd(),U5(i(n))},options:e,browsers:r}}Dr.postcss=!0;Dr.data=hv;Dr.defaults=N5.defaults;Dr.info=()=>Dr().info()});var bv={};Ge(bv,{default:()=>W5});var W5,wv=P(()=>{u();W5=[]});var xv={};Ge(xv,{default:()=>G5});var vv,G5,kv=P(()=>{u();Xi();vv=pe(rn()),G5=St(vv.default.theme)});var Av={};Ge(Av,{default:()=>Q5});var Sv,Q5,Cv=P(()=>{u();Xi();Sv=pe(rn()),Q5=St(Sv.default)});u();"use strict";var Y5=vt(_y()),K5=vt($e()),X5=vt(yv()),Z5=vt((wv(),bv)),J5=vt((kv(),xv)),eP=vt((Cv(),Av)),tP=vt((Vs(),_f)),rP=vt((al(),sl)),iP=vt((sa(),sc));function vt(r){return r&&r.__esModule?r:{default:r}}console.warn("cdn.tailwindcss.com should not be used in production. To use Tailwind CSS in production, install it as a PostCSS plugin or use the Tailwind CLI: https://tailwindcss.com/docs/installation");var Ns="tailwind",uf="text/tailwindcss",_v="/template.html",Yt,Ev=!0,Ov=0,ff=new Set,cf,Tv="",Rv=(r=!1)=>({get(e,t){return(!r||t==="config")&&typeof e[t]=="object"&&e[t]!==null?new Proxy(e[t],Rv()):e[t]},set(e,t,i){return e[t]=i,(!r||t==="config")&&pf(!0),!0}});window[Ns]=new Proxy({config:{},defaultTheme:J5.default,defaultConfig:eP.default,colors:tP.default,plugin:rP.default,resolveConfig:iP.default},Rv(!0));function Pv(r){cf.observe(r,{attributes:!0,attributeFilter:["type"],characterData:!0,subtree:!0,childList:!0})}new MutationObserver(async r=>{let e=!1;if(!cf){cf=new MutationObserver(async()=>await pf(!0));for(let t of document.querySelectorAll(`style[type="${uf}"]`))Pv(t)}for(let t of r)for(let i of t.addedNodes)i.nodeType===1&&i.tagName==="STYLE"&&i.getAttribute("type")===uf&&(Pv(i),e=!0);await pf(e)}).observe(document.documentElement,{attributes:!0,attributeFilter:["class"],childList:!0,subtree:!0});async function pf(r=!1){r&&(Ov++,ff.clear());let e="";for(let i of document.querySelectorAll(`style[type="${uf}"]`))e+=i.textContent;let t=new Set;for(let i of document.querySelectorAll("[class]"))for(let n of i.classList)ff.has(n)||t.add(n);if(document.body&&(Ev||t.size>0||e!==Tv||!Yt||!Yt.isConnected)){for(let n of t)ff.add(n);Ev=!1,Tv=e,self[_v]=Array.from(t).join(" ");let{css:i}=await(0,K5.default)([(0,Y5.default)({...window[Ns].config,_hash:Ov,content:{files:[_v],extract:{html:n=>n.split(" ")}},plugins:[...Z5.default,...Array.isArray(window[Ns].config.plugins)?window[Ns].config.plugins:[]]}),(0,X5.default)({remove:!1})]).process(`@tailwind base;@tailwind components;@tailwind utilities;${e}`);(!Yt||!Yt.isConnected)&&(Yt=document.createElement("style"),document.head.append(Yt)),Yt.textContent=i}}})(); `))}gv.exports=Dr;function Dr(...r){let e;if(r.length===1&&V5(r[0])?(e=r[0],r=void 0):r.length===0||r.length===1&&!r[0]?r=void 0:r.length<=2&&(Array.isArray(r[0])||!r[0])?(e=r[1],r=r[0]):typeof r[r.length-1]=="object"&&(e=r.pop()),e||(e={}),e.browser)throw new Error("Change `browser` option to `overrideBrowserslist` in Autoprefixer");if(e.browserslist)throw new Error("Change `browserslist` option to `overrideBrowserslist` in Autoprefixer");e.overrideBrowserslist?r=e.overrideBrowserslist:e.browsers&&(typeof console!="undefined"&&console.warn&&(of.red?console.warn(of.red(mv.replace(/`[^`]+`/g,n=>of.yellow(n.slice(1,-1))))):console.warn(mv)),r=e.browsers);let t={ignoreUnknownVersions:e.ignoreUnknownVersions,stats:e.stats,env:e.env};function i(n){let s=hv,a=new F5(s.browsers,r,n,t),o=a.selected.join(", ")+JSON.stringify(e);return lf.has(o)||lf.set(o,new j5(s.prefixes,a,e)),lf.get(o)}return{postcssPlugin:"autoprefixer",prepare(n){let s=i({from:n.opts.from,env:e.env});return{OnceExit(a){H5(n,s),e.remove!==!1&&s.processor.remove(a,n),e.add!==!1&&s.processor.add(a,n)}}},info(n){return n=n||{},n.from=n.from||m.cwd(),U5(i(n))},options:e,browsers:r}}Dr.postcss=!0;Dr.data=hv;Dr.defaults=N5.defaults;Dr.info=()=>Dr().info()});var bv={};Ge(bv,{default:()=>W5});var W5,wv=P(()=>{u();W5=[]});var xv={};Ge(xv,{default:()=>G5});var vv,G5,kv=P(()=>{u();Xi();vv=pe(rn()),G5=St(vv.default.theme)});var Av={};Ge(Av,{default:()=>Q5});var Sv,Q5,Cv=P(()=>{u();Xi();Sv=pe(rn()),Q5=St(Sv.default)});u();"use strict";var Y5=vt(_y()),K5=vt($e()),X5=vt(yv()),Z5=vt((wv(),bv)),J5=vt((kv(),xv)),eP=vt((Cv(),Av)),tP=vt((Vs(),_f)),rP=vt((al(),sl)),iP=vt((sa(),sc));function vt(r){return r&&r.__esModule?r:{default:r}}console.warn("cdn.tailwindcss.com should not be used in production. To use Tailwind CSS in production, install it as a PostCSS plugin or use the Tailwind CLI: https://tailwindcss.com/docs/installation");var Ns="tailwind",uf="text/tailwindcss",_v="/template.html",Yt,Ev=!0,Ov=0,ff=new Set,cf,Tv="",Rv=(r=!1)=>({get(e,t){return(!r||t==="config")&&typeof e[t]=="object"&&e[t]!==null?new Proxy(e[t],Rv()):e[t]},set(e,t,i){return e[t]=i,(!r||t==="config")&&pf(!0),!0}});window[Ns]=new Proxy({config:{},defaultTheme:J5.default,defaultConfig:eP.default,colors:tP.default,plugin:rP.default,resolveConfig:iP.default},Rv(!0));function Pv(r){cf.observe(r,{attributes:!0,attributeFilter:["type"],characterData:!0,subtree:!0,childList:!0})}new MutationObserver(async r=>{let e=!1;if(!cf){cf=new MutationObserver(async()=>await pf(!0));for(let t of document.querySelectorAll(`style[type="${uf}"]`))Pv(t)}for(let t of r)for(let i of t.addedNodes)i.nodeType===1&&i.tagName==="STYLE"&&i.getAttribute("type")===uf&&(Pv(i),e=!0);await pf(e)}).observe(document.documentElement,{attributes:!0,attributeFilter:["class"],childList:!0,subtree:!0});async function pf(r=!1){r&&(Ov++,ff.clear());let e="";for(let i of document.querySelectorAll(`style[type="${uf}"]`))e+=i.textContent;let t=new Set;for(let i of document.querySelectorAll("[class]"))for(let n of i.classList)ff.has(n)||t.add(n);if(document.body&&(Ev||t.size>0||e!==Tv||!Yt||!Yt.isConnected)){for(let n of t)ff.add(n);Ev=!1,Tv=e,self[_v]=Array.from(t).join(" ");let{css:i}=await(0,K5.default)([(0,Y5.default)({...window[Ns].config,_hash:Ov,content:{files:[_v],extract:{html:n=>n.split(" ")}},plugins:[...Z5.default,...Array.isArray(window[Ns].config.plugins)?window[Ns].config.plugins:[]]}),(0,X5.default)({remove:!1})]).process(`@tailwind base;@tailwind components;@tailwind utilities;${e}`);(!Yt||!Yt.isConnected)&&(Yt=document.createElement("style"),document.head.append(Yt)),Yt.textContent=i}}})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -45,7 +45,7 @@
<p>Follow BTCforPlebs on <a href="https://nostrudel.btcforplebs.com/u/npub1w4rz7n0vunaau499xh86p84s6v5mmgys48p0nmttt7w36takc9dsf4382j">Nostr</a> or <a href="https://youtube.com/@btcforplebs">YouTube</a> for the latest</p> <p>Follow BTCforPlebs on <a href="https://nostrudel.btcforplebs.com/u/npub1w4rz7n0vunaau499xh86p84s6v5mmgys48p0nmttt7w36takc9dsf4382j">Nostr</a> or <a href="https://youtube.com/@btcforplebs">YouTube</a> for the latest</p>
</div> </div>
<script src="https://btcforplebs.com/nostr-chat-widget.js" <script src="https://btcforplebs.com/nostr-chat-widget-mini.js"
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b" data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
data-brand-name="Chat with BTCforPlebs" data-brand-name="Chat with BTCforPlebs"
data-color="#8e30eb" data-color="#8e30eb"