'use client';
import Link from 'next/link';
import Image from 'next/image';
import { useEffect, useRef, useState } from 'react';
import { FaGithub, FaMastodon, FaLinkedin } from 'react-icons/fa';
import { FiTrendingUp, FiArrowRight } from 'react-icons/fi';
import { siteConfig } from '@/lib/config';
import { getAllTagsWithCount } from '@/lib/posts';
import { allPages } from 'contentlayer2/generated';
import dynamic from 'next/dynamic';
// Lazy load MastodonFeed - only load when sidebar is visible
const MastodonFeed = dynamic(() => import('./mastodon-feed').then(mod => ({ default: mod.MastodonFeed })), {
ssr: false,
loading: () =>
,
});
/** Shared sidebar content for desktop aside and mobile drawer */
export function RightSidebarContent({ forceLoadFeed = false }: { forceLoadFeed?: boolean }) {
const [shouldLoadFeed, setShouldLoadFeed] = useState(forceLoadFeed);
const feedRef = useRef(null);
useEffect(() => {
if (forceLoadFeed) {
setShouldLoadFeed(true);
return;
}
if (!feedRef.current) return;
let observer: IntersectionObserver | null = null;
let cleanupRequested = false;
const setupObserver = () => {
if (cleanupRequested) return;
const el = feedRef.current;
if (!el) return;
observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting) {
setShouldLoadFeed(true);
observer?.disconnect();
}
},
{ rootMargin: '100px' }
);
observer.observe(el);
};
// Defer observer setup for better initial performance
requestAnimationFrame(() => {
if (!cleanupRequested && feedRef.current) {
setupObserver();
}
});
return () => {
cleanupRequested = true;
observer?.disconnect();
};
}, [forceLoadFeed]);
const tags = getAllTagsWithCount().slice(0, 5);
const aboutPage =
allPages.find((p) => p.title.includes('關於作者')) ??
allPages.find((p) => p.slug === 'about-me');
const avatarSrc = siteConfig.avatar;
const socialItems = [
siteConfig.social.github && {
key: 'github',
href: siteConfig.social.github,
icon: FaGithub,
label: 'GitHub'
},
siteConfig.social.mastodon && {
key: 'mastodon',
href: siteConfig.social.mastodon,
icon: FaMastodon,
label: 'Mastodon'
},
siteConfig.social.linkedin && {
key: 'linkedin',
href: siteConfig.social.linkedin,
icon: FaLinkedin,
label: 'LinkedIn'
}
].filter(Boolean) as { key: string; href: string; icon: any; label: string }[];
return (
{avatarSrc ? (
) : (
{siteConfig.name.charAt(0).toUpperCase()}
)}
{socialItems.length > 0 && (
{socialItems.map((item) => (
))}
)}
{siteConfig.aboutShort && (
{siteConfig.aboutShort.split(/\n+/).map((line, index) => (
{line}
))}
)}
{/* Mastodon Feed - Lazy loaded when visible */}
{shouldLoadFeed && }
{tags.length > 0 && (
熱門標籤
{tags.map(({ tag, slug, count }) => {
let sizeClass = '';
if (count >= 5) sizeClass = 'font-semibold';
else if (count >= 3) sizeClass = 'font-medium';
return (
{tag}
);
})}
一覽所有標籤
前往
)}
);
}
export function RightSidebar() {
return (
);
}