···
214
+
align-items: center;
215
+
margin-right: 10px;
font-family: 'JetBrains Mono', monospace;
···
233
-
white-space: nowrap;
235
-
text-overflow: ellipsis;
236
-
margin-right: 15px;
238
+
margin-bottom: 3px;
···
color: var(--accent-color);
249
-
.feed-item-preview {
251
-
white-space: nowrap;
251
+
.feed-item-content-wrapper {
253
-
text-overflow: ellipsis;
256
+
.feed-item-preview {
color: var(--text-muted);
256
-
margin-right: 15px;
260
+
text-overflow: ellipsis;
261
+
white-space: nowrap;
262
+
transition: all 0.3s ease;
···
transition: all 0.3s ease;
272
-
.feed-item.content-open {
border-left-color: var(--accent-color);
background-color: rgba(77, 250, 123, 0.03);
···
297
-
.feed-item-external-links {
302
+
.feed-item:hover .feed-item-preview {
303
+
white-space: normal;
309
+
.preview-references {
300
-
border-top: 1px dashed var(--border-color);
305
-
background-color: rgba(77, 250, 123, 0.02);
317
+
border-top: 1px dotted var(--border-color);
320
+
.external-link-item[title*="github.com"] {
321
+
background-color: rgba(77, 180, 128, 0.08);
322
+
color: var(--accent-alt);
325
+
.feed-item:hover .preview-links,
326
+
.feed-item:hover .preview-references {
···
item.addEventListener('mouseenter', () => {
// Close all sections in previously hovered item
if (currentHoveredItem && currentHoveredItem !== item) {
532
-
// Don't close manually opened content (with the button)
533
-
if (!currentHoveredItem.classList.contains('content-open')) {
534
-
const prevContent = currentHoveredItem.querySelector('.feed-item-content');
536
-
prevContent.style.display = 'none';
538
-
// Update button state
539
-
const prevButton = currentHoveredItem.querySelector('.read-more-btn');
541
-
prevButton.textContent = '📄';
542
-
prevButton.title = 'Show content';
554
+
// Remove this section - we no longer show the full content
547
-
// Don't close manually opened external links
548
-
if (!currentHoveredItem.classList.contains('links-open')) {
549
-
const prevLinks = currentHoveredItem.querySelector('.feed-item-external-links');
551
-
prevLinks.style.display = 'none';
553
-
// Update button state
554
-
const prevButton = currentHoveredItem.querySelector('.external-links-toggle');
556
-
prevButton.textContent = '🌐';
557
-
prevButton.title = 'Show external links';
556
+
// No need to close preview content now since it's controlled by CSS hover
562
-
// Don't close manually opened references
563
-
if (!currentHoveredItem.classList.contains('refs-to-open')) {
564
-
const prevRefsTo = currentHoveredItem.querySelector('.references-to');
566
-
prevRefsTo.style.display = 'none';
568
-
// Update button state
569
-
const prevButton = currentHoveredItem.querySelector('.references-to-toggle');
571
-
prevButton.textContent = '➡️';
572
-
prevButton.title = 'Show references to other posts';
577
-
if (!currentHoveredItem.classList.contains('refs-by-open')) {
578
-
const prevRefsBy = currentHoveredItem.querySelector('.references-by');
580
-
prevRefsBy.style.display = 'none';
582
-
// Update button state
583
-
const prevButton = currentHoveredItem.querySelector('.references-by-toggle');
585
-
prevButton.textContent = '⬅️';
586
-
prevButton.title = 'Show posts referencing this one';
558
+
// References are now controlled by CSS hover
// Set this as current hovered item
currentHoveredItem = item;
595
-
// Show content on hover (unless manually closed)
596
-
const content = item.querySelector('.feed-item-content');
598
-
content.style.display = 'block';
600
-
// Update button state
601
-
const button = item.querySelector('.read-more-btn');
603
-
button.textContent = '📕';
604
-
button.title = 'Hide content';
564
+
// Remove this section - we no longer show the full content
608
-
// Show external links if available
609
-
const externalLinks = item.querySelector('.feed-item-external-links');
610
-
if (externalLinks) {
611
-
externalLinks.style.display = 'flex';
613
-
// Update button state
614
-
const externalButton = item.querySelector('.external-links-toggle');
615
-
if (externalButton) {
616
-
externalButton.textContent = '🌐';
617
-
externalButton.title = 'Hide external links';
566
+
// Preview content is shown automatically by CSS on hover
···
638
-
// Function to get first line of text
639
-
function getFirstLine(html) {
585
+
// Function to get a paragraph preview of text
586
+
function getTextPreview(html, maxLength = 300) {
// Create a temporary div to parse HTML
const tempDiv = document.createElement('div');
tempDiv.innerHTML = html;
644
-
// Extract text content
591
+
// Extract text content and remove extra whitespace
const text = tempDiv.textContent || '';
593
+
const cleanText = text.replace(/\s+/g, ' ').trim();
647
-
// Get first line (up to first period or newline, whichever comes first)
648
-
const firstPeriod = text.indexOf('.');
649
-
const firstNewline = text.indexOf('\n');
652
-
if (firstPeriod !== -1 && firstNewline !== -1) {
653
-
endIndex = Math.min(firstPeriod, firstNewline);
654
-
} else if (firstPeriod !== -1) {
655
-
endIndex = firstPeriod;
656
-
} else if (firstNewline !== -1) {
657
-
endIndex = firstNewline;
659
-
// If no period or newline, take first 80 chars
660
-
endIndex = Math.min(text.length, 80);
595
+
// Get a reasonable preview length (about a paragraph)
596
+
if (cleanText.length <= maxLength) {
663
-
return text.substring(0, endIndex + 1).trim();
666
-
// Function to toggle content visibility
667
-
function toggleContent(articleId) {
668
-
const article = document.getElementById(articleId);
669
-
const content = article.querySelector('.feed-item-content');
670
-
const button = article.querySelector('.read-more-btn');
600
+
// Try to find a good break point
601
+
let endIndex = maxLength;
672
-
if (content.style.display === 'block') {
673
-
content.style.display = 'none';
674
-
button.textContent = '📄';
675
-
button.title = 'Show content';
677
-
// Remove forced hover state
678
-
article.classList.remove('content-open');
603
+
// Look for the last sentence break within our limit
604
+
const lastPeriod = cleanText.lastIndexOf('.', maxLength);
605
+
if (lastPeriod > maxLength / 2) {
606
+
endIndex = lastPeriod + 1;
680
-
content.style.display = 'block';
681
-
button.textContent = '📕';
682
-
button.title = 'Hide content';
684
-
// Add forced hover state
685
-
article.classList.add('content-open');
689
-
// Function to toggle external links visibility
690
-
function toggleExternalLinks(articleId) {
691
-
const article = document.getElementById(articleId);
692
-
const linksContainer = article.querySelector('.feed-item-external-links');
693
-
const button = article.querySelector('.external-links-toggle');
695
-
if (!linksContainer || !button) {
696
-
console.error(`External links container or button for ${articleId} not found`);
608
+
// Look for the last space to avoid cutting words
609
+
const lastSpace = cleanText.lastIndexOf(' ', maxLength);
610
+
if (lastSpace > 0) {
611
+
endIndex = lastSpace;
700
-
if (linksContainer.style.display === 'flex') {
701
-
linksContainer.style.display = 'none';
702
-
button.textContent = '🌐';
703
-
button.title = 'Show external links';
704
-
article.classList.remove('links-open');
706
-
linksContainer.style.display = 'flex';
707
-
button.textContent = '🌐';
708
-
button.title = 'Hide external links';
709
-
article.classList.add('links-open');
615
+
return cleanText.substring(0, endIndex) + '...';
713
-
// Function to toggle references visibility
714
-
function toggleReferences(articleId, type) {
715
-
const article = document.getElementById(articleId);
716
-
const referencesContainer = article.querySelector(`.references-${type}`);
717
-
const button = article.querySelector(`.references-${type}-toggle`);
618
+
// Function to get first line for preview in post listing
619
+
function getFirstLine(html) {
620
+
// Create a temporary div to parse HTML
621
+
const tempDiv = document.createElement('div');
622
+
tempDiv.innerHTML = html;
719
-
if (!referencesContainer || !button) {
720
-
console.error(`References container or button for ${articleId} not found`);
624
+
// Extract text content
625
+
const text = tempDiv.textContent || '';
626
+
const cleanText = text.replace(/\s+/g, ' ').trim();
724
-
if (referencesContainer.style.display === 'block') {
725
-
referencesContainer.style.display = 'none';
726
-
button.textContent = type === 'to' ? '➡️' : '⬅️';
727
-
button.title = type === 'to' ? 'Show references to other posts' : 'Show posts referencing this one';
728
-
article.classList.remove(`refs-${type}-open`);
628
+
// Get first sentence, or about 80 chars
629
+
const firstPeriod = cleanText.indexOf('.');
632
+
if (firstPeriod !== -1 && firstPeriod < 100) {
633
+
endIndex = firstPeriod;
730
-
referencesContainer.style.display = 'block';
731
-
button.textContent = type === 'to' ? '➡️' : '⬅️';
732
-
button.title = type === 'to' ? 'Hide references to other posts' : 'Hide posts referencing this one';
733
-
article.classList.add(`refs-${type}-open`);
635
+
// If no suitable period, take first 80 chars
636
+
endIndex = Math.min(cleanText.length, 80);
637
+
// Look for the last space to avoid cutting words
638
+
const lastSpace = cleanText.lastIndexOf(' ', endIndex);
639
+
if (lastSpace > endIndex / 2) {
640
+
endIndex = lastSpace;
644
+
return cleanText.substring(0, endIndex + 1).trim();
647
+
// Function removed - we no longer toggle full content
649
+
// Removed the external links toggle function as it's no longer needed
651
+
// Reference toggle function removed - references are now shown with CSS on hover
// Fetch the Atom feed and threads data in parallel
···
805
-
// Get the first line for preview
721
+
// Get the first line and paragraph preview
const firstLine = getFirstLine(contentHtml);
723
+
const textPreview = getTextPreview(contentHtml);
···
···
<article id="${entry.articleId}" class="feed-item" ${dateAttr}>
<div class="feed-item-row">
847
+
<div class="feed-item-left">
848
+
<a href="${entry.link}" target="_blank" class="external-link" title="Open original post">🔗</a>
<div class="feed-item-date">${formatDate(entry.published)}</div>
<div class="feed-item-author">${entry.author}</div>
931
-
<div class="feed-item-title"><a href="${entry.link}" target="_blank">${entry.title}</a></div>
932
-
<div class="feed-item-preview">${entry.firstLine}</div>
933
-
<div class="feed-item-actions">
934
-
<button class="read-more-btn" onclick="toggleContent('${entry.articleId}')" title="Show/hide content">📄</button>
935
-
<a href="${entry.link}" target="_blank" class="external-link" title="Open original post">🔗</a>
936
-
${entry.externalLinks && entry.externalLinks.length > 0 ?
937
-
`<button class="external-links-toggle" onclick="toggleExternalLinks('${entry.articleId}')" title="Show/hide external links">🌐</button>` : ''}
938
-
${entry.referencesTo && entry.referencesTo.length > 0 ?
939
-
`<button class="references-to-toggle references-toggle" onclick="toggleReferences('${entry.articleId}', 'to')" title="Show/hide references to other posts">➡️</button>` : ''}
940
-
${entry.referencedBy && entry.referencedBy.length > 0 ?
941
-
`<button class="references-by-toggle references-toggle" onclick="toggleReferences('${entry.articleId}', 'by')" title="Show/hide posts referencing this one">⬅️</button>` : ''}
944
-
<div class="feed-item-content">${entry.contentHtml}</div>
946
-
${entry.externalLinks && entry.externalLinks.length > 0 ? `
947
-
<div class="feed-item-external-links">
948
-
<span class="external-links-label">External links:</span>
949
-
${entry.externalLinks.map(link => `<a href="${link.url}" target="_blank" class="external-link-item" title="${link.url}">${new URL(link.url).hostname}</a>`).join(', ')}
953
-
${entry.referencesTo && entry.referencesTo.length > 0 ? `
954
-
<div class="references-container references-to" style="display: none;">
955
-
<div class="reference-header">References to other posts:</div>
956
-
${entry.referencesTo.map(ref => `
957
-
<div class="reference-item">
958
-
<span class="reference-indicator">→</span>
959
-
<a href="${ref.link}" target="_blank" class="reference-link">${ref.title}</a>
960
-
<span class="reference-author"> by ${ref.author}</span>
852
+
<div class="feed-item-content-wrapper">
853
+
<div class="feed-item-title"><a href="${entry.link}" target="_blank">${entry.title}</a></div>
854
+
<div class="feed-item-preview">${entry.textPreview}</div>
856
+
${entry.externalLinks && entry.externalLinks.length > 0 ? `
857
+
<div class="preview-links">
858
+
<span class="external-links-label">External links:</span>
859
+
${entry.externalLinks.map(link => {
860
+
const url = new URL(link.url);
861
+
let displayText = url.hostname.replace('www.', '');
863
+
// Special handling for GitHub links
864
+
if (url.hostname === 'github.com' || url.hostname === 'gist.github.com') {
865
+
// Extract the parts from pathname (remove leading slash)
866
+
const parts = url.pathname.substring(1).split('/').filter(part => part);
867
+
if (parts.length >= 2) {
868
+
displayText = `github:${parts[0]}/${parts[1]}`;
872
+
// Special handling for Wikipedia links
873
+
if (url.hostname === 'en.wikipedia.org' || url.hostname === 'wikipedia.org' || url.hostname.endsWith('.wikipedia.org')) {
874
+
const titlePart = url.pathname.split('/').pop();
876
+
const title = decodeURIComponent(titlePart).replace(/_/g, ' ');
877
+
displayText = `wikipedia:${title}`;
881
+
return `<a href="${link.url}" target="_blank" class="external-link-item" title="${link.url}">${displayText}</a>`;
886
+
${entry.referencesTo && entry.referencesTo.length > 0 ? `
887
+
<div class="preview-references">
888
+
<span class="external-links-label">References:</span>
889
+
${entry.referencesTo.map(ref => `
890
+
<a href="${ref.link}" target="_blank" class="external-link-item" title="${ref.title} by ${ref.author}">→ ${ref.title}</a>
966
-
${entry.referencedBy && entry.referencedBy.length > 0 ? `
967
-
<div class="references-container references-by" style="display: none;">
968
-
<div class="reference-header">Posts referencing this one:</div>
969
-
${entry.referencedBy.map(ref => `
970
-
<div class="reference-item">
971
-
<span class="reference-indicator">←</span>
972
-
<a href="${ref.link}" target="_blank" class="reference-link">${ref.title}</a>
973
-
<span class="reference-author"> by ${ref.author}</span>
895
+
${entry.referencedBy && entry.referencedBy.length > 0 ? `
896
+
<div class="preview-references">
897
+
<span class="external-links-label">Referenced by:</span>
898
+
${entry.referencedBy.map(ref => `
899
+
<a href="${ref.link}" target="_blank" class="external-link-item" title="${ref.title} by ${ref.author}">← ${ref.title}</a>
···
sourceCountElement.textContent = sources.size;
989
-
// Add the toggle functions to the global scope
990
-
window.toggleContent = toggleContent;
991
-
window.toggleExternalLinks = toggleExternalLinks;
992
-
window.toggleReferences = toggleReferences;
916
+
// No toggle functions needed anymore
// Build timeline sidebar
const timelineSidebar = document.getElementById('timeline-sidebar');