this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

sync

+112 -125
+112 -125
index.html
··· 53 53 justify-content: space-between; 54 54 align-items: center; 55 55 width: 100%; 56 - max-width: 1000px; 56 + max-width: 1200px; 57 57 margin: 0 auto; 58 58 } 59 59 ··· 85 85 86 86 .content { 87 87 width: 100%; 88 - max-width: 850px; 88 + max-width: 1200px; 89 89 } 90 90 91 91 .feed-item { 92 92 background-color: var(--card-bg); 93 93 border: 1px solid var(--border-color); 94 - border-radius: 6px; 95 - margin-bottom: 15px; 94 + border-radius: 4px; 95 + margin-bottom: 8px; 96 96 overflow: hidden; 97 - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); 98 - transition: transform 0.2s ease, box-shadow 0.2s ease; 97 + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1); 98 + transition: background-color 0.2s ease; 99 99 } 100 100 101 101 .feed-item:hover { 102 - transform: translateY(-2px); 103 - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15); 102 + background-color: #202930; 104 103 } 105 104 106 - .feed-item-header { 107 - padding: 10px 15px; 108 - border-bottom: 1px solid var(--border-color); 109 - background-color: rgba(77, 250, 123, 0.05); 105 + .feed-item-row { 106 + display: flex; 107 + align-items: center; 108 + padding: 8px 15px; 109 + width: 100%; 110 + overflow: hidden; 111 + } 112 + 113 + .feed-item-date { 114 + font-family: 'JetBrains Mono', monospace; 115 + font-size: 0.75rem; 116 + color: var(--text-muted); 117 + min-width: 80px; 118 + margin-right: 10px; 119 + } 120 + 121 + .feed-item-author { 122 + font-family: 'JetBrains Mono', monospace; 123 + color: var(--accent-alt); 124 + font-size: 0.85rem; 125 + min-width: 70px; 126 + margin-right: 15px; 127 + white-space: nowrap; 110 128 } 111 129 112 130 .feed-item-title { 113 - font-size: 1.15rem; 114 - font-weight: 500; 115 - margin-bottom: 3px; 116 - line-height: 1.3; 131 + flex: 1; 132 + font-size: 0.95rem; 133 + font-weight: 400; 134 + white-space: nowrap; 135 + overflow: hidden; 136 + text-overflow: ellipsis; 137 + margin-right: 15px; 117 138 } 118 139 119 140 .feed-item-title a { ··· 126 147 color: var(--accent-color); 127 148 } 128 149 129 - .feed-item-meta { 130 - display: flex; 131 - justify-content: space-between; 132 - align-items: center; 133 - font-size: 0.8rem; 134 - color: var(--text-muted); 135 - } 136 - 137 - .feed-item-source { 138 - font-family: 'JetBrains Mono', monospace; 139 - color: var(--accent-alt); 140 - } 141 - 142 150 .feed-item-preview { 143 - padding: 10px 15px; 144 - line-height: 1.5; 145 - border-bottom: 1px solid var(--border-color); 151 + flex: 2; 146 152 white-space: nowrap; 147 153 overflow: hidden; 148 154 text-overflow: ellipsis; 155 + color: var(--text-muted); 156 + font-size: 0.85rem; 157 + margin-right: 15px; 158 + } 159 + 160 + .feed-item-actions { 161 + display: flex; 162 + align-items: center; 163 + gap: 10px; 164 + margin-left: auto; 149 165 } 150 166 151 167 .feed-item-content { 152 168 padding: 15px; 153 169 line-height: 1.6; 154 170 display: none; 171 + border-top: 1px solid var(--border-color); 172 + background-color: #1d252c; 155 173 } 156 174 157 175 .feed-item-content img { ··· 182 200 color: var(--text-muted); 183 201 } 184 202 185 - .feed-item-actions { 186 - padding: 6px 15px; 187 - display: flex; 188 - justify-content: space-between; 189 - align-items: center; 190 - } 191 - 192 - .read-more { 203 + .read-more-btn { 193 204 background-color: transparent; 194 - border: 1px solid var(--accent-color); 205 + border: none; 195 206 color: var(--accent-color); 196 - padding: 5px 10px; 197 - border-radius: 4px; 198 207 cursor: pointer; 199 208 font-family: 'JetBrains Mono', monospace; 200 209 font-size: 0.8rem; 210 + padding: 2px 5px; 211 + border-radius: 3px; 201 212 transition: all 0.2s ease; 202 213 display: inline-flex; 203 214 align-items: center; 204 215 } 205 216 206 - .read-more:hover { 207 - background-color: var(--accent-color); 208 - color: var(--bg-color); 217 + .read-more-btn:hover { 218 + background-color: rgba(77, 250, 123, 0.1); 219 + } 220 + 221 + .external-link { 222 + color: var(--text-muted); 223 + font-size: 0.8rem; 224 + display: inline-flex; 225 + align-items: center; 226 + text-decoration: none; 209 227 } 210 228 211 - .read-more::after { 212 - content: '⌄'; 213 - margin-left: 5px; 214 - font-size: 1.2em; 215 - line-height: 0.8; 216 - transition: transform 0.2s ease; 229 + .external-link:hover { 230 + color: var(--accent-alt); 217 231 } 218 232 219 - .read-more.active::after { 220 - transform: rotate(180deg); 233 + .icon { 234 + font-size: 0.9rem; 235 + margin-left: 3px; 221 236 } 222 237 223 238 #loading { ··· 256 271 font-family: 'JetBrains Mono', monospace; 257 272 } 258 273 259 - .timestamp { 260 - font-family: 'JetBrains Mono', monospace; 261 - font-size: 0.75rem; 262 - } 263 - 264 - .external-link { 265 - display: inline-flex; 266 - align-items: center; 267 - color: var(--text-muted); 268 - text-decoration: none; 269 - font-size: 0.8rem; 270 - transition: color 0.2s ease; 271 - } 272 - 273 - .external-link:hover { 274 - color: var(--accent-alt); 275 - } 276 - 277 - .external-link::after { 278 - content: '↗'; 279 - margin-left: 3px; 280 - font-size: 0.9em; 274 + @media (max-width: 900px) { 275 + .feed-item-preview { 276 + display: none; 277 + } 281 278 } 282 279 283 280 @media (max-width: 600px) { 284 - .feed-item-title { 285 - font-size: 1rem; 281 + .feed-item-author { 282 + min-width: 50px; 283 + margin-right: 10px; 286 284 } 287 285 288 - .feed-item-header, .feed-item-preview, .feed-item-content, .feed-item-actions { 289 - padding: 8px 12px; 290 - } 291 - 292 - .read-more { 293 - padding: 4px 8px; 294 - font-size: 0.75rem; 286 + .feed-item-date { 287 + min-width: 60px; 288 + margin-right: 10px; 295 289 } 296 290 } 297 291 </style> ··· 323 317 const entryCountElement = document.getElementById('entry-count'); 324 318 const sourceCountElement = document.getElementById('source-count'); 325 319 326 - // Function to format date 320 + // Function to format date (only date, no time) 327 321 function formatDate(dateString) { 328 322 const date = new Date(dateString); 329 - return date.toLocaleString('en-US', { 323 + return date.toLocaleDateString('en-US', { 330 324 year: 'numeric', 331 325 month: 'short', 332 - day: 'numeric', 333 - hour: '2-digit', 334 - minute: '2-digit' 326 + day: 'numeric' 335 327 }); 336 328 } 337 329 ··· 356 348 } else if (firstNewline !== -1) { 357 349 endIndex = firstNewline; 358 350 } else { 359 - // If no period or newline, take first 100 chars 360 - endIndex = Math.min(text.length, 100); 351 + // If no period or newline, take first 80 chars 352 + endIndex = Math.min(text.length, 80); 361 353 } 362 354 363 355 return text.substring(0, endIndex + 1).trim(); 364 356 } 365 357 366 - // Function to attach toggle handlers 367 - function setupToggleHandlers() { 368 - document.querySelectorAll('.read-more').forEach(button => { 369 - button.addEventListener('click', function() { 370 - const article = this.closest('article'); 371 - const content = article.querySelector('.feed-item-content'); 372 - 373 - if (content.style.display === 'block') { 374 - content.style.display = 'none'; 375 - this.textContent = 'Read More'; 376 - this.classList.remove('active'); 377 - } else { 378 - content.style.display = 'block'; 379 - this.textContent = 'Show Less'; 380 - this.classList.add('active'); 381 - } 382 - }); 383 - }); 358 + // Function to toggle content visibility 359 + function toggleContent(articleId) { 360 + const article = document.getElementById(articleId); 361 + const content = article.querySelector('.feed-item-content'); 362 + const button = article.querySelector('.read-more-btn'); 363 + 364 + if (content.style.display === 'block') { 365 + content.style.display = 'none'; 366 + button.innerHTML = 'More <span class="icon">↓</span>'; 367 + } else { 368 + content.style.display = 'block'; 369 + button.innerHTML = 'Less <span class="icon">↑</span>'; 370 + } 384 371 } 385 372 386 373 try { ··· 406 393 407 394 for (let i = 0; i < entries.length; i++) { 408 395 const entry = entries[i]; 396 + const articleId = `article-${i}`; 409 397 410 398 // Extract entry data 411 399 const title = entry.getElementsByTagName('title')[0]?.textContent || 'No Title'; ··· 415 403 const contentType = contentElement?.getAttribute('type') || 'text'; 416 404 const published = entry.getElementsByTagName('published')[0]?.textContent || 417 405 entry.getElementsByTagName('updated')[0]?.textContent || ''; 406 + const author = entry.getElementsByTagName('author')[0]?.getElementsByTagName('name')[0]?.textContent || 'Unknown'; 418 407 const categories = entry.getElementsByTagName('category'); 419 408 420 409 // Extract source from category (we're using category to store source name) ··· 441 430 // Get the first line for preview 442 431 const firstLine = getFirstLine(contentHtml); 443 432 444 - // Format the entry HTML 433 + // Format the entry HTML - single line layout 445 434 entriesHTML += ` 446 - <article class="feed-item"> 447 - <div class="feed-item-header"> 448 - <h2 class="feed-item-title"><a href="${link}" target="_blank">${title}</a></h2> 449 - <div class="feed-item-meta"> 450 - <span class="feed-item-source">${source}</span> 451 - <span class="timestamp">${formatDate(published)}</span> 435 + <article id="${articleId}" class="feed-item"> 436 + <div class="feed-item-row"> 437 + <div class="feed-item-date">${formatDate(published)}</div> 438 + <div class="feed-item-author">${author}</div> 439 + <div class="feed-item-title"><a href="${link}" target="_blank">${title}</a></div> 440 + <div class="feed-item-preview">${firstLine}</div> 441 + <div class="feed-item-actions"> 442 + <button class="read-more-btn" onclick="toggleContent('${articleId}')">More <span class="icon">↓</span></button> 443 + <a href="${link}" target="_blank" class="external-link">Link <span class="icon">↗</span></a> 452 444 </div> 453 445 </div> 454 - <div class="feed-item-preview">${firstLine}</div> 455 - <div class="feed-item-actions"> 456 - <button class="read-more">Read More</button> 457 - <a href="${link}" target="_blank" class="external-link">View Original</a> 458 - </div> 459 446 <div class="feed-item-content">${contentHtml}</div> 460 447 </article> 461 448 `; ··· 464 451 // Update sources count 465 452 sourceCountElement.textContent = sources.size; 466 453 454 + // Add the toggleContent function to the global scope 455 + window.toggleContent = toggleContent; 456 + 467 457 // Hide loading, show content 468 458 loadingContainer.style.display = 'none'; 469 459 feedItemsContainer.innerHTML = entriesHTML; 470 - 471 - // Setup toggle handlers 472 - setupToggleHandlers(); 473 460 474 461 } catch (error) { 475 462 console.error('Error loading feed:', error);