summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--_data/links.csv28
-rw-r--r--js/rss-feed-preview.js223
-rw-r--r--links.md4
3 files changed, 240 insertions, 15 deletions
diff --git a/_data/links.csv b/_data/links.csv
index e495e23..390f3fc 100644
--- a/_data/links.csv
+++ b/_data/links.csv
@@ -1,14 +1,14 @@
-title,link,description
-花火学园,https://www.sayhanabi.net/,和谐融洽的ACG交流以及资源聚集地
-资源统筹局,https://gkdworld.com/,统筹保管用户分享的资源
-贫困的蚊子,https://mozz.ie/,*No description*
-极客兔兔,https://geektutu.com/,致力于分享有趣的技术实践
-维基萌,https://www.wikimoe.com/,萌即是正义!一名热爱acg的前端设计师的小站!
-7gugu's blog,https://www.7gugu.com/,"一个用来存放我爱好的地方,编程,摄影之类的空间"
-云游君,https://www.yunyoujun.cn/,希望能成为一个有趣的人。
-Kingfish404,https://blog.kingfish404.cn/,"Stay curious,stay naive. WUT. Jin Yu's Blog"
-FKUN,https://blog.fkun.tech/,*No description*
-Sinofine,https://sinofine.me/,*No description*
-JiaoYuan's blog,https://yuanj.top/,思绪来得快去得也快,偶尔会在这里停留
-花生莲子粥,https://blog.hslzz.cn/,与世无争,不染于泥
-南蛮子懋和,https://www.dao.js.cn/,李懋和,俗名李栋梁。书法、国画爱好者,互联网安全与前端建设者。
\ No newline at end of file
+title,link,feed_url,description
+花火学园,https://www.sayhanabi.net/,,和谐融洽的ACG交流以及资源聚集地
+资源统筹局,https://gkdworld.com/,,统筹保管用户分享的资源
+贫困的蚊子,https://mozz.ie/,https://mozz.ie/index.xml,*No description*
+极客兔兔,https://geektutu.com/,https://geektutu.com/atom.xml,致力于分享有趣的技术实践
+维基萌,https://www.wikimoe.com/,https://www.wikimoe.com/rss,萌即是正义!一名热爱acg的前端设计师的小站!
+7gugu's blog,https://www.7gugu.com/,https://7gugu.com/index.php/feed/,"一个用来存放我爱好的地方,编程,摄影之类的空间"
+云游君,https://www.yunyoujun.cn/,https://www.yunyoujun.cn/atom.xml,希望能成为一个有趣的人。
+Kingfish404,https://blog.kingfish404.cn/,https://blog.kingfish404.cn/index.xml,"Stay curious,stay naive. WUT. Jin Yu's Blog"
+FKUN,https://blog.fkun.tech/,https://blog.fkun.tech/feed/,*No description*
+Sinofine,https://sinofine.me/,https://sinofine.me/atom.xml,*No description*
+JiaoYuan's blog,https://yuanj.top/,https://yuanj.top/index.xml,思绪来得快去得也快,偶尔会在这里停留
+花生莲子粥,https://blog.hslzz.cn/,https://blog.hslzz.cn/atom.xml,与世无争,不染于泥
+南蛮子懋和,https://www.dao.js.cn/,https://www.dao.js.cn/feed.php,李懋和,俗名李栋梁。书法、国画爱好者,互联网安全与前端建设者。
\ No newline at end of file
diff --git a/js/rss-feed-preview.js b/js/rss-feed-preview.js
new file mode 100644
index 0000000..8d74709
--- /dev/null
+++ b/js/rss-feed-preview.js
@@ -0,0 +1,223 @@
+/**
+ * RSS/Atom Feed Preview for Links Table
+ */
+
+(function() {
+    const existingPreviews = document.querySelectorAll('#rss-feed-preview');
+    existingPreviews.forEach(el => el.remove());
+  
+    const CORS_PROXY = 'https://cors-anywhere.mayx.eu.org/?';
+  
+    const createPreviewElement = () => {
+      const existingPreview = document.getElementById('rss-feed-preview');
+      if (existingPreview) {
+        return existingPreview;
+      }
+  
+      const previewEl = document.createElement('div');
+      previewEl.id = 'rss-feed-preview';
+      previewEl.style.cssText = `
+        position: fixed;
+        display: none;
+        width: 300px;
+        max-height: 400px;
+        overflow-y: auto;
+        background-color: white;
+        border: 1px solid #ccc;
+        border-radius: 5px;
+        padding: 10px;
+        box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
+        z-index: 1000;
+        font-size: 14px;
+        line-height: 1.4;
+      `;
+      document.body.appendChild(previewEl);
+      return previewEl;
+    };
+  
+    const parseRSS = (xmlText) => {
+      const parser = new DOMParser();
+      const xml = parser.parseFromString(xmlText, 'text/xml');
+  
+      const rssItems = xml.querySelectorAll('item');
+      if (rssItems.length > 0) {
+        return Array.from(rssItems).slice(0, 5).map(item => {
+          return {
+            title: item.querySelector('title')?.textContent || 'No title',
+            date: item.querySelector('pubDate')?.textContent || 'No date',
+          };
+        });
+      }
+  
+      const atomItems = xml.querySelectorAll('entry');
+      if (atomItems.length > 0) {
+        return Array.from(atomItems).slice(0, 5).map(item => {
+          return {
+            title: item.querySelector('title')?.textContent || 'No title',
+            date: item.querySelector('updated')?.textContent || 'No date',
+          };
+        });
+      }
+  
+      return null;
+    };
+  
+    const checkFeed = async (url) => {
+      try {
+        const response = await fetch(CORS_PROXY + url);
+        if (!response.ok) {
+          return null;
+        }
+  
+        const text = await response.text();
+        return parseRSS(text);
+      } catch (error) {
+        return null;
+      }
+    };
+  
+    const findFeedUrl = async (siteUrl, linkElement) => {
+      if (linkElement && linkElement.hasAttribute('data-feed')) {
+        const dataFeedUrl = linkElement.getAttribute('data-feed');
+        if (dataFeedUrl) {
+          const feedItems = await checkFeed(dataFeedUrl);
+          if (feedItems) {
+            return { url: dataFeedUrl, items: feedItems };
+          }
+        }
+      }
+  
+      return null;
+    };
+  
+    const renderFeedItems = (previewEl, items, siteName) => {
+      if (!items || items.length === 0) {
+        previewEl.innerHTML = '<p>No feed items found.</p>';
+        return;
+      }
+  
+      let html = `<h3>Latest from ${siteName}</h3><ul style="list-style: none; padding: 0; margin: 0;">`;
+  
+      items.forEach(item => {
+        html += `
+          <li style="margin-bottom: 10px; padding-bottom: 10px; border-bottom: 1px solid #eee;">
+            <div style="color: #24292e; font-weight: bold;">
+              ${item.title}
+            </div>
+            <div style="color: #586069; font-size: 12px; margin: 3px 0;">
+              ${new Date(item.date).toLocaleDateString()}
+            </div>
+          </li>
+        `;
+      });
+  
+      html += '</ul>';
+      previewEl.innerHTML = html;
+    };
+  
+    const positionPreview = (previewEl, event) => {
+      const viewportWidth = window.innerWidth;
+      const viewportHeight = window.innerHeight;
+  
+      let left = event.clientX + 20;
+      let top = event.clientY + 20;
+  
+      const rect = previewEl.getBoundingClientRect();
+  
+      if (left + rect.width > viewportWidth) {
+        left = event.clientX - rect.width - 20;
+      }
+  
+      if (top + rect.height > viewportHeight) {
+        top = event.clientY - rect.height - 20;
+      }
+  
+      left = Math.max(10, left);
+      top = Math.max(10, top);
+  
+      previewEl.style.left = `${left}px`;
+      previewEl.style.top = `${top}px`;
+    };
+  
+    const initFeedPreview = () => {
+      const previewEl = createPreviewElement();
+  
+      const tableLinks = document.querySelectorAll('main table tbody tr td a');
+  
+      const feedCache = {};
+  
+      let currentLink = null;
+      let loadingTimeout = null;
+  
+      tableLinks.forEach(link => {
+        link.addEventListener('mouseenter', async (event) => {
+          currentLink = link;
+          const url = link.getAttribute('href');
+          const siteName = link.textContent;
+  
+          previewEl.innerHTML = '<p>Checking for RSS/Atom feed...</p>';
+          previewEl.style.display = 'block';
+          positionPreview(previewEl, event);
+  
+          if (loadingTimeout) {
+            clearTimeout(loadingTimeout);
+          }
+  
+          loadingTimeout = setTimeout(async () => {
+            if (feedCache[url]) {
+              renderFeedItems(previewEl, feedCache[url].items, siteName);
+              positionPreview(previewEl, event); // Reposition after content is loaded
+              return;
+            }
+  
+            const feedData = await findFeedUrl(url, link);
+  
+            if (currentLink === link) {
+              if (feedData) {
+                feedCache[url] = feedData;
+                renderFeedItems(previewEl, feedData.items, siteName);
+                positionPreview(previewEl, event); // Reposition after content is loaded
+              } else {
+                previewEl.style.display = 'none';
+              }
+            }
+          }, 300);
+        });
+  
+        link.addEventListener('mousemove', (event) => {
+          if (previewEl.style.display === 'block') {
+            window.requestAnimationFrame(() => {
+              positionPreview(previewEl, event);
+            });
+          }
+        });
+  
+        link.addEventListener('mouseleave', () => {
+          if (loadingTimeout) {
+            clearTimeout(loadingTimeout);
+            loadingTimeout = null;
+          }
+  
+          currentLink = null;
+          previewEl.style.display = 'none';
+        });
+      });
+  
+      document.addEventListener('click', (event) => {
+        if (!previewEl.contains(event.target)) {
+          previewEl.style.display = 'none';
+        }
+      });
+    };
+  
+    if (!window.rssFeedPreviewInitialized) {
+      window.rssFeedPreviewInitialized = true;
+  
+      if (document.readyState === 'loading') {
+        document.addEventListener('DOMContentLoaded', initFeedPreview);
+      } else {
+        initFeedPreview();
+      }
+    }
+  })();
+  
\ No newline at end of file
diff --git a/links.md b/links.md
index b0b8e67..dbefd15 100644
--- a/links.md
+++ b/links.md
@@ -8,7 +8,7 @@ tags: [links]
 
 | Link | Description |
 | - | - |
-{% for item in site.data.links %}| [{{ item.title }}]({{ item.link }}) | {{ item.description }} |
+{% for item in site.data.links %}| <a href="{{ item.link }}" data-feed="{{ item.feed_url }}">{{ item.title }}</a> | {{ item.description }} |
 {% endfor %}
 
 ## Links申请
@@ -25,3 +25,5 @@ tags: [links]
 链接:<https://mabbs.github.io>   
 头像:<https://avatars0.githubusercontent.com/u/17966333>   
 Logo:<https://mabbs.github.io/favicon.ico>
+
+<script src="/js/rss-feed-preview.js"></script>
\ No newline at end of file