Spaces:
Running
Running
File size: 7,745 Bytes
e82d5c4 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 | document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('searchForm');
const resultsContainer = document.getElementById('resultsContainer');
const resultsDiv = document.getElementById('results');
const loadingDiv = document.getElementById('loading');
const copyAllBtn = document.getElementById('copyAllBtn');
// Mock data - in a real implementation, this would call a Bluesky API
const mockPosts = [
{
author: {
handle: "nba.bsky.social",
displayName: "NBA Official",
avatar: "https://static.photos/sport/200x200/1"
},
text: "Breaking: The Lakers have just signed a new point guard to bolster their roster for the playoffs! ππ₯ #LakeShow",
reposts: 42,
timestamp: "2 hours ago",
url: "https://bsky.app/profile/nba.bsky.social/post/123"
},
{
author: {
handle: "wojespn.bsky.social",
displayName: "Adrian Wojnarowski",
avatar: "https://static.photos/people/200x200/2"
},
text: "Sources: LeBron James expected to return from injury for the first round of playoffs. Big boost for LA.",
reposts: 89,
timestamp: "1 hour ago",
url: "https://bsky.app/profile/wojespn.bsky.social/post/456"
},
{
author: {
handle: "shams.bsky.social",
displayName: "Shams Charania",
avatar: "https://static.photos/people/200x200/3"
},
text: "The Phoenix Suns are finalizing a deal with veteran center DeAndre Jordan, sources tell @TheAthletic.",
reposts: 56,
timestamp: "2.5 hours ago",
url: "https://bsky.app/profile/shams.bsky.social/post/789"
}
];
form.addEventListener('submit', async (e) => {
e.preventDefault();
const topic = document.getElementById('topic').value.trim();
const hours = document.getElementById('hours').value;
const minReposts = parseInt(document.getElementById('minReposts').value);
if (!topic) {
alert('Please enter an NBA topic to search for');
return;
}
// Show loading
resultsContainer.classList.remove('hidden');
resultsDiv.innerHTML = '';
loadingDiv.classList.remove('hidden');
// Simulate API delay
setTimeout(() => {
loadingDiv.classList.add('hidden');
// Filter mock data based on reposts (in a real app, this would be done server-side)
const filteredPosts = mockPosts.filter(post => post.reposts >= minReposts);
if (filteredPosts.length === 0) {
resultsDiv.innerHTML = `
<div class="bg-yellow-50 border-l-4 border-yellow-400 p-4">
<div class="flex">
<div class="flex-shrink-0">
<i data-feather="alert-triangle" class="h-5 w-5 text-yellow-400"></i>
</div>
<div class="ml-3">
<p class="text-sm text-yellow-700">
No posts found matching your criteria. Try widening your search parameters.
</p>
</div>
</div>
</div>
`;
feather.replace();
return;
}
// Display results
filteredPosts.forEach((post, index) => {
const postElement = document.createElement('div');
postElement.className = 'bg-gray-50 rounded-lg p-4 border border-gray-200';
postElement.innerHTML = `
<div class="flex justify-between items-start mb-2">
<div class="flex items-center space-x-3">
<img src="${post.author.avatar}" alt="${post.author.displayName}" class="w-10 h-10 rounded-full object-cover">
<div>
<p class="font-medium text-gray-900">${post.author.displayName}</p>
<p class="text-sm text-gray-500">@${post.author.handle} Β· ${post.timestamp}</p>
</div>
</div>
<div class="flex items-center space-x-2">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-blue-100 text-blue-800">
<i data-feather="repeat" class="w-3 h-3 mr-1"></i>
${post.reposts}
</span>
<button class="copy-btn text-blue-600 hover:text-blue-800" data-content="${escapeHtml(post.text)}">
<i data-feather="copy" class="w-4 h-4"></i>
</button>
</div>
</div>
<p class="text-gray-800 whitespace-pre-line mt-2">${post.text}</p>
<div class="mt-3 pt-2 border-t border-gray-200 flex justify-end">
<a href="${post.url}" target="_blank" class="text-sm text-blue-600 hover:text-blue-800 flex items-center">
View on Bluesky <i data-feather="external-link" class="w-3 h-3 ml-1"></i>
</a>
</div>
`;
resultsDiv.appendChild(postElement);
});
feather.replace();
}, 1500); // Simulate network delay
});
// Copy all button
copyAllBtn.addEventListener('click', () => {
const posts = [...document.querySelectorAll('.copy-btn')].map(btn => btn.getAttribute('data-content'));
if (posts.length === 0) return;
const textToCopy = posts.join('\n\n---\n\n');
navigator.clipboard.writeText(textToCopy).then(() => {
showNotification('All posts copied to clipboard!', copyAllBtn);
});
});
// Event delegation for copy buttons
resultsDiv.addEventListener('click', (e) => {
if (e.target.closest('.copy-btn')) {
const btn = e.target.closest('.copy-btn');
const text = btn.getAttribute('data-content');
navigator.clipboard.writeText(text).then(() => {
showNotification('Copied to clipboard!', btn);
});
}
});
// Helper function to show notification
function showNotification(message, element) {
const notification = document.createElement('div');
notification.className = 'copied-notification absolute bg-green-600 text-white text-sm py-1 px-3 rounded-md shadow-lg';
notification.textContent = message;
const rect = element.getBoundingClientRect();
notification.style.left = `${rect.left + window.scrollX}px`;
notification.style.top = `${rect.top + window.scrollY - 30}px`;
document.body.appendChild(notification);
setTimeout(() => {
notification.remove();
}, 2000);
}
// Helper function to escape HTML
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
}); |