swapout
This commit is contained in:
@@ -109,6 +109,13 @@
|
|||||||
</section>
|
</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>
|
<div id="back-to-top"><a href="#top" title="Back to Top">🔝</a></div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -188,7 +188,7 @@
|
|||||||
|
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
<script src="/nostr-chat-widget.js"
|
||||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||||
data-brand-name="Chat with BTCforPlebs"
|
data-brand-name="Chat with BTCforPlebs"
|
||||||
data-color="#fdad01"
|
data-color="#fdad01"
|
||||||
@@ -213,7 +213,8 @@
|
|||||||
if (sectionId) {
|
if (sectionId) {
|
||||||
document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' });
|
document.getElementById(sectionId).scrollIntoView({ behavior: 'smooth' });
|
||||||
}
|
}
|
||||||
}</script>
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
@@ -62,7 +62,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};</script>
|
};</script>
|
||||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
<script src="/nostr-chat-widget.js"
|
||||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||||
data-brand-name="Chat with BTCforPlebs"
|
data-brand-name="Chat with BTCforPlebs"
|
||||||
data-color="#fdad01"
|
data-color="#fdad01"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<div id="back-to-top">
|
<div id="back-to-top">
|
||||||
<a href="#top" title="Back to Top">🔝</a>
|
<a href="#top" title="Back to Top">🔝</a>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
<script src="/nostr-chat-widget.js"
|
||||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||||
data-brand-name="Chat with BTCforPlebs"
|
data-brand-name="Chat with BTCforPlebs"
|
||||||
data-color="#fdad01"
|
data-color="#fdad01"
|
||||||
|
|||||||
@@ -105,7 +105,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="footer"></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-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||||
data-brand-name="Chat with BTCforPlebs"
|
data-brand-name="Chat with BTCforPlebs"
|
||||||
data-color="#fdad01"
|
data-color="#fdad01"
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
<a href="/index.html" class="button">Home</a>
|
<a href="/index.html" class="button">Home</a>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script src="https://btcforplebs.com/nostr-chat-widget.js"
|
<script src="/nostr-chat-widget.js"
|
||||||
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
data-nostr-pubkey="75462f4dece4fbde54a535cfa09eb0d329bda090a9c2f9ed6b5f9d1d2fb6c15b"
|
||||||
data-brand-name="Chat with BTCforPlebs"
|
data-brand-name="Chat with BTCforPlebs"
|
||||||
data-color="#fdad01"
|
data-color="#fdad01"
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
* </script>
|
* </script>
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
'use strict';
|
'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';
|
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover';
|
||||||
|
|
||||||
|
|
||||||
// Inject custom styles with glassmorphism
|
// 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: env(safe-area-inset-bottom);
|
padding-bottom: max(env(safe-area-inset-bottom), 1rem);
|
||||||
}
|
}
|
||||||
#nostr-chat-widget-root > div {
|
#nostr-chat-widget-root > div {
|
||||||
pointer-events: auto !important;
|
pointer-events: auto !important;
|
||||||
@@ -127,6 +125,7 @@
|
|||||||
z-index: 10 !important;
|
z-index: 10 !important;
|
||||||
backdrop-filter: blur(20px) !important;
|
backdrop-filter: blur(20px) !important;
|
||||||
-webkit-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() {
|
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.myPrivKey = getSessionKey();
|
||||||
state.myPubKey = getPublicKey(state.myPrivKey);
|
state.myPubKey = getPublicKey(state.myPrivKey);
|
||||||
state.sessionId = state.myPubKey.substring(0, 8);
|
state.sessionId = state.myPubKey.substring(0, 8);
|
||||||
|
|
||||||
console.log('🔑 Session Identity:', nip19.npubEncode(state.myPubKey));
|
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) => {
|
const relayPromises = CONFIG.relays.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
|
console.log(\`Attempting: \${url}\`);
|
||||||
const relay = relayInit(url);
|
const relay = relayInit(url);
|
||||||
|
|
||||||
relay.on('connect', () => {
|
relay.on('connect', () => {
|
||||||
@@ -217,6 +228,11 @@
|
|||||||
|
|
||||||
relay.on('disconnect', () => {
|
relay.on('disconnect', () => {
|
||||||
console.log(\`✗ Disconnected from \${url}\`);
|
console.log(\`✗ Disconnected from \${url}\`);
|
||||||
|
checkConnection();
|
||||||
|
});
|
||||||
|
|
||||||
|
relay.on('error', (err) => {
|
||||||
|
console.error(\`❌ Relay error \${url}:\`, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
await relay.connect();
|
await relay.connect();
|
||||||
@@ -229,13 +245,13 @@
|
|||||||
|
|
||||||
state.relays = (await Promise.all(relayPromises)).filter(r => r !== null);
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(\`✓ Connected to \${state.relays.length}/\${CONFIG.relays.length} relays\`);
|
|
||||||
|
|
||||||
subscribeToReplies();
|
subscribeToReplies();
|
||||||
loadPreviousMessages();
|
loadPreviousMessages();
|
||||||
|
|
||||||
@@ -324,6 +340,10 @@
|
|||||||
|
|
||||||
async function sendMessage() {
|
async function sendMessage() {
|
||||||
if (!state.inputMessage.trim()) return;
|
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;
|
const messageText = state.inputMessage;
|
||||||
state.inputMessage = '';
|
state.inputMessage = '';
|
||||||
@@ -360,17 +380,26 @@
|
|||||||
event.sig = signEvent(event, state.myPrivKey);
|
event.sig = signEvent(event, state.myPrivKey);
|
||||||
|
|
||||||
let published = 0;
|
let published = 0;
|
||||||
for (const relay of state.relays) {
|
const publishPromises = state.relays.map(async (relay) => {
|
||||||
try {
|
try {
|
||||||
await relay.publish(event);
|
await relay.publish(event);
|
||||||
published++;
|
published++;
|
||||||
console.log(\`✓ Published to \${relay.url}\`);
|
console.log(\`✓ Published to \${relay.url}\`);
|
||||||
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(\`✗ Failed: \${relay.url}:\`, err);
|
console.error(\`✗ Failed: \${relay.url}:\`, err);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
await Promise.all(publishPromises);
|
||||||
|
|
||||||
if (published === 0) {
|
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');
|
addMessage('system', '⚠️ Failed to send - no relay connections');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -386,7 +415,13 @@
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sending:', 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="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-white/80 truncate">
|
<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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -526,7 +561,7 @@
|
|||||||
}).join('')}
|
}).join('')}
|
||||||
</div>
|
</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">
|
<div class="glass-input rounded-xl p-2 flex gap-2 items-center">
|
||||||
<input
|
<input
|
||||||
id="nostr-message-input"
|
id="nostr-message-input"
|
||||||
@@ -563,7 +598,6 @@
|
|||||||
sendButton.disabled = !state.connected || !e.target.value.trim();
|
sendButton.disabled = !state.connected || !e.target.value.trim();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
messageInput.addEventListener('keypress', (e) => {
|
messageInput.addEventListener('keypress', (e) => {
|
||||||
if (e.key === 'Enter' && !e.shiftKey) {
|
if (e.key === 'Enter' && !e.shiftKey) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|||||||
@@ -33,15 +33,15 @@
|
|||||||
if (!viewportMeta) {
|
if (!viewportMeta) {
|
||||||
viewportMeta = document.createElement('meta');
|
viewportMeta = document.createElement('meta');
|
||||||
viewportMeta.name = 'viewport';
|
viewportMeta.name = 'viewport';
|
||||||
viewportMeta.content = 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no';
|
|
||||||
document.head.appendChild(viewportMeta);
|
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
|
// 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: env(safe-area-inset-bottom);
|
padding-bottom: max(env(safe-area-inset-bottom), 1rem);
|
||||||
}
|
}
|
||||||
#nostr-chat-widget-root > div {
|
#nostr-chat-widget-root > div {
|
||||||
pointer-events: auto !important;
|
pointer-events: auto !important;
|
||||||
@@ -71,7 +71,26 @@
|
|||||||
.glass-input::placeholder {
|
.glass-input::placeholder {
|
||||||
color: rgba(255, 255, 255, 0.6);
|
color: rgba(255, 255, 255, 0.6);
|
||||||
}
|
}
|
||||||
|
.mobile-input-container {
|
||||||
|
position: sticky;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
@media (max-width: 640px) {
|
@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 {
|
#nostr-chat-widget-root .chat-window-mobile {
|
||||||
position: fixed !important;
|
position: fixed !important;
|
||||||
top: 0 !important;
|
top: 0 !important;
|
||||||
@@ -79,9 +98,34 @@
|
|||||||
right: 0 !important;
|
right: 0 !important;
|
||||||
bottom: 0 !important;
|
bottom: 0 !important;
|
||||||
width: 100% !important;
|
width: 100% !important;
|
||||||
height: 100% !important;
|
height: 100vh !important;
|
||||||
|
height: 100dvh !important;
|
||||||
max-height: 100vh !important;
|
max-height: 100vh !important;
|
||||||
|
max-height: 100dvh !important;
|
||||||
border-radius: 0 !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() {
|
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.myPrivKey = getSessionKey();
|
||||||
state.myPubKey = getPublicKey(state.myPrivKey);
|
state.myPubKey = getPublicKey(state.myPrivKey);
|
||||||
state.sessionId = state.myPubKey.substring(0, 8);
|
state.sessionId = state.myPubKey.substring(0, 8);
|
||||||
|
|
||||||
console.log('🔑 Session Identity:', nip19.npubEncode(state.myPubKey));
|
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) => {
|
const relayPromises = CONFIG.relays.map(async (url) => {
|
||||||
try {
|
try {
|
||||||
|
console.log(\`Attempting: \${url}\`);
|
||||||
const relay = relayInit(url);
|
const relay = relayInit(url);
|
||||||
|
|
||||||
relay.on('connect', () => {
|
relay.on('connect', () => {
|
||||||
@@ -172,6 +228,11 @@
|
|||||||
|
|
||||||
relay.on('disconnect', () => {
|
relay.on('disconnect', () => {
|
||||||
console.log(\`✗ Disconnected from \${url}\`);
|
console.log(\`✗ Disconnected from \${url}\`);
|
||||||
|
checkConnection();
|
||||||
|
});
|
||||||
|
|
||||||
|
relay.on('error', (err) => {
|
||||||
|
console.error(\`❌ Relay error \${url}:\`, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
await relay.connect();
|
await relay.connect();
|
||||||
@@ -184,13 +245,13 @@
|
|||||||
|
|
||||||
state.relays = (await Promise.all(relayPromises)).filter(r => r !== null);
|
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) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(\`✓ Connected to \${state.relays.length}/\${CONFIG.relays.length} relays\`);
|
|
||||||
|
|
||||||
subscribeToReplies();
|
subscribeToReplies();
|
||||||
loadPreviousMessages();
|
loadPreviousMessages();
|
||||||
|
|
||||||
@@ -279,6 +340,10 @@
|
|||||||
|
|
||||||
async function sendMessage() {
|
async function sendMessage() {
|
||||||
if (!state.inputMessage.trim()) return;
|
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;
|
const messageText = state.inputMessage;
|
||||||
state.inputMessage = '';
|
state.inputMessage = '';
|
||||||
@@ -315,17 +380,26 @@
|
|||||||
event.sig = signEvent(event, state.myPrivKey);
|
event.sig = signEvent(event, state.myPrivKey);
|
||||||
|
|
||||||
let published = 0;
|
let published = 0;
|
||||||
for (const relay of state.relays) {
|
const publishPromises = state.relays.map(async (relay) => {
|
||||||
try {
|
try {
|
||||||
await relay.publish(event);
|
await relay.publish(event);
|
||||||
published++;
|
published++;
|
||||||
console.log(\`✓ Published to \${relay.url}\`);
|
console.log(\`✓ Published to \${relay.url}\`);
|
||||||
|
return true;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(\`✗ Failed: \${relay.url}:\`, err);
|
console.error(\`✗ Failed: \${relay.url}:\`, err);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
|
await Promise.all(publishPromises);
|
||||||
|
|
||||||
if (published === 0) {
|
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');
|
addMessage('system', '⚠️ Failed to send - no relay connections');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -341,7 +415,13 @@
|
|||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error sending:', 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,8 +443,13 @@
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const container = document.getElementById('nostr-messages');
|
const container = document.getElementById('nostr-messages');
|
||||||
if (container) {
|
if (container) {
|
||||||
|
// 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;
|
container.scrollTop = container.scrollHeight;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -408,14 +493,14 @@
|
|||||||
container.innerHTML = \`
|
container.innerHTML = \`
|
||||||
<div class="fixed inset-0 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="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="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 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-0.5">
|
<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-white/80 truncate">
|
<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>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -432,7 +517,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</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 ? \`
|
\${state.messages.length === 0 ? \`
|
||||||
<div class="text-center text-white/60 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">
|
||||||
@@ -476,7 +561,7 @@
|
|||||||
}).join('')}
|
}).join('')}
|
||||||
</div>
|
</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">
|
<div class="glass-input rounded-xl p-2 flex gap-2 items-center">
|
||||||
<input
|
<input
|
||||||
id="nostr-message-input"
|
id="nostr-message-input"
|
||||||
@@ -527,14 +612,22 @@
|
|||||||
}, 100);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only auto-focus on desktop
|
||||||
|
if (window.innerWidth >= 640) {
|
||||||
messageInput.focus();
|
messageInput.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Expose global API
|
// Expose global API
|
||||||
window.NostrChat = {
|
window.NostrChat = {
|
||||||
open: async () => {
|
open: async () => {
|
||||||
state.isOpen = true;
|
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();
|
render();
|
||||||
if (state.relays.length === 0) {
|
if (state.relays.length === 0) {
|
||||||
await init();
|
await init();
|
||||||
@@ -542,6 +635,9 @@
|
|||||||
},
|
},
|
||||||
close: () => {
|
close: () => {
|
||||||
state.isOpen = false;
|
state.isOpen = false;
|
||||||
|
// Restore body scroll on mobile
|
||||||
|
document.documentElement.classList.remove('chat-open');
|
||||||
|
document.body.classList.remove('chat-open');
|
||||||
render();
|
render();
|
||||||
},
|
},
|
||||||
send: sendMessage
|
send: sendMessage
|
||||||
@@ -554,7 +650,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>
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -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-WIP.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"
|
||||||
|
|||||||
Reference in New Issue
Block a user