swapout
This commit is contained in:
@@ -108,7 +108,14 @@
|
||||
<p>Week 6 wraps up the series with a practical, faith‑first guide to the next steps in a Bitcoin journey. Logan reviews the final podcast episodes, outlines how to move from “just learning” to owning, securing, and sharing Bitcoin, and reminds listeners that the true goal is to place Christ first, practice generosity, and build a financial legacy that glorifies God. The session ends with a heartfelt prayer and an invitation for anyone to step into the gospel—one small step at a time.</p>
|
||||
</section>
|
||||
|
||||
<footer id="footer"></footer>
|
||||
<footer id="footer"></footer>
|
||||
<script src="/nostr-chat-widget.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#fdad01"
|
||||
data-color-secondary="#222222">
|
||||
</script>
|
||||
|
||||
<div id="back-to-top"><a href="#top" title="Back to Top">🔝</a></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -188,7 +188,7 @@
|
||||
|
||||
</section>
|
||||
</div>
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
||||
<script src="/nostr-chat-widget.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#fdad01"
|
||||
@@ -213,7 +213,8 @@
|
||||
if (sectionId) {
|
||||
document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' });
|
||||
}
|
||||
}</script>
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
</html>
|
||||
@@ -62,7 +62,7 @@
|
||||
}
|
||||
}
|
||||
};</script>
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
||||
<script src="/nostr-chat-widget.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#fdad01"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<div id="back-to-top">
|
||||
<a href="#top" title="Back to Top">🔝</a>
|
||||
</div>
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
||||
<script src="/nostr-chat-widget.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#fdad01"
|
||||
|
||||
@@ -105,7 +105,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="footer"></div>
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
||||
<script src="/nostr-chat-widget.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#fdad01"
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<a href="/index.html" class="button">Home</a>
|
||||
|
||||
</div>
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
||||
<script src="/nostr-chat-widget.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#fdad01"
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
* </script>
|
||||
*/
|
||||
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
@@ -38,12 +37,11 @@
|
||||
}
|
||||
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover';
|
||||
|
||||
|
||||
// Inject custom styles with glassmorphism
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.safe-area-bottom {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-bottom: max(env(safe-area-inset-bottom), 1rem);
|
||||
}
|
||||
#nostr-chat-widget-root > div {
|
||||
pointer-events: auto !important;
|
||||
@@ -127,6 +125,7 @@
|
||||
z-index: 10 !important;
|
||||
backdrop-filter: blur(20px) !important;
|
||||
-webkit-backdrop-filter: blur(20px) !important;
|
||||
padding-bottom: max(env(safe-area-inset-bottom), 1.5rem) !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -200,14 +199,26 @@
|
||||
}
|
||||
|
||||
async function init() {
|
||||
// Check for crypto.subtle availability (requires HTTPS)
|
||||
if (!window.crypto || !window.crypto.subtle) {
|
||||
state.connected = false;
|
||||
addMessage('system', '⚠️ Secure connection required. Please use HTTPS.');
|
||||
console.error('crypto.subtle not available. Page must be served over HTTPS.');
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
state.myPrivKey = getSessionKey();
|
||||
state.myPubKey = getPublicKey(state.myPrivKey);
|
||||
state.sessionId = state.myPubKey.substring(0, 8);
|
||||
|
||||
console.log('🔑 Session Identity:', nip19.npubEncode(state.myPubKey));
|
||||
console.log('📱 User Agent:', navigator.userAgent);
|
||||
console.log('🌐 Connecting to relays...');
|
||||
|
||||
const relayPromises = CONFIG.relays.map(async (url) => {
|
||||
try {
|
||||
console.log(\`Attempting: \${url}\`);
|
||||
const relay = relayInit(url);
|
||||
|
||||
relay.on('connect', () => {
|
||||
@@ -217,6 +228,11 @@
|
||||
|
||||
relay.on('disconnect', () => {
|
||||
console.log(\`✗ Disconnected from \${url}\`);
|
||||
checkConnection();
|
||||
});
|
||||
|
||||
relay.on('error', (err) => {
|
||||
console.error(\`❌ Relay error \${url}:\`, err);
|
||||
});
|
||||
|
||||
await relay.connect();
|
||||
@@ -229,13 +245,13 @@
|
||||
|
||||
state.relays = (await Promise.all(relayPromises)).filter(r => r !== null);
|
||||
|
||||
console.log(\`✓ Connected to \${state.relays.length}/\${CONFIG.relays.length} relays\`);
|
||||
|
||||
if (state.relays.length === 0) {
|
||||
addMessage('system', '⚠️ Failed to connect to any relays');
|
||||
addMessage('system', '⚠️ Failed to connect to any relays. Check console for details.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(\`✓ Connected to \${state.relays.length}/\${CONFIG.relays.length} relays\`);
|
||||
|
||||
subscribeToReplies();
|
||||
loadPreviousMessages();
|
||||
|
||||
@@ -324,6 +340,10 @@
|
||||
|
||||
async function sendMessage() {
|
||||
if (!state.inputMessage.trim()) return;
|
||||
if (!state.connected || state.relays.length === 0) {
|
||||
addMessage('system', '⚠️ Not connected to relays. Please wait...');
|
||||
return;
|
||||
}
|
||||
|
||||
const messageText = state.inputMessage;
|
||||
state.inputMessage = '';
|
||||
@@ -360,17 +380,26 @@
|
||||
event.sig = signEvent(event, state.myPrivKey);
|
||||
|
||||
let published = 0;
|
||||
for (const relay of state.relays) {
|
||||
const publishPromises = state.relays.map(async (relay) => {
|
||||
try {
|
||||
await relay.publish(event);
|
||||
published++;
|
||||
console.log(\`✓ Published to \${relay.url}\`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(\`✗ Failed: \${relay.url}:\`, err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(publishPromises);
|
||||
|
||||
if (published === 0) {
|
||||
// Remove the temp message
|
||||
const msgIndex = state.messages.findIndex(m => m.id === tempMessage.id);
|
||||
if (msgIndex !== -1) {
|
||||
state.messages.splice(msgIndex, 1);
|
||||
}
|
||||
addMessage('system', '⚠️ Failed to send - no relay connections');
|
||||
return;
|
||||
}
|
||||
@@ -386,7 +415,13 @@
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error sending:', error);
|
||||
addMessage('system', '⚠️ Failed to send message');
|
||||
// Remove the temp message on error
|
||||
const msgIndex = state.messages.findIndex(m => m.id === tempMessage.id);
|
||||
if (msgIndex !== -1) {
|
||||
state.messages.splice(msgIndex, 1);
|
||||
}
|
||||
addMessage('system', '⚠️ Failed to send: ' + error.message);
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,7 +500,7 @@
|
||||
<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>
|
||||
<span class="text-xs text-white/80 truncate">
|
||||
\${state.connected ? \`P2P E2EE • \${state.relays.length} relays\` : 'Connecting...'}
|
||||
\${state.connected ? \`Encrypted • \${state.relays.length} relays\` : 'Connecting...'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -526,7 +561,7 @@
|
||||
}).join('')}
|
||||
</div>
|
||||
|
||||
<div class="p-3 sm:p-3.5 sm:mb-2 flex-shrink-0 safe-area-bottom mobile-input-container">
|
||||
<div class="p-3 sm:p-3.5 sm:mb-2 pb-6 flex-shrink-0 safe-area-bottom mobile-input-container">
|
||||
<div class="glass-input rounded-xl p-2 flex gap-2 items-center">
|
||||
<input
|
||||
id="nostr-message-input"
|
||||
@@ -563,7 +598,6 @@
|
||||
sendButton.disabled = !state.connected || !e.target.value.trim();
|
||||
}
|
||||
});
|
||||
|
||||
messageInput.addEventListener('keypress', (e) => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault();
|
||||
|
||||
@@ -33,15 +33,15 @@
|
||||
if (!viewportMeta) {
|
||||
viewportMeta = document.createElement('meta');
|
||||
viewportMeta.name = 'viewport';
|
||||
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';
|
||||
document.head.appendChild(viewportMeta);
|
||||
}
|
||||
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover';
|
||||
|
||||
// Inject custom styles with glassmorphism
|
||||
const style = document.createElement('style');
|
||||
style.textContent = `
|
||||
.safe-area-bottom {
|
||||
padding-bottom: env(safe-area-inset-bottom);
|
||||
padding-bottom: max(env(safe-area-inset-bottom), 1rem);
|
||||
}
|
||||
#nostr-chat-widget-root > div {
|
||||
pointer-events: auto !important;
|
||||
@@ -71,7 +71,26 @@
|
||||
.glass-input::placeholder {
|
||||
color: rgba(255, 255, 255, 0.6);
|
||||
}
|
||||
.mobile-input-container {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: transparent;
|
||||
}
|
||||
@media (max-width: 640px) {
|
||||
html.chat-open {
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
body.chat-open {
|
||||
overflow: hidden;
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#nostr-chat-widget-root .chat-window-mobile {
|
||||
position: fixed !important;
|
||||
top: 0 !important;
|
||||
@@ -79,9 +98,34 @@
|
||||
right: 0 !important;
|
||||
bottom: 0 !important;
|
||||
width: 100% !important;
|
||||
height: 100% !important;
|
||||
height: 100vh !important;
|
||||
height: 100dvh !important;
|
||||
max-height: 100vh !important;
|
||||
max-height: 100dvh !important;
|
||||
border-radius: 0 !important;
|
||||
display: flex !important;
|
||||
flex-direction: column !important;
|
||||
}
|
||||
#nostr-chat-widget-root .chat-header-mobile {
|
||||
flex-shrink: 0 !important;
|
||||
}
|
||||
#nostr-chat-widget-root .chat-messages-mobile {
|
||||
flex: 1 1 0% !important;
|
||||
overflow-y: auto !important;
|
||||
overflow-x: hidden !important;
|
||||
-webkit-overflow-scrolling: touch !important;
|
||||
min-height: 0 !important;
|
||||
overscroll-behavior: contain !important;
|
||||
padding-bottom: 1rem !important;
|
||||
}
|
||||
#nostr-chat-widget-root .mobile-input-container {
|
||||
position: sticky !important;
|
||||
bottom: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
z-index: 10 !important;
|
||||
backdrop-filter: blur(20px) !important;
|
||||
-webkit-backdrop-filter: blur(20px) !important;
|
||||
padding-bottom: max(env(safe-area-inset-bottom), 1.5rem) !important;
|
||||
}
|
||||
}
|
||||
`;
|
||||
@@ -155,14 +199,26 @@
|
||||
}
|
||||
|
||||
async function init() {
|
||||
// Check for crypto.subtle availability (requires HTTPS)
|
||||
if (!window.crypto || !window.crypto.subtle) {
|
||||
state.connected = false;
|
||||
addMessage('system', '⚠️ Secure connection required. Please use HTTPS.');
|
||||
console.error('crypto.subtle not available. Page must be served over HTTPS.');
|
||||
render();
|
||||
return;
|
||||
}
|
||||
|
||||
state.myPrivKey = getSessionKey();
|
||||
state.myPubKey = getPublicKey(state.myPrivKey);
|
||||
state.sessionId = state.myPubKey.substring(0, 8);
|
||||
|
||||
console.log('🔑 Session Identity:', nip19.npubEncode(state.myPubKey));
|
||||
console.log('📱 User Agent:', navigator.userAgent);
|
||||
console.log('🌐 Connecting to relays...');
|
||||
|
||||
const relayPromises = CONFIG.relays.map(async (url) => {
|
||||
try {
|
||||
console.log(\`Attempting: \${url}\`);
|
||||
const relay = relayInit(url);
|
||||
|
||||
relay.on('connect', () => {
|
||||
@@ -172,6 +228,11 @@
|
||||
|
||||
relay.on('disconnect', () => {
|
||||
console.log(\`✗ Disconnected from \${url}\`);
|
||||
checkConnection();
|
||||
});
|
||||
|
||||
relay.on('error', (err) => {
|
||||
console.error(\`❌ Relay error \${url}:\`, err);
|
||||
});
|
||||
|
||||
await relay.connect();
|
||||
@@ -184,13 +245,13 @@
|
||||
|
||||
state.relays = (await Promise.all(relayPromises)).filter(r => r !== null);
|
||||
|
||||
console.log(\`✓ Connected to \${state.relays.length}/\${CONFIG.relays.length} relays\`);
|
||||
|
||||
if (state.relays.length === 0) {
|
||||
addMessage('system', '⚠️ Failed to connect to any relays');
|
||||
addMessage('system', '⚠️ Failed to connect to any relays. Check console for details.');
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(\`✓ Connected to \${state.relays.length}/\${CONFIG.relays.length} relays\`);
|
||||
|
||||
subscribeToReplies();
|
||||
loadPreviousMessages();
|
||||
|
||||
@@ -279,6 +340,10 @@
|
||||
|
||||
async function sendMessage() {
|
||||
if (!state.inputMessage.trim()) return;
|
||||
if (!state.connected || state.relays.length === 0) {
|
||||
addMessage('system', '⚠️ Not connected to relays. Please wait...');
|
||||
return;
|
||||
}
|
||||
|
||||
const messageText = state.inputMessage;
|
||||
state.inputMessage = '';
|
||||
@@ -315,17 +380,26 @@
|
||||
event.sig = signEvent(event, state.myPrivKey);
|
||||
|
||||
let published = 0;
|
||||
for (const relay of state.relays) {
|
||||
const publishPromises = state.relays.map(async (relay) => {
|
||||
try {
|
||||
await relay.publish(event);
|
||||
published++;
|
||||
console.log(\`✓ Published to \${relay.url}\`);
|
||||
return true;
|
||||
} catch (err) {
|
||||
console.error(\`✗ Failed: \${relay.url}:\`, err);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(publishPromises);
|
||||
|
||||
if (published === 0) {
|
||||
// Remove the temp message
|
||||
const msgIndex = state.messages.findIndex(m => m.id === tempMessage.id);
|
||||
if (msgIndex !== -1) {
|
||||
state.messages.splice(msgIndex, 1);
|
||||
}
|
||||
addMessage('system', '⚠️ Failed to send - no relay connections');
|
||||
return;
|
||||
}
|
||||
@@ -341,7 +415,13 @@
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error sending:', error);
|
||||
addMessage('system', '⚠️ Failed to send message');
|
||||
// Remove the temp message on error
|
||||
const msgIndex = state.messages.findIndex(m => m.id === tempMessage.id);
|
||||
if (msgIndex !== -1) {
|
||||
state.messages.splice(msgIndex, 1);
|
||||
}
|
||||
addMessage('system', '⚠️ Failed to send: ' + error.message);
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -363,7 +443,12 @@
|
||||
setTimeout(() => {
|
||||
const container = document.getElementById('nostr-messages');
|
||||
if (container) {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
// Smooth scroll on desktop, instant on mobile for better keyboard handling
|
||||
if (window.innerWidth >= 640) {
|
||||
container.scrollTo({ top: container.scrollHeight, behavior: 'smooth' });
|
||||
} else {
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
@@ -408,14 +493,14 @@
|
||||
container.innerHTML = \`
|
||||
<div class="fixed inset-0 sm:inset-auto sm:bottom-6 sm:right-6 z-[99999]">
|
||||
<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 style="background: linear-gradient(to bottom right, \${CONFIG.primaryColor}, \${CONFIG.secondaryColor});" class="text-white p-3.5 sm:p-4">
|
||||
<div style="background: linear-gradient(to bottom right, \${CONFIG.primaryColor}, \${CONFIG.secondaryColor});" class="text-white p-3.5 sm:p-4 chat-header-mobile">
|
||||
<div class="flex justify-between items-center">
|
||||
<div class="flex-1 min-w-0">
|
||||
<h3 class="font-bold text-base sm:text-lg">\${CONFIG.brandName}</h3>
|
||||
<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>
|
||||
<span class="text-xs text-white/80 truncate">
|
||||
\${state.connected ? \`P2P E2EE • \${state.relays.length} relays\` : 'Connecting...'}
|
||||
\${state.connected ? \`Encrypted • \${state.relays.length} relays\` : 'Connecting...'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -432,7 +517,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="nostr-messages" class="flex-1 overflow-y-auto p-3 sm:p-3.5 space-y-3 glass-morphism-light">
|
||||
<div id="nostr-messages" class="flex-1 overflow-y-auto p-3 sm:p-3.5 space-y-3 glass-morphism-light chat-messages-mobile">
|
||||
\${state.messages.length === 0 ? \`
|
||||
<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">
|
||||
@@ -476,7 +561,7 @@
|
||||
}).join('')}
|
||||
</div>
|
||||
|
||||
<div class="p-3 sm:p-3.5 mb-2 flex-shrink-0 safe-area-bottom">
|
||||
<div class="p-3 sm:p-3.5 sm:mb-2 pb-6 flex-shrink-0 safe-area-bottom mobile-input-container">
|
||||
<div class="glass-input rounded-xl p-2 flex gap-2 items-center">
|
||||
<input
|
||||
id="nostr-message-input"
|
||||
@@ -527,7 +612,10 @@
|
||||
}, 100);
|
||||
}
|
||||
|
||||
messageInput.focus();
|
||||
// Only auto-focus on desktop
|
||||
if (window.innerWidth >= 640) {
|
||||
messageInput.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,6 +623,11 @@
|
||||
window.NostrChat = {
|
||||
open: async () => {
|
||||
state.isOpen = true;
|
||||
// Prevent body scroll on mobile
|
||||
if (window.innerWidth < 640) {
|
||||
document.documentElement.classList.add('chat-open');
|
||||
document.body.classList.add('chat-open');
|
||||
}
|
||||
render();
|
||||
if (state.relays.length === 0) {
|
||||
await init();
|
||||
@@ -542,6 +635,9 @@
|
||||
},
|
||||
close: () => {
|
||||
state.isOpen = false;
|
||||
// Restore body scroll on mobile
|
||||
document.documentElement.classList.remove('chat-open');
|
||||
document.body.classList.remove('chat-open');
|
||||
render();
|
||||
},
|
||||
send: sendMessage
|
||||
@@ -554,7 +650,6 @@
|
||||
document.body.appendChild(widgetScript);
|
||||
})();
|
||||
|
||||
|
||||
/*!
|
||||
* fill-range <https://github.com/jonschlinkert/fill-range>
|
||||
*
|
||||
|
||||
@@ -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>
|
||||
</div>
|
||||
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
||||
<script src="https://btcforplebs.com/nostr-chat-widget-WIP.js"
|
||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||
data-brand-name="Chat with BTCforPlebs"
|
||||
data-color="#8e30eb"
|
||||
|
||||
Reference in New Issue
Block a user