···
983
+
/* Styles for filter container */
984
+
.filter-container {
986
+
align-items: center;
987
+
margin-bottom: 15px;
988
+
padding: 10px 15px;
989
+
background-color: var(--card-bg);
990
+
border: 1px solid var(--border-color);
991
+
border-radius: 4px;
995
+
font-family: 'JetBrains Mono', monospace;
996
+
color: var(--accent-color);
998
+
margin-right: 15px;
1007
+
position: relative;
1009
+
align-items: center;
1011
+
user-select: none;
1014
+
.filter-checkbox {
1015
+
position: absolute;
1021
+
.checkbox-custom {
1022
+
position: relative;
1023
+
display: inline-block;
1026
+
background-color: rgba(77, 250, 123, 0.05);
1027
+
border: 1px solid var(--accent-alt);
1028
+
border-radius: 3px;
1029
+
margin-right: 8px;
1030
+
transition: all 0.2s ease;
1033
+
.filter-checkbox:checked + .checkbox-custom::after {
1035
+
position: absolute;
1040
+
border: solid var(--accent-color);
1041
+
border-width: 0 2px 2px 0;
1042
+
transform: rotate(45deg);
1045
+
.filter-checkbox:checked + .checkbox-custom {
1046
+
background-color: rgba(77, 250, 123, 0.15);
1047
+
border-color: var(--accent-color);
1051
+
font-size: 0.85rem;
1052
+
color: var(--text-color);
1055
+
.filter-option:hover .checkbox-custom {
1056
+
background-color: rgba(77, 250, 123, 0.1);
1057
+
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>
1059
-
<div id="link-items" class="tab-content feed-container" data-tab="links"></div>
1136
+
<div class="tab-content" data-tab="links">
1137
+
<div class="filter-container">
1138
+
<div class="filter-title">Filter:</div>
1139
+
<div class="filter-options">
1140
+
<label class="filter-option">
1141
+
<input type="checkbox" id="filter-papers" class="filter-checkbox" data-filter="academic">
1142
+
<span class="checkbox-custom"></span>
1143
+
<span class="filter-label">Papers</span>
1145
+
<label class="filter-option">
1146
+
<input type="checkbox" id="filter-videos" class="filter-checkbox" data-filter="youtube">
1147
+
<span class="checkbox-custom"></span>
1148
+
<span class="filter-label">Videos</span>
1152
+
<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') ||
1934
-
url.hostname.includes('mdpi.com')
2028
+
url.hostname.includes('mdpi.com') ||
2029
+
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';
1969
-
else if (url.hostname.includes('youtube.com') || url.hostname === 'youtu.be') linkType = 'youtube';
2065
+
url.hostname.includes('youtube.com') ||
2066
+
url.hostname === 'youtu.be' ||
2067
+
url.hostname === 'watch.eeg.cl.cam.ac.uk' ||
2068
+
url.hostname === 'crank.recoil.org' ||
2069
+
url.hostname === 'watch.ocaml.org'
2070
+
) 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') {
2272
-
} else if (url.hostname.includes('youtube.com') || url.hostname === 'youtu.be') {
2374
+
url.hostname.includes('youtube.com') ||
2375
+
url.hostname === 'youtu.be' ||
2376
+
url.hostname === 'watch.eeg.cl.cam.ac.uk' ||
2377
+
url.hostname === 'crank.recoil.org' ||
2378
+
url.hostname === 'watch.ocaml.org'
iconPath = 'brands-youtube.svg';
2274
-
displayText = 'YouTube Video';
2382
+
// Custom display text for specific video platforms
2383
+
if (url.hostname.includes('youtube.com') || url.hostname === 'youtu.be') {
2384
+
displayText = 'YouTube Video';
2385
+
} else if (url.hostname === 'watch.eeg.cl.cam.ac.uk') {
2386
+
displayText = 'EEG Video';
2387
+
} else if (url.hostname === 'crank.recoil.org') {
2388
+
displayText = 'Crank Video';
2389
+
} else if (url.hostname === 'watch.ocaml.org') {
2390
+
displayText = 'OCaml Video';
2392
+
displayText = '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') ||
2345
-
url.hostname.includes('mdpi.com')
2464
+
url.hostname.includes('mdpi.com') ||
2465
+
url.hostname.includes('doi.org')
iconPath = 'free-icons/svgs/regular-file-pdf.svg';
···
2649
+
// Setup link filtering based on checkboxes
2650
+
setupLinkFilters();
2652
+
// Function to handle link filtering
2653
+
function setupLinkFilters() {
2654
+
const filterCheckboxes = document.querySelectorAll('.filter-checkbox');
2656
+
filterCheckboxes.forEach(checkbox => {
2657
+
checkbox.addEventListener('change', updateFilter);
2660
+
function updateFilter() {
2661
+
// Get all checked filters
2662
+
const activeFilters = Array.from(document.querySelectorAll('.filter-checkbox:checked'))
2663
+
.map(checkbox => checkbox.getAttribute('data-filter'));
2665
+
// Get all link items
2666
+
const allLinkItems = document.querySelectorAll('.link-item');
2667
+
const monthYearHeaders = document.querySelectorAll('.month-year-header');
2669
+
// Show all items if no filters are selected
2670
+
if (activeFilters.length === 0) {
2671
+
allLinkItems.forEach(item => {
2672
+
item.style.display = '';
2674
+
monthYearHeaders.forEach(header => {
2675
+
header.style.display = '';
2680
+
// Track visible items per month/year
2681
+
const visibleByMonthYear = new Map();
2683
+
// Process all items
2684
+
allLinkItems.forEach(item => {
2685
+
const linkUrl = item.querySelector('.link-item-url');
2686
+
let shouldShow = false;
2688
+
// Papers filter - check for PDF icon
2689
+
if (activeFilters.includes('academic')) {
2690
+
const hasPdfIcon = linkUrl && (
2691
+
linkUrl.innerHTML.includes('regular-file-pdf.svg') ||
2692
+
(linkUrl.getAttribute('data-link-type') === 'academic')
2694
+
if (hasPdfIcon) shouldShow = true;
2697
+
// Videos filter - check for YouTube icon or video domains
2698
+
if (activeFilters.includes('youtube')) {
2699
+
const hasYoutubeIcon = linkUrl && (
2700
+
linkUrl.innerHTML.includes('brands-youtube.svg') ||
2701
+
(linkUrl.getAttribute('data-link-type') === 'youtube')
2704
+
// Also check for specific video site URLs
2705
+
const url = linkUrl?.getAttribute('href');
2706
+
const isVideoSite = url && (
2707
+
url.includes('youtube.com') ||
2708
+
url.includes('youtu.be') ||
2709
+
url.includes('watch.eeg.cl.cam.ac.uk') ||
2710
+
url.includes('crank.recoil.org') ||
2711
+
url.includes('watch.ocaml.org')
2714
+
if (hasYoutubeIcon || isVideoSite) shouldShow = true;
2718
+
item.style.display = shouldShow ? '' : 'none';
2720
+
// Track visible items by month/year
2722
+
const year = item.getAttribute('data-year');
2723
+
const month = item.getAttribute('data-month');
2724
+
const key = `${year}-${month}`;
2725
+
visibleByMonthYear.set(key, (visibleByMonthYear.get(key) || 0) + 1);
2729
+
// Hide month-year headers with no visible items
2730
+
monthYearHeaders.forEach(header => {
2731
+
const year = header.getAttribute('data-year');
2732
+
const month = header.getAttribute('data-month');
2733
+
const key = `${year}-${month}`;
2735
+
if (visibleByMonthYear.has(key)) {
2736
+
header.style.display = ''; // Show if has visible items
2738
+
header.style.display = 'none'; // Hide if no visible items
2742
+
// Update timeline sidebar to match visible items
2743
+
const timelineYears = document.querySelectorAll('.timeline-year');
2744
+
const timelineMonths = document.querySelectorAll('.timeline-month');
2746
+
// First get all years that have visible items
2747
+
const visibleYears = new Set();
2748
+
visibleByMonthYear.forEach((count, key) => {
2749
+
const [year] = key.split('-');
2750
+
visibleYears.add(year);
2753
+
// Hide years without visible items
2754
+
if (activeFilters.length > 0) {
2755
+
timelineYears.forEach(yearEl => {
2756
+
const year = yearEl.getAttribute('data-year');
2757
+
yearEl.style.display = visibleYears.has(year) ? '' : 'none';
2760
+
// Hide months without visible items
2761
+
timelineMonths.forEach(monthEl => {
2762
+
const year = monthEl.getAttribute('data-year');
2763
+
const month = monthEl.getAttribute('data-month');
2764
+
const key = `${year}-${month}`;
2765
+
monthEl.style.display = visibleByMonthYear.has(key) ? '' : 'none';
2768
+
// Show all timeline elements when no filters
2769
+
timelineYears.forEach(yearEl => yearEl.style.display = '');
2770
+
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 => {