···
+
/* Styles for filter container */
+
background-color: var(--card-bg);
+
border: 1px solid var(--border-color);
+
font-family: 'JetBrains Mono', monospace;
+
color: var(--accent-color);
+
background-color: rgba(77, 250, 123, 0.05);
+
border: 1px solid var(--accent-alt);
+
transition: all 0.2s ease;
+
.filter-checkbox:checked + .checkbox-custom::after {
+
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);
+
color: var(--text-color);
+
.filter-option:hover .checkbox-custom {
+
background-color: rgba(77, 250, 123, 0.1);
+
border-color: var(--accent-color);
@media (max-width: 600px) {
···
<p class="loading-text">Growing Content...</p>
<div id="feed-items" class="tab-content active feed-container" data-tab="posts"></div>
+
<div class="tab-content" data-tab="links">
+
<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 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>
+
<div id="link-items" class="feed-container"></div>
<div id="people-items" class="tab-content" data-tab="people">
<h2 class="people-header">EEG Sources</h2>
<div class="people-container"></div>
···
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')) {
···
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';
+
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';
···
if (parts.length >= 2 && parts[0] === 'in') {
+
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';
+
// 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 if (url.hostname === 'ocaml.org' && url.pathname.startsWith('/p/')) {
const parts = url.pathname.substring(1).split('/').filter(part => part);
···
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 = 'free-icons/svgs/regular-file-pdf.svg';
···
+
// Setup link filtering based on checkboxes
+
// 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'));
+
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 = '';
+
// Track visible items per month/year
+
const visibleByMonthYear = new Map();
+
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('regular-file-pdf.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;
+
item.style.display = shouldShow ? '' : 'none';
+
// Track visible items by month/year
+
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
+
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';
+
// 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 => {