From 795cd8ed01064251321a5648454cbb3e57043a76 Mon Sep 17 00:00:00 2001 From: Rawan Abdellatif Date: Thu, 30 Apr 2026 12:01:25 -0600 Subject: [PATCH] Add latest news feed from Mastodon on homepage instead of Twitter --- docusaurus.config.js | 2 +- src/components/MastodonFeed.tsx | 144 ++++++++++++++++++++++++++------ src/pages/index.tsx | 6 +- 3 files changed, 125 insertions(+), 27 deletions(-) diff --git a/docusaurus.config.js b/docusaurus.config.js index 10f9b6b..627e25e 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -76,7 +76,7 @@ const config = { // { to: "/event", label: "Event", position: "left" }, { to: "/tools", label: "Tools", position: "left" }, - { to: "/test"}, + // { to: "/test"}, // { to: "/data1", label: "Data1", position: "left" }, // { to: "/data2", label: "Data2", position: "left" }, diff --git a/src/components/MastodonFeed.tsx b/src/components/MastodonFeed.tsx index 6ab788e..6d21406 100644 --- a/src/components/MastodonFeed.tsx +++ b/src/components/MastodonFeed.tsx @@ -6,11 +6,87 @@ type Post = { content: string; pubDate: string; imageUrl: string | null; + authorName: string; + authorHandle: string; + authorUrl: string; }; + +function AuthorHeader({ + name, + handle, + url, + avatar, +}: { + name: string; + handle: string; + url: string; + avatar: string | null; +}) { + return ( + + {/* Real profile image */} + {avatar ? ( + {name} + ) : ( +
+ )} + + {/* Text */} +
+ {name} + {handle} +
+
+ ); +} + + export function MastodonFeed() { const [posts, setPosts] = useState([]); - const RSS_URL = "https://mastodon.social/@rawanabdellatif.rss"; + const [avatar, setAvatar] = useState(null); + + const RSS_URL = "https://mastodon.social/@daslab.rss"; + + + + useEffect(() => { + fetch( + "https://mastodon.social/api/v1/accounts/lookup?acct=daslab" + ) + .then((res) => res.json()) + .then((data) => setAvatar(data.avatar)) + .catch((err) => console.error("Avatar fetch error:", err)); + }, []); + useEffect(() => { fetch(RSS_URL) @@ -26,42 +102,33 @@ export function MastodonFeed() { const link = item.querySelector("link")?.textContent || ""; const pubDate = item.querySelector("pubDate")?.textContent || ""; - // content const contentNode = item.querySelector("content\\:encoded") || item.querySelector("description"); const content = contentNode?.textContent || ""; - // ------------------------- - // IMAGE EXTRACTION (FIXED) - // ------------------------- - let imageUrl: string | null = null; - // 1. enclosure (BEST SOURCE) const enclosure = item.querySelector("enclosure"); if (enclosure?.getAttribute("url")) { imageUrl = enclosure.getAttribute("url"); } - // 2. media:content fallback if (!imageUrl) { - const mediaContent = item.getElementsByTagName("media:content")[0]; + const mediaContent = + item.getElementsByTagName("media:content")[0]; if (mediaContent?.getAttribute("url")) { imageUrl = mediaContent.getAttribute("url"); } } - // 3. HTML fallback if (!imageUrl) { const contentDoc = new DOMParser().parseFromString( content, "text/html" ); - const img = contentDoc.querySelector("img"); - if (img) { imageUrl = img.getAttribute("src") || @@ -70,7 +137,16 @@ export function MastodonFeed() { } } - return { title, link, content, pubDate, imageUrl }; + return { + title, + link, + content, + pubDate, + imageUrl, + authorName: "DASLAB", + authorHandle: "@daslab", + authorUrl: "https://mastodon.social/@daslab", + }; }); setPosts(latestPosts); @@ -90,39 +166,59 @@ export function MastodonFeed() { gap: "15px", marginBottom: "20px", border: "1px solid #ddd", - padding: "10px", - borderRadius: "8px", + padding: "12px", + borderRadius: "10px", }} > - {/* Image */} + {/* Post image */} {post.imageUrl && ( {post.title )} {/* Content */}
-
+ {/* Author with REAL avatar */} + + + {/* Text */} +
+ {post.content + ? post.content.replace(/<[^>]+>/g, "").slice(0, 200) + + "..." + : ""} +
+ {/* Date */} {post.pubDate ? new Date(post.pubDate).toLocaleDateString() : ""} - {/*
*/} - + {/* Link */} +
))} diff --git a/src/pages/index.tsx b/src/pages/index.tsx index f30880d..a05c91d 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -5,6 +5,7 @@ import useDocusaurusContext from "@docusaurus/useDocusaurusContext"; import styles from "./index.module.css"; import logo from "../../static/img/logo.png"; import { TwitterFeed } from "../components/Twitter"; +import { MastodonFeed } from "../components/MastodonFeed"; import HomeNotes from "./_home.mdx"; function HomepageHeader() { @@ -34,11 +35,12 @@ export default function Home(): JSX.Element {
- + /> */} +