Atom feed for our EEG site

Compare changes

Choose any two refs to compare.

Changed files
+353 -4
+353 -4
index.html
···
font-size: 0.75rem;
margin-top: 3px;
}
+
+
/* Styles for filter container */
+
.filter-container {
+
display: flex;
+
align-items: center;
+
margin-bottom: 10px;
+
padding: 5px 10px;
+
background-color: var(--card-bg);
+
border: 1px solid var(--border-color);
+
border-radius: 4px;
+
align-self: flex-end;
+
width: auto;
+
margin-left: auto;
+
}
+
+
.filter-title {
+
font-family: 'JetBrains Mono', monospace;
+
color: var(--accent-color);
+
font-size: 0.8rem;
+
margin-right: 10px;
+
}
+
+
.filter-options {
+
display: flex;
+
gap: 10px;
+
}
+
+
.filter-option {
+
position: relative;
+
display: flex;
+
align-items: center;
+
cursor: pointer;
+
user-select: none;
+
}
+
+
.filter-checkbox {
+
position: absolute;
+
opacity: 0;
+
height: 0;
+
width: 0;
+
}
+
+
.checkbox-custom {
+
position: relative;
+
display: inline-block;
+
width: 14px;
+
height: 14px;
+
background-color: rgba(77, 250, 123, 0.05);
+
border: 1px solid var(--accent-alt);
+
border-radius: 3px;
+
margin-right: 6px;
+
transition: all 0.2s ease;
+
}
+
+
.filter-checkbox:checked + .checkbox-custom::after {
+
content: '';
+
position: absolute;
+
top: 1px;
+
left: 4px;
+
width: 4px;
+
height: 7px;
+
border: solid var(--accent-color);
+
border-width: 0 2px 2px 0;
+
transform: rotate(45deg);
+
}
+
+
.filter-checkbox:checked + .checkbox-custom {
+
background-color: rgba(77, 250, 123, 0.15);
+
border-color: var(--accent-color);
+
}
+
+
.filter-label {
+
font-size: 0.8rem;
+
color: var(--text-color);
+
}
+
+
.filter-option:hover .checkbox-custom {
+
background-color: rgba(77, 250, 123, 0.1);
+
border-color: var(--accent-color);
+
}
+
+
.links-header {
+
display: flex;
+
justify-content: flex-end;
+
margin-bottom: 10px;
+
width: 100%;
+
}
@media (max-width: 600px) {
.feed-item-author {
···
.content {
padding-left: 50px; /* Match the sidebar width on small screens */
+
+
/* Hide green dot indicators on mobile to prevent text overlap */
+
.timeline-year::after,
+
.timeline-month::after {
+
display: none;
+
}
+
+
/* Also hide the connecting line on mobile */
+
.timeline-year::before,
+
.timeline-month::before {
+
display: none;
+
}
</style>
</head>
···
<p class="loading-text">Growing Content...</p>
</div>
<div id="feed-items" class="tab-content active feed-container" data-tab="posts"></div>
-
<div id="link-items" class="tab-content feed-container" data-tab="links"></div>
+
<div class="tab-content" data-tab="links">
+
<div class="links-header">
+
<div class="filter-container">
+
<div class="filter-title">Filter:</div>
+
<div class="filter-options">
+
<label class="filter-option">
+
<input type="checkbox" id="filter-papers" class="filter-checkbox" data-filter="academic">
+
<span class="checkbox-custom"></span>
+
<span class="filter-label">Papers</span>
+
</label>
+
<label class="filter-option">
+
<input type="checkbox" id="filter-videos" class="filter-checkbox" data-filter="youtube">
+
<span class="checkbox-custom"></span>
+
<span class="filter-label">Videos</span>
+
</label>
+
</div>
+
</div>
+
</div>
+
<div id="link-items" class="feed-container"></div>
+
</div>
<div id="people-items" class="tab-content" data-tab="people">
<h2 class="people-header">EEG Sources</h2>
<div class="people-container"></div>
···
+
// Academic paper detection - PDF files and academic domains
+
else if (
+
link.url.toLowerCase().endsWith('.pdf') ||
+
url.hostname.includes('arxiv.org') ||
+
url.hostname.includes('nature.com') ||
+
url.hostname.includes('science.org') ||
+
url.hostname.includes('mdpi.com') ||
+
url.hostname.includes('doi.org')
+
) {
+
// Set display text based on source
+
if (url.hostname.includes('arxiv.org')) {
+
// Try to extract arXiv ID
+
const arxivIdMatch = url.pathname.match(/\d+\.\d+/);
+
if (arxivIdMatch) {
+
displayText = `<img src="solid-book-open.svg" width="14" height="14" style="vertical-align: middle; margin-right: 4px;"> ${arxivIdMatch[0]}`;
+
} else {
+
displayText = `<img src="solid-book-open.svg" width="14" height="14" style="vertical-align: middle; margin-right: 4px;"> Paper`;
+
}
+
} else if (url.hostname.includes('nature.com')) {
+
displayText = `<img src="solid-book-open.svg" width="14" height="14" style="vertical-align: middle; margin-right: 4px;"> Paper`;
+
} else if (url.hostname.includes('science.org')) {
+
displayText = `<img src="solid-book-open.svg" width="14" height="14" style="vertical-align: middle; margin-right: 4px;"> Paper`;
+
} else if (url.hostname.includes('mdpi.com')) {
+
displayText = `<img src="solid-book-open.svg" width="14" height="14" style="vertical-align: middle; margin-right: 4px;"> Paper`;
+
} else if (link.url.toLowerCase().endsWith('.pdf')) {
+
// For direct PDF links, try to get a meaningful filename
+
const pathParts = url.pathname.split('/');
+
const filename = pathParts[pathParts.length - 1];
+
if (filename) {
+
displayText = `<img src="solid-book-open.svg" width="13https://www.blogger.com/feeds/19062127/posts/default" height="14" style="vertical-align: middle; margin-right: 4px;"> ${decodeURIComponent(filename)}`;
+
} else {
+
displayText = `<img src="solid-book-open.svg" width="14" height="14" style="vertical-align: middle; margin-right: 4px;"> Document`;
+
}
+
}
+
}
+
// Determine link type for styling and future reference
let linkType = '';
if (url.hostname.includes('github')) linkType = 'github';
else if (url.hostname.includes('wikipedia')) linkType = 'wikipedia';
else if (url.hostname === 'twitter.com' || url.hostname === 'x.com') linkType = 'twitter';
else if (url.hostname.includes('linkedin.com')) linkType = 'linkedin';
-
else if (url.hostname.includes('youtube.com') || url.hostname === 'youtu.be') linkType = 'youtube';
+
else if (
+
url.hostname.includes('youtube.com') ||
+
url.hostname === 'youtu.be' ||
+
url.hostname === 'watch.eeg.cl.cam.ac.uk' ||
+
url.hostname === 'crank.recoil.org' ||
+
url.hostname === 'watch.ocaml.org'
+
) linkType = 'youtube';
else if (url.hostname.includes('medium.com')) linkType = 'medium';
else if (url.hostname.includes('stackoverflow.com')) linkType = 'stackoverflow';
else if (url.hostname === 'dev.to') linkType = 'dev';
···
else if (url.hostname.includes('news.ycombinator.com')) linkType = 'hackernews';
else if (url.hostname === 'bsky.app' || url.hostname === 'bsky.social') linkType = 'bluesky';
else if (url.hostname === 'ocaml.org' && url.pathname.startsWith('/p/')) linkType = 'ocaml';
+
else if (
+
link.url.toLowerCase().endsWith('.pdf') ||
+
url.hostname.includes('arxiv.org') ||
+
url.hostname.includes('nature.com') ||
+
url.hostname.includes('science.org') ||
+
url.hostname.includes('mdpi.com')
+
) linkType = 'academic';
return `<a href="${link.url}" target="_blank" class="external-link-item" title="${link.url}" data-link-type="${linkType}">${displayText}</a>`;
}).join(' ')}
···
if (parts.length >= 2 && parts[0] === 'in') {
displayText = parts[1];
-
} else if (url.hostname.includes('youtube.com') || url.hostname === 'youtu.be') {
+
} else if (
+
url.hostname.includes('youtube.com') ||
+
url.hostname === 'youtu.be' ||
+
url.hostname === 'watch.eeg.cl.cam.ac.uk' ||
+
url.hostname === 'crank.recoil.org' ||
+
url.hostname === 'watch.ocaml.org'
+
) {
iconPath = 'brands-youtube.svg';
-
displayText = 'YouTube Video';
+
+
// Custom display text for specific video platforms
+
if (url.hostname.includes('youtube.com') || url.hostname === 'youtu.be') {
+
displayText = 'YouTube Video';
+
} else if (url.hostname === 'watch.eeg.cl.cam.ac.uk') {
+
displayText = 'EEG Video';
+
} else if (url.hostname === 'crank.recoil.org') {
+
displayText = 'Crank Video';
+
} else if (url.hostname === 'watch.ocaml.org') {
+
displayText = 'OCaml Video';
+
} else {
+
displayText = 'Video';
+
}
} else if (url.hostname === 'ocaml.org' && url.pathname.startsWith('/p/')) {
const parts = url.pathname.substring(1).split('/').filter(part => part);
if (parts.length >= 2) {
···
displayText = 'Post';
} else {
displayText = `@${parts[0]}`;
+
}
+
}
+
}
+
+
// Academic paper detection - PDF files and academic domains
+
else if (
+
link.url.toLowerCase().endsWith('.pdf') ||
+
url.hostname.includes('arxiv.org') ||
+
url.hostname.includes('nature.com') ||
+
url.hostname.includes('science.org') ||
+
url.hostname.includes('mdpi.com') ||
+
url.hostname.includes('doi.org')
+
) {
+
iconPath = 'solid-book-open.svg';
+
+
// Set display text based on source
+
if (url.hostname.includes('arxiv.org')) {
+
// Try to extract arXiv ID
+
const arxivIdMatch = url.pathname.match(/\d+\.\d+/);
+
if (arxivIdMatch) {
+
displayText = arxivIdMatch[0];
+
} else {
+
displayText = 'Paper';
+
}
+
} else if (url.hostname.includes('nature.com')) {
+
displayText = 'Paper';
+
} else if (url.hostname.includes('science.org')) {
+
displayText = 'Paper';
+
} else if (url.hostname.includes('mdpi.com')) {
+
displayText = 'Paper';
+
} else if (link.url.toLowerCase().endsWith('.pdf')) {
+
// For direct PDF links, try to get a meaningful filename
+
const pathParts = url.pathname.split('/');
+
const filename = pathParts[pathParts.length - 1];
+
if (filename) {
+
displayText = decodeURIComponent(filename);
+
} else {
+
displayText = 'Document';
···
// Initialize tabs
setupTabs();
+
+
// Setup link filtering based on checkboxes
+
setupLinkFilters();
+
+
// Function to handle link filtering
+
function setupLinkFilters() {
+
const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
+
+
filterCheckboxes.forEach(checkbox => {
+
checkbox.addEventListener('change', updateFilter);
+
});
+
+
function updateFilter() {
+
// Get all checked filters
+
const activeFilters = Array.from(document.querySelectorAll('.filter-checkbox:checked'))
+
.map(checkbox => checkbox.getAttribute('data-filter'));
+
+
// Get all link items
+
const allLinkItems = document.querySelectorAll('.link-item');
+
const monthYearHeaders = document.querySelectorAll('.month-year-header');
+
+
// Show all items if no filters are selected
+
if (activeFilters.length === 0) {
+
allLinkItems.forEach(item => {
+
item.style.display = '';
+
});
+
monthYearHeaders.forEach(header => {
+
header.style.display = '';
+
});
+
return;
+
}
+
+
// Track visible items per month/year
+
const visibleByMonthYear = new Map();
+
+
// Process all items
+
allLinkItems.forEach(item => {
+
const linkUrl = item.querySelector('.link-item-url');
+
let shouldShow = false;
+
+
// Papers filter - check for PDF icon
+
if (activeFilters.includes('academic')) {
+
const hasPdfIcon = linkUrl && (
+
linkUrl.innerHTML.includes('solid-book-open.svg') ||
+
(linkUrl.getAttribute('data-link-type') === 'academic')
+
);
+
if (hasPdfIcon) shouldShow = true;
+
}
+
+
// Videos filter - check for YouTube icon or video domains
+
if (activeFilters.includes('youtube')) {
+
const hasYoutubeIcon = linkUrl && (
+
linkUrl.innerHTML.includes('brands-youtube.svg') ||
+
(linkUrl.getAttribute('data-link-type') === 'youtube')
+
);
+
+
// Also check for specific video site URLs
+
const url = linkUrl?.getAttribute('href');
+
const isVideoSite = url && (
+
url.includes('youtube.com') ||
+
url.includes('youtu.be') ||
+
url.includes('watch.eeg.cl.cam.ac.uk') ||
+
url.includes('crank.recoil.org') ||
+
url.includes('watch.ocaml.org')
+
);
+
+
if (hasYoutubeIcon || isVideoSite) shouldShow = true;
+
}
+
+
// Set visibility
+
item.style.display = shouldShow ? '' : 'none';
+
+
// Track visible items by month/year
+
if (shouldShow) {
+
const year = item.getAttribute('data-year');
+
const month = item.getAttribute('data-month');
+
const key = `${year}-${month}`;
+
visibleByMonthYear.set(key, (visibleByMonthYear.get(key) || 0) + 1);
+
}
+
});
+
+
// Hide month-year headers with no visible items
+
monthYearHeaders.forEach(header => {
+
const year = header.getAttribute('data-year');
+
const month = header.getAttribute('data-month');
+
const key = `${year}-${month}`;
+
+
if (visibleByMonthYear.has(key)) {
+
header.style.display = ''; // Show if has visible items
+
} else {
+
header.style.display = 'none'; // Hide if no visible items
+
}
+
});
+
+
// Update timeline sidebar to match visible items
+
const timelineYears = document.querySelectorAll('.timeline-year');
+
const timelineMonths = document.querySelectorAll('.timeline-month');
+
+
// First get all years that have visible items
+
const visibleYears = new Set();
+
visibleByMonthYear.forEach((count, key) => {
+
const [year] = key.split('-');
+
visibleYears.add(year);
+
});
+
+
// Hide years without visible items
+
if (activeFilters.length > 0) {
+
timelineYears.forEach(yearEl => {
+
const year = yearEl.getAttribute('data-year');
+
yearEl.style.display = visibleYears.has(year) ? '' : 'none';
+
});
+
+
// Hide months without visible items
+
timelineMonths.forEach(monthEl => {
+
const year = monthEl.getAttribute('data-year');
+
const month = monthEl.getAttribute('data-month');
+
const key = `${year}-${month}`;
+
monthEl.style.display = visibleByMonthYear.has(key) ? '' : 'none';
+
});
+
} else {
+
// Show all timeline elements when no filters
+
timelineYears.forEach(yearEl => yearEl.style.display = '');
+
timelineMonths.forEach(monthEl => monthEl.style.display = '');
+
}
+
}
+
}
// Make timeline items clickable to scroll to relevant posts or links
document.querySelectorAll('.timeline-year, .timeline-month').forEach(item => {