Working on ui

This commit is contained in:
Your Name 2025-09-24 14:05:19 -04:00
parent 6f46fce625
commit f10ee66972
3 changed files with 105 additions and 47 deletions

View File

@ -418,6 +418,8 @@ small {
border-radius: var(--border-radius);
filter: grayscale(100%);
transition: filter 0.3s ease;
object-fit: cover;
object-position: center;
}
#thrower-banner:hover {
@ -431,6 +433,8 @@ small {
border: var(--border-width) solid var(--primary-color);
filter: grayscale(100%);
transition: filter 0.3s ease;
object-fit: cover;
object-position: center;
}
#thrower-icon:hover {
@ -449,6 +453,8 @@ small {
border: var(--border-width) solid var(--primary-color);
filter: grayscale(100%);
transition: filter 0.3s ease;
object-fit: cover;
object-position: center;
}
#profile-picture:hover {

View File

@ -542,7 +542,7 @@
<div class="thrower-details-section collapsed" id="details-${index}">
${thrower.icon ? `
<div style="margin-bottom: 15px;">
<img src="${thrower.icon}" style="width: 50px; height: 50px; border-radius: var(--border-radius); border: var(--border-width) solid var(--primary-color); filter: grayscale(100%); transition: filter 0.3s ease;" onmouseover="this.style.filter='grayscale(0%) saturate(50%)'" onmouseout="this.style.filter='grayscale(100%)'">
<img src="${thrower.icon}" style="width: 50px; height: 50px; border-radius: var(--border-radius); border: var(--border-width) solid var(--primary-color); filter: grayscale(100%); transition: filter 0.3s ease; object-fit: cover; object-position: center;" onmouseover="this.style.filter='grayscale(0%) saturate(50%)'" onmouseout="this.style.filter='grayscale(100%)'">
</div>
` : ''}
@ -762,16 +762,17 @@
select.removeChild(select.lastChild);
}
// Add discovered throwers
// Add discovered throwers with real-time online status check
discoveredThrowers.forEach(thrower => {
const option = document.createElement('option');
option.value = thrower.pubkey;
// Always check current online status when populating
const onlineStatus = isThrowerOnline(thrower) ? '🟢' : '🔴';
option.textContent = `${onlineStatus} ${thrower.name} (${thrower.pubkey.substring(0, 8)}...)`;
select.appendChild(option);
});
console.log('INFO', `Populated thrower dropdown for bounce ${bounceId} with ${discoveredThrowers.length} throwers`);
console.log('INFO', `Populated thrower dropdown for bounce ${bounceId} with ${discoveredThrowers.length} throwers (with current online status)`);
}
// Update all existing thrower dropdowns with current online status
@ -904,7 +905,7 @@
return null;
}
// Populate relay dropdown with relays the selected thrower can read from
// Populate relay dropdown with relays the selected thrower can throw to (write to)
function populateRelayDropdown(bounceId, throwerPubkey) {
const relaySelect = document.getElementById(`relay-select-${bounceId}`);
const relayInput = document.getElementById(`bounce-relays-${bounceId}`);
@ -927,17 +928,15 @@
return;
}
// Get relays the thrower can read from (read or both)
const readableRelays = thrower.relayList.relays.filter(r => r.type === 'read' || r.type === 'both');
// Get relays the thrower can write to (write or both)
// Get relays the thrower can write to (write or both) - these are the relays it can throw to
const writableRelays = thrower.relayList.relays.filter(r => r.type === 'write' || r.type === 'both');
if (readableRelays.length === 0) {
relaySelect.innerHTML = '<option value="">-- This thrower cannot read from any relays --</option><option value="__manual__">⊕ Add manually (enter relay URL)</option>';
// Show manual option since thrower has no readable relays
if (writableRelays.length === 0) {
relaySelect.innerHTML = '<option value="">-- This thrower cannot throw to any relays --</option><option value="__manual__">⊕ Add manually (enter relay URL)</option>';
// Show manual option since thrower has no writable relays
const manualOption = relaySelect.querySelector('option[value="__manual__"]');
manualOption.classList.remove('hidden');
console.log('WARN', `Thrower ${thrower.name} cannot read from any relays`);
console.log('WARN', `Thrower ${thrower.name} cannot throw to any relays`);
return;
}
@ -949,8 +948,8 @@
relaySelect.appendChild(allRelaysOption);
}
// Add readable relays to dropdown
readableRelays.forEach(relay => {
// Add writable relays to dropdown (these are the relays the thrower can throw to)
writableRelays.forEach(relay => {
const option = document.createElement('option');
option.value = relay.url;
option.textContent = relay.url;
@ -967,7 +966,7 @@
relayInput.value = '';
relayManualDiv.classList.add('hidden');
console.log('INFO', `Populated relay dropdown for bounce ${bounceId} with ${readableRelays.length} readable relays and ${writableRelays.length} writable relays from ${thrower.name}`);
console.log('INFO', `Populated relay dropdown for bounce ${bounceId} with ${writableRelays.length} writable relays that ${thrower.name} can throw to`);
}
// Clear relay dropdown
@ -1142,7 +1141,7 @@
</div>
</div>
<div class="input-group">
<label for="relay-select-${bounceId}">Target Relay:</label>
<label for="relay-select-${bounceId}">Thrower throws to this relay(s):</label>
<select id="relay-select-${bounceId}" onchange="onRelaySelect(${bounceId})" style="width: 100%; margin-bottom: 10px;">
<option value="">-- Select a thrower first --</option>
<option value="__manual__" class="hidden">⊕ Add manually (enter relay URL)</option>
@ -1647,19 +1646,12 @@
const throwerName = getThrowerName(bounce, bounceNumber);
if (isFirst) {
// User sends the outermost routing event (first bounce created)
// For the first bounce, we skip the user publishing step since it's handled by the button
// Start directly with relay propagation after the button click
const routingEventSize = JSON.stringify(bounce.routingEvent).length;
const relays = getRelaysForBounce(bounceNumber);
// Step 1: User sends to relay
flow.push({
time: currentTime,
actor: userName,
action: `Publishes routing event`,
size: routingEventSize
});
// Step 2: Relay propagates (immediate)
// Step 1: Relay propagates (immediate after button click)
currentTime += 2000; // 2 seconds for relay propagation
flow.push({
time: currentTime,

View File

@ -48,7 +48,7 @@
<div><strong>Events in Queue:</strong> <span id="events-queued">0</span></div>
<div><strong>Info Status:</strong> <span id="thrower-info-status">Loading...</span></div>
<div><strong>Last Updated:</strong> <span id="thrower-info-updated">Never</span></div>
<div><strong>Refresh Rate:</strong> <span id="thrower-info-refresh">60 seconds</span></div>
<div><strong>Refresh Rate:</strong> <span id="thrower-info-refresh">300 seconds</span></div>
</div>
</div>
@ -71,7 +71,7 @@
<div class="input-group">
<label>Add New Relay:</label>
<div class="add-relay-form">
<input type="url" id="new-relay-url" placeholder="wss://relay.example.com">
<input type="url" id="new-relay-url" placeholder="wss://relay.example.com (or comma-separated list)">
<select id="new-relay-type">
<option value="">Both</option>
<option value="read">Read</option>
@ -151,7 +151,7 @@
</div>
<div class="input-group">
<label for="edit-refresh-rate">Refresh Rate (seconds):</label>
<input type="number" id="edit-refresh-rate" placeholder="60" value="60" min="10" max="3600">
<input type="number" id="edit-refresh-rate" placeholder="300" value="300" min="10" max="3600">
</div>
<div class="input-group">
<label for="edit-thrower-content">Additional Content (optional):</label>
@ -616,35 +616,95 @@
}
// Add new relay
// Add new relay (supports comma-separated list)
function addRelay() {
const url = document.getElementById('new-relay-url').value.trim();
const input = document.getElementById('new-relay-url').value.trim();
const type = document.getElementById('new-relay-type').value;
if (!url) {
if (!input) {
showStatus('relay-status', 'Please enter a relay URL', 'error');
return;
}
if (!url.startsWith('wss://') && !url.startsWith('ws://')) {
showStatus('relay-status', 'Relay URL must start with wss:// or ws://', 'error');
return;
}
// Check if input contains commas (multiple URLs)
const urls = input.includes(',') ?
input.split(',').map(url => url.trim()).filter(url => url.length > 0) :
[input];
// Check for duplicates
if (currentRelays.some(r => r.url === url)) {
showStatus('relay-status', 'Relay already exists', 'error');
return;
}
const results = {
added: [],
failed: [],
duplicates: []
};
currentRelays.push({ url, type });
// Process each URL
urls.forEach(url => {
// Validate URL format
if (!url.startsWith('wss://') && !url.startsWith('ws://')) {
results.failed.push({ url, reason: 'Must start with wss:// or ws://' });
return;
}
// Check for duplicates
if (currentRelays.some(r => r.url === url)) {
results.duplicates.push(url);
return;
}
// Add relay
currentRelays.push({ url, type, authStatus: 'unknown', lastTested: null });
results.added.push(url);
});
// Update display
displayRelayList();
// Clear form
document.getElementById('new-relay-url').value = '';
document.getElementById('new-relay-type').value = '';
showStatus('relay-status', 'Relay added (remember to save)', 'info');
// Provide detailed feedback
const messages = [];
if (results.added.length > 0) {
const typeText = type ? ` (${type === 'read' ? 'Read only' : type === 'write' ? 'Write only' : 'Both'})` : ' (Both)';
if (results.added.length === 1) {
messages.push(`✅ Added: ${results.added[0]}${typeText}`);
} else {
messages.push(`✅ Added ${results.added.length} relays${typeText}:`);
results.added.forEach(url => messages.push(` • ${url}`));
}
}
if (results.duplicates.length > 0) {
if (results.duplicates.length === 1) {
messages.push(`⚠️ Duplicate skipped: ${results.duplicates[0]}`);
} else {
messages.push(`⚠️ ${results.duplicates.length} duplicates skipped:`);
results.duplicates.forEach(url => messages.push(` • ${url}`));
}
}
if (results.failed.length > 0) {
if (results.failed.length === 1) {
messages.push(`❌ Failed: ${results.failed[0].url} (${results.failed[0].reason})`);
} else {
messages.push(`❌ ${results.failed.length} failed:`);
results.failed.forEach(item => messages.push(` • ${item.url} (${item.reason})`));
}
}
// Show comprehensive status
const statusMessage = messages.join('\n');
const statusType = results.added.length > 0 ? 'info' :
results.failed.length > 0 ? 'error' : 'info';
// Add reminder to save if any were added
const finalMessage = results.added.length > 0 ?
statusMessage + '\n\n💾 Remember to save your relay configuration!' :
statusMessage;
showStatus('relay-status', finalMessage, statusType);
}
// Remove relay
@ -1067,7 +1127,7 @@
version: '1.0.0',
privacyPolicy: '',
termsOfService: '',
refreshRate: 60,
refreshRate: 300,
content: event.content || ''
};
@ -1084,7 +1144,7 @@
else if (tag[0] === 'version') currentThrowerInfo.version = tag[1] || '1.0.0';
else if (tag[0] === 'privacy_policy') currentThrowerInfo.privacyPolicy = tag[1] || '';
else if (tag[0] === 'terms_of_service') currentThrowerInfo.termsOfService = tag[1] || '';
else if (tag[0] === 'refresh_rate') currentThrowerInfo.refreshRate = parseInt(tag[1]) || 60;
else if (tag[0] === 'refresh_rate') currentThrowerInfo.refreshRate = parseInt(tag[1]) || 300;
});
lastThrowerInfoPublish = event.created_at;
@ -1103,7 +1163,7 @@
version: '1.0.0',
privacyPolicy: '',
termsOfService: '',
refreshRate: 60,
refreshRate: 300,
content: ''
};
displayThrowerInfo(currentThrowerInfo);
@ -1148,7 +1208,7 @@
document.getElementById('edit-version').value = currentThrowerInfo.version || '1.0.0';
document.getElementById('edit-privacy-policy').value = currentThrowerInfo.privacyPolicy || '';
document.getElementById('edit-terms-service').value = currentThrowerInfo.termsOfService || '';
document.getElementById('edit-refresh-rate').value = currentThrowerInfo.refreshRate || 60;
document.getElementById('edit-refresh-rate').value = currentThrowerInfo.refreshRate || 300;
document.getElementById('edit-thrower-content').value = currentThrowerInfo.content || '';
}
@ -1172,7 +1232,7 @@
const version = document.getElementById('edit-version').value.trim();
const privacyPolicy = document.getElementById('edit-privacy-policy').value.trim();
const termsOfService = document.getElementById('edit-terms-service').value.trim();
const refreshRate = parseInt(document.getElementById('edit-refresh-rate').value) || 60;
const refreshRate = parseInt(document.getElementById('edit-refresh-rate').value) || 300;
const content = document.getElementById('edit-thrower-content').value.trim();
try {