blog / src /pages /rss.astro
cacode's picture
Upload 434 files
96dd062 verified
---
import MainGridLayout from "@layouts/MainGridLayout.astro";
import { getSortedPosts } from "@utils/content-utils";
import { formatDateToYYYYMMDD } from "@utils/date-utils";
import { Icon } from "astro-icon/components";
import I18nKey from "@/i18n/i18nKey";
import { i18n } from "@/i18n/translation";
const posts = await getSortedPosts();
const recentPosts = posts.slice(0, 6);
---
<MainGridLayout title={i18n(I18nKey.rss)} description={i18n(I18nKey.rssDescription)}>
<div class="onload-animation">
<!-- RSS 标题和介绍 -->
<div class="card-base rounded-(--radius-large) p-8 mb-6">
<div class="text-center">
<div class="inline-flex items-center justify-center w-16 h-16 bg-(--primary) rounded-2xl mb-4">
<Icon name="material-symbols:rss-feed" class="text-white text-3xl" />
</div>
<h1 class="text-3xl font-bold text-(--primary) mb-3">{i18n(I18nKey.rss)}</h1>
<p class="text-75 max-w-2xl mx-auto">
{i18n(I18nKey.rssSubtitle)}
</p>
</div>
</div>
<!-- RSS 链接复制区域 -->
<div class="card-base rounded-(--radius-large) p-6 mb-6">
<div class="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div class="flex items-center">
<div class="w-12 h-12 bg-(--primary) rounded-xl flex items-center justify-center mr-4">
<Icon name="material-symbols:link" class="text-white text-xl" />
</div>
<div>
<h3 class="font-semibold text-90 mb-1">{i18n(I18nKey.rssLink)}</h3>
<p class="text-sm text-75">{i18n(I18nKey.rssCopyToReader)}</p>
</div>
</div>
<div class="flex flex-col sm:flex-row items-stretch sm:items-center gap-3">
<code class="bg-(--card-bg) px-3 py-2 rounded-lg text-sm font-mono text-75 border border-(--line-divider) break-all">
{Astro.site}rss.xml
</code>
<button
id="copy-rss-btn"
class="px-4 py-2 bg-(--primary) text-white rounded-lg hover:opacity-80 transition-all duration-200 font-medium text-sm whitespace-nowrap"
data-url={`${Astro.site}rss.xml`}
data-copied-text={i18n(I18nKey.rssCopied)}
data-failed-text={i18n(I18nKey.rssCopyFailed)}
>
{i18n(I18nKey.rssCopyLink)}
</button>
</div>
</div>
</div>
<!-- 最新文章预览 -->
<div class="card-base rounded-(--radius-large) p-6 mb-6">
<h2 class="text-xl font-bold text-90 mb-4 flex items-center">
<Icon name="material-symbols:article" class="mr-2 text-(--primary)" />
{i18n(I18nKey.rssLatestPosts)}
</h2>
<div class="space-y-4">
{recentPosts.map((post) => (
<article class="bg-(--card-bg) rounded-xl p-4 border border-(--line-divider) hover:border-(--primary) transition-all duration-300">
<h3 class="text-lg font-semibold text-90 mb-2 hover:text-(--primary) transition-colors">
<a href={`/posts/${post.id}/`} class="hover:underline">
{post.data.title}
</a>
</h3>
{post.data.description && (
<p class="text-75 mb-3 line-clamp-2">
{post.data.description}
</p>
)}
<div class="flex items-center gap-4 text-sm text-60">
<time datetime={post.data.published.toISOString()} class="text-75">
{formatDateToYYYYMMDD(post.data.published)}
</time>
</div>
</article>
))}
</div>
</div>
<!-- RSS 说明 -->
<div class="card-base rounded-(--radius-large) p-6">
<h2 class="text-xl font-bold text-90 mb-4 flex items-center">
<Icon name="material-symbols:help-outline" class="mr-2 text-(--primary)" />
{i18n(I18nKey.rssWhatIsRSS)}
</h2>
<div class="text-75 space-y-3">
<p>
{i18n(I18nKey.rssWhatIsRSSDescription)}
</p>
<ul class="list-disc list-inside space-y-1 ml-4">
<li>{i18n(I18nKey.rssBenefit1)}</li>
<li>{i18n(I18nKey.rssBenefit2)}</li>
<li>{i18n(I18nKey.rssBenefit3)}</li>
<li>{i18n(I18nKey.rssBenefit4)}</li>
</ul>
<p class="text-sm">
{i18n(I18nKey.rssHowToUse)}
</p>
</div>
</div>
</div>
<script>
function initRssCopy() {
const copyBtn = document.getElementById('copy-rss-btn');
if (!copyBtn) return;
// 移除旧的事件监听器(通过克隆节点的方式)
const newBtn = copyBtn.cloneNode(true);
copyBtn.parentNode?.replaceChild(newBtn, copyBtn);
// 绑定新的事件监听器
newBtn.addEventListener('click', async function() {
const url = this.getAttribute('data-url');
if (!url) return;
try {
await navigator.clipboard.writeText(url);
const originalText = this.textContent;
this.textContent = this.getAttribute('data-copied-text') || '';
this.style.backgroundColor = 'var(--success-color, #10b981)';
setTimeout(() => {
this.textContent = originalText;
this.style.backgroundColor = '';
}, 2000);
} catch (err) {
console.error('复制失败:', err);
const originalText = this.textContent;
this.textContent = this.getAttribute('data-failed-text') || '';
setTimeout(() => {
this.textContent = originalText;
}, 2000);
}
});
}
// 立即初始化(支持直接访问页面和刷新)
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initRssCopy);
} else {
// DOM 已加载,直接初始化
setTimeout(initRssCopy, 0);
}
// 支持 Swup 客户端路由(如果存在)
if (typeof window !== 'undefined' && (window as any).swup) {
(window as any).swup.hooks.on('content:replace', () => {
// 延迟执行以确保 DOM 已更新
setTimeout(initRssCopy, 100);
});
}
</script>
</MainGridLayout>