HTML/CSS/Javascript 在线代码运行工具:https://www.runoob.com/runcode
动态磁贴 RSS订阅 嵌入式代码 1
<div id="rss-tile-widget-container" class="wp-embed-container my-4">
<!-- 引入 Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* 确保中文字体优先 */
@import url('https://fonts.googleapis.com/css2?family=Inter:[email protected]&display=swap');
/* 定义磁贴的基本样式和交互效果,仅对容器内的元素生效 */
#rss-tile-widget-container .tile {
/* Updated for frosted glass effect (磨砂玻璃效果) */
background-color: rgba(255, 255, 255, 0.6); /* 半透明白色背景 */
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.2); /* 细微边框,增加质感 */
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
transition: transform 0.2s, box-shadow 0.2s;
cursor: pointer;
overflow: hidden; /* 确保内容不溢出 */
display: flex;
flex-direction: column;
font-family: 'Inter', 'Noto Sans SC', sans-serif; /* 确保字体在嵌入环境中生效 */
}
#rss-tile-widget-container .tile:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
/* 强制图片占满空间并保持纵横比 */
#rss-tile-widget-container .tile-img {
width: 100%;
height: 100%;
object-fit: cover;
}
/* Specific styles for colored tiles to maintain theme but allow glass effect */
#rss-tile-widget-container .tile-blue-glass {
background-color: rgba(0, 120, 212, 0.7); /* msn-blue with opacity */
}
#rss-tile-widget-container .tile-red-glass {
background-color: rgba(216, 59, 1, 0.7); /* msn-red with opacity */
}
#rss-tile-widget-container .tile-dark-glass {
background-color: rgba(55, 65, 81, 0.7); /* gray-700 with opacity */
}
</style>
<script>
// 重新配置 Tailwind 颜色,以便在嵌入环境中生效
tailwind.config = {
theme: {
extend: {
colors: {
'msn-blue': '#0078D4', /* 典型的 Microsoft 蓝 */
'msn-green': '#107C10',
'msn-red': '#D83B01',
}
}
}
}
</script>
<!-- 磁贴主布局 -->
<main class="max-w-7xl mx-auto p-4">
<!--
使用 CSS Grid 创建磁贴布局
添加 grid-flow-row-dense (grid-auto-flow: dense) 确保磁贴紧凑排列,不留空隙。
-->
<div id="grid-container" class="grid grid-cols-2 md:grid-cols-4 gap-4 auto-rows-[120px] md:auto-rows-[160px] grid-flow-row-dense">
<!-- 初始加载状态 -->
<div class="col-span-4 p-8 text-center text-gray-500">
<p>正在加载少数派和爱范儿资讯...</p>
<div class="mt-4 w-6 h-6 border-4 border-msn-blue border-t-transparent rounded-full animate-spin mx-auto"></div>
</div>
</div>
</main>
<script>
// RSS Feed URL 1 (少数派)
const SSPAI_FEED_URL = "https://sspai.com/feed";
const SSPAI_PROXY_URL = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(SSPAI_FEED_URL)}`;
// RSS Feed URL 2 (爱范儿)
const IFANR_FEED_URL = "https://www.ifanr.com/feed";
const IFANR_PROXY_URL = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(IFANR_FEED_URL)}`;
// 随机图片 API URL
const RANDOM_IMAGE_URL = 'https://www.dmoe.cc/random.php';
// 预定义的磁贴大小和样式 (共 20 个配置)
const TILE_CONFIGS = [
{ class: "col-span-2 row-span-2 tile-blue-glass text-white", hasImage: true }, // 1. 2x2 (Primary)
{ class: "col-span-2 row-span-1", hasImage: true }, // 2. 2x1 (Wide)
{ class: "col-span-1 row-span-1 tile-red-glass text-white", hasImage: false }, // 3. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: false }, // 4. 1x1 (Small)
{ class: "col-span-1 row-span-2", hasImage: true }, // 5. 1x2 (Tall)
{ class: "col-span-1 row-span-1", hasImage: false }, // 6. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: false }, // 7. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: false }, // 8. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: true }, // 9. 1x1 (Small)
{ class: "col-span-2 row-span-1 tile-dark-glass text-white", hasImage: true }, // 10. 2x1 (Wide - Dark)
{ class: "col-span-2 row-span-1", hasImage: true }, // 11. 2x1
{ class: "col-span-1 row-span-2", hasImage: true }, // 12. 1x2
{ class: "col-span-1 row-span-1 tile-red-glass text-white", hasImage: true }, // 13. 1x1
{ class: "col-span-1 row-span-1", hasImage: false }, // 14. 1x1
{ class: "col-span-1 row-span-1 tile-blue-glass text-white", hasImage: false }, // 15. 1x1
{ class: "col-span-2 row-span-2", hasImage: true }, // 16. 2x2
{ class: "col-span-1 row-span-1", hasImage: false }, // 17. 1x1
{ class: "col-span-1 row-span-1", hasImage: false }, // 18. 1x1
{ class: "col-span-2 row-span-1 tile-dark-glass text-white", hasImage: true }, // 19. 2x1
{ class: "col-span-1 row-span-1", hasImage: false }, // 20. 1x1
];
/**
* 随机打乱数组顺序
* @param {Array<any>} array
*/
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
/**
* 解析 RSS JSON 响应为文章对象数组
* @param {object} jsonResponse - API 返回的 JSON 对象
* @param {string} sourceName - 资讯来源名称 (e.g., '少数派', '爱范儿')
* @returns {Array<{title: string, link: string, summary: string, source: string}>}
*/
function parseFeed(jsonResponse, sourceName) {
const items = jsonResponse.items || [];
const articles = [];
items.forEach((item) => {
const title = item.title || '无标题';
const link = item.link || '#';
// 使用 description 或 content 字段
const description = item.description || item.content || '无描述';
// 提取纯文本并截断
const tempDiv = document.createElement('div');
tempDiv.innerHTML = description;
const plainText = tempDiv.textContent.replace(/[\n\r\t]/g, ' ').trim();
const summary = plainText.substring(0, 150) + (plainText.length > 150 ? '...' : '');
articles.push({ title, link, summary, source: sourceName });
});
return articles;
}
/**
* 动态生成并渲染磁贴
* @param {Array<{title: string, link: string, summary: string, source: string}>} articles
*/
function renderTiles(articles) {
// 注意:这里我们使用容器ID来确保只查找我们这个嵌入块内的 grid-container
const container = document.getElementById('rss-tile-widget-container').querySelector('#grid-container');
if (!container) return;
// 清空加载状态
container.innerHTML = '';
articles.forEach((article, index) => {
const config = TILE_CONFIGS[index];
// 针对不同尺寸的磁贴定制内容结构
let contentHTML = '';
const tileContentClasses = (config.class.includes('text-white') ? 'text-white' : 'text-gray-800');
// 移除 alt 属性中的随机图片占位符,仅使用图片 URL
const imageTag = config.hasImage ? `<img src="${RANDOM_IMAGE_URL}?v=${Math.random()}" class="tile-img" alt="资讯图片" />` : '';
// 根据来源设置分类标签和颜色
let categoryName;
let categoryClass;
let primaryTag;
if (article.source === '少数派') {
categoryName = '效率工具';
categoryClass = 'text-msn-green';
primaryTag = '少数派精选';
} else {
categoryName = '科技快讯';
// 使用紫色的 Tailwind 类来区分爱范儿
categoryClass = 'text-purple-500';
primaryTag = '爱范儿速递';
}
if (config.class.includes('col-span-2 row-span-2')) {
// 2x2 大磁贴 (主标题)
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full relative p-4 flex flex-col justify-end">
<div class="w-full h-full absolute inset-0">
${imageTag.replace('tile-img', 'tile-img opacity-50')}
</div>
<div class="relative z-10">
<p class="text-sm font-light mb-1 opacity-80">${primaryTag}</p>
<h2 class="text-3xl font-extrabold leading-tight line-clamp-3">${article.title}</h2>
<p class="text-sm mt-2 opacity-80 hidden md:block line-clamp-2">${article.summary}</p>
</div>
</a>
`;
} else if (config.class.includes('row-span-2') && config.hasImage) {
// 1x2 窄高磁贴 (图片在上,文字在下)
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full flex flex-col">
<div class="h-1/2 w-full">
${imageTag}
</div>
<div class="p-3 flex flex-col justify-start h-1/2 ${tileContentClasses}">
<p class="text-sm ${categoryClass} font-semibold mb-1">${categoryName}</p>
<h3 class="text-lg font-bold leading-tight line-clamp-3">${article.title}</h3>
</div>
</a>
`;
} else if (config.class.includes('col-span-2') && config.hasImage) {
// 2x1 宽磁贴 (标题和摘要,左侧图片)
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full p-4 flex items-center ${tileContentClasses}">
<div class="flex-shrink-0 w-24 h-full hidden sm:block mr-4 rounded overflow-hidden">
${imageTag}
</div>
<div class="flex-grow">
<p class="text-sm ${categoryClass} font-semibold mb-1">${categoryName}</p>
<h3 class="text-xl font-bold truncate">${article.title}</h3>
<p class="text-sm opacity-80 mt-1 hidden sm:block line-clamp-1">${article.summary}</p>
</div>
</a>
`;
} else {
// 1x1 或无图磁贴 (只有标题/摘要)
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full p-3 ${tileContentClasses}">
<p class="text-xs ${categoryClass} font-semibold mb-1">${article.source}专栏</p>
<h3 class="font-semibold line-clamp-3">${article.title}</h3>
${config.class.includes('row-span-2') ? `<p class="text-sm opacity-80 mt-2 line-clamp-4">${article.summary}</p>` : ''}
</a>
`;
}
const tileDiv = document.createElement('div');
tileDiv.className = `tile ${config.class}`;
tileDiv.innerHTML = contentHTML;
container.appendChild(tileDiv);
});
}
/**
* 启动函数:获取 RSS Feed 并渲染
*/
async function fetchFeed() {
const widgetContainer = document.getElementById('rss-tile-widget-container');
const container = widgetContainer ? widgetContainer.querySelector('#grid-container') : null;
if (container) {
container.innerHTML = '<div class="col-span-4 p-8 text-center text-gray-500"><p>正在加载少数派和爱范儿资讯...</p><div class="mt-4 w-6 h-6 border-4 border-msn-blue border-t-transparent rounded-full animate-spin mx-auto"></div></div>';
} else {
return; // 如果容器不存在,则停止执行
}
try {
// 1. 同时获取两个 RSS Feed
const [sspaiResponse, ifanrResponse] = await Promise.all([
fetch(SSPAI_PROXY_URL),
fetch(IFANR_PROXY_URL),
]);
// 2. 检查响应状态 (使用 console.warn 避免在嵌入环境中显示红色错误)
if (!sspaiResponse.ok) {
console.warn(`[WARNING] SSPAI fetch failed with status ${sspaiResponse.status}. Using fallback.`);
}
if (!ifanrResponse.ok) {
console.warn(`[WARNING] IFANR fetch failed with status ${ifanrResponse.status}. Using fallback.`);
}
// 3. 解析 JSON
const sspaiJson = sspaiResponse.ok ? await sspaiResponse.json() : { status: 'error' };
const ifanrJson = ifanrResponse.ok ? await ifanrResponse.json() : { status: 'error' };
// 4. 解析文章
const sspaiArticles = sspaiJson.status === 'ok' ? parseFeed(sspaiJson, '少数派') : [];
const ifanrArticles = ifanrJson.status === 'ok' ? parseFeed(ifanrJson, '爱范儿') : [];
// 5. 合并、打乱并限制数量
let allArticles = shuffleArray([...sspaiArticles, ...ifanrArticles]);
if (allArticles.length === 0) {
throw new Error('两个 RSS Feed 内容均为空或无法解析。');
}
// 限制文章数量以匹配磁贴配置
allArticles = allArticles.slice(0, TILE_CONFIGS.length);
// 6. 渲染
renderTiles(allArticles);
} catch (error) {
console.error("Failed to fetch or parse RSS feed:", error);
if (container) {
container.innerHTML =
'<div class="col-span-4 p-8 text-center text-red-600 bg-red-100 rounded-lg">' +
'<p class="font-bold mb-2">资讯加载失败</p>' +
`错误信息: ${error.message}` +
'<p class="mt-2 text-sm">请检查 RSS 源是否可用,或代理服务是否正常工作。</p>' +
'</div>';
}
}
}
// 确保在整个嵌入容器加载完成后运行
document.addEventListener('DOMContentLoaded', fetchFeed);
</script>
</div>
动态磁贴 RSS订阅 嵌入式代码 2
<div id="rss-tile-widget-container" class="wp-embed-container my-4">
<!-- 引入 Tailwind CSS CDN -->
<script src="https://cdn.tailwindcss.com"></script>
<style>
/* 确保中文字体优先 */
@import url('https://fonts.googleapis.com/css2?family=Inter:[email protected]&display=swap');
/* ----------------------------------------------------------- */
/* 关键:防止样式泄露的隔离和重置,使用 !important 提高优先级 */
/* ----------------------------------------------------------- */
/* 强制重置所有子元素的 box-sizing, margin, padding,防止被 WordPress 主题继承 */
#rss-tile-widget-container * {
box-sizing: border-box !important;
margin: 0 !important;
padding: 0 !important;
line-height: normal !important;
text-decoration: none !important; /* 清除链接下划线 */
}
/* 确保内部 <main> 元素能够正确居中和间距 */
#rss-tile-widget-container main {
padding: 1rem !important;
margin-left: auto !important;
margin-right: auto !important;
max-width: 80rem !important; /* 匹配 max-w-7xl */
}
/* ----------------------------------------------------------- */
/* 定义磁贴的基本样式和交互效果,仅对容器内的元素生效 */
/* ----------------------------------------------------------- */
#rss-tile-widget-container .tile {
/* 默认深色磨砂玻璃背景 (Apple Dark Mode 风格) */
background-color: rgba(30, 30, 30, 0.8) !important; /* 提高不透明度 */
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.15) !important; /* 增强边框可见性 */
color: #f3f4f6 !important; /* 默认浅色字体 (text-gray-100) */
border-radius: 10px !important; /* 略微更圆润的边缘 */
/* 增强阴影,增加深度感 */
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.4) !important;
transition: transform 0.2s, box-shadow 0.2s !important;
cursor: pointer !important;
overflow: hidden !important;
display: flex !important;
flex-direction: column !important;
font-family: 'Inter', 'Noto Sans SC', sans-serif !important;
text-decoration: none !important;
}
#rss-tile-widget-container .tile:hover {
transform: translateY(-4px) !important; /* 更明显的悬停提升 */
box-shadow: 0 8px 20px rgba(0, 0, 0, 0.5) !important; /* 更深的悬停阴影 */
}
/* 强制图片占满空间并保持纵横比 */
#rss-tile-widget-container .tile-img {
width: 100% !important;
height: 100% !important;
object-fit: cover !important;
}
/* Specific styles for colored tiles to maintain theme but allow glass effect */
#rss-tile-widget-container .tile-blue-glass {
background-color: rgba(0, 120, 212, 0.75) !important;
}
#rss-tile-widget-container .tile-red-glass {
background-color: rgba(216, 59, 1, 0.75) !important;
}
#rss-tile-widget-container .tile-dark-glass {
background-color: rgba(55, 65, 81, 0.75) !important;
}
/* 确保内部链接的颜色是继承的白色,并且没有下划线 */
#rss-tile-widget-container a {
color: inherit !important;
text-decoration: none !important;
}
</style>
<script>
// 重新配置 Tailwind 颜色,以便在嵌入环境中生效
tailwind.config = {
theme: {
extend: {
colors: {
'msn-blue': '#0078D4', /* 典型的 Microsoft 蓝 */
'msn-green': '#107C10',
'msn-red': '#D83B01',
}
}
}
}
</script>
<!-- 磁贴主布局 -->
<main class="max-w-7xl mx-auto p-4">
<!--
使用 CSS Grid 创建磁贴布局
添加 grid-flow-row-dense (grid-auto-flow: dense) 确保磁贴紧凑排列,不留空隙。
-->
<div id="grid-container" class="grid grid-cols-2 md:grid-cols-4 gap-4 auto-rows-[120px] md:auto-rows-[160px] grid-flow-row-dense">
<!-- 初始加载状态 -->
<div class="col-span-4 p-8 text-center text-gray-400">
<p>正在加载少数派和爱范儿资讯...</p>
<div class="mt-4 w-6 h-6 border-4 border-msn-blue border-t-transparent rounded-full animate-spin mx-auto"></div>
</div>
</div>
</main>
<script>
// RSS Feed URL 1 (少数派)
const SSPAI_FEED_URL = "https://sspai.com/feed";
const SSPAI_PROXY_URL = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(SSPAI_FEED_URL)}`;
// RSS Feed URL 2 (爱范儿)
const IFANR_FEED_URL = "https://www.ifanr.com/feed";
const IFANR_PROXY_URL = `https://api.rss2json.com/v1/api.json?rss_url=${encodeURIComponent(IFANR_FEED_URL)}`;
// 随机图片 API URL
const RANDOM_IMAGE_URL = 'https://www.dmoe.cc/random.php';
// 预定义的磁贴大小和样式 (共 20 个配置)
const TILE_CONFIGS = [
{ class: "col-span-2 row-span-2 tile-blue-glass", hasImage: true }, // 1. 2x2 (Primary)
{ class: "col-span-2 row-span-1", hasImage: true }, // 2. 2x1 (Wide)
{ class: "col-span-1 row-span-1 tile-red-glass", hasImage: false }, // 3. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: false }, // 4. 1x1 (Small)
{ class: "col-span-1 row-span-2", hasImage: true }, // 5. 1x2 (Tall)
{ class: "col-span-1 row-span-1", hasImage: false }, // 6. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: false }, // 7. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: false }, // 8. 1x1 (Small)
{ class: "col-span-1 row-span-1", hasImage: true }, // 9. 1x1 (Small)
{ class: "col-span-2 row-span-1 tile-dark-glass", hasImage: true }, // 10. 2x1 (Wide - Dark)
{ class: "col-span-2 row-span-1", hasImage: true }, // 11. 2x1
{ class: "col-span-1 row-span-2", hasImage: true }, // 12. 1x2
{ class: "col-span-1 row-span-1 tile-red-glass", hasImage: true }, // 13. 1x1
{ class: "col-span-1 row-span-1", hasImage: false }, // 14. 1x1
{ class: "col-span-1 row-span-1 tile-blue-glass", hasImage: false }, // 15. 1x1
{ class: "col-span-2 row-span-2", hasImage: true }, // 16. 2x2
{ class: "col-span-1 row-span-1", hasImage: false }, // 17. 1x1
{ class: "col-span-1 row-span-1", hasImage: false }, // 18. 1x1
{ class: "col-span-2 row-span-1 tile-dark-glass", hasImage: true }, // 19. 2x1
{ class: "col-span-1 row-span-1", hasImage: false }, // 20. 1x1
];
/**
* 随机打乱数组顺序
* @param {Array<any>} array
*/
function shuffleArray(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
/**
* 解析 RSS JSON 响应为文章对象数组
* @param {object} jsonResponse - API 返回的 JSON 对象
* @param {string} sourceName - 资讯来源名称 (e.g., '少数派', '爱范儿')
* @returns {Array<{title: string, link: string, summary: string, source: string}>}
*/
function parseFeed(jsonResponse, sourceName) {
const items = jsonResponse.items || [];
const articles = [];
items.forEach((item) => {
const title = item.title || '无标题';
const link = item.link || '#';
// 使用 description 或 content 字段
const description = item.description || item.content || '无描述';
// 提取纯文本并截断
const tempDiv = document.createElement('div');
tempDiv.innerHTML = description;
const plainText = tempDiv.textContent.replace(/[\n\r\t]/g, ' ').trim();
const summary = plainText.substring(0, 150) + (plainText.length > 150 ? '...' : '');
articles.push({ title, link, summary, source: sourceName });
});
return articles;
}
/**
* 动态生成并渲染磁贴
* @param {Array<{title: string, link: string, summary: string, source: string}>} articles
*/
function renderTiles(articles) {
// 注意:这里我们使用容器ID来确保只查找我们这个嵌入块内的 grid-container
const container = document.getElementById('rss-tile-widget-container').querySelector('#grid-container');
if (!container) return;
// 清空加载状态
container.innerHTML = '';
articles.forEach((article, index) => {
const config = TILE_CONFIGS[index];
// 针对不同尺寸的磁贴定制内容结构
let contentHTML = '';
const imageTag = config.hasImage ? `<img src="${RANDOM_IMAGE_URL}?v=${Math.random()}" class="tile-img" alt="资讯图片" />` : '';
// 根据来源设置分类标签和颜色
let categoryName;
let categoryClass;
let primaryTag;
if (article.source === '少数派') {
categoryName = '效率工具';
categoryClass = 'text-msn-green';
primaryTag = '少数派精选';
} else {
categoryName = '科技快讯';
// 使用紫色的 Tailwind 类来区分爱范儿
categoryClass = 'text-purple-400';
primaryTag = '爱范儿速递';
}
// 所有磁贴现在默认继承浅色字体
const defaultTextColor = 'text-gray-100';
if (config.class.includes('col-span-2 row-span-2')) {
// 2x2 大磁贴 (主标题)
// 调整字体大小为 4xl, 摘要为 base
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full relative p-4 flex flex-col justify-end ${defaultTextColor}">
<div class="w-full h-full absolute inset-0">
${imageTag.replace('tile-img', 'tile-img opacity-50')}
</div>
<div class="relative z-10">
<p class="text-sm font-light mb-1 opacity-80">
<span class="${categoryClass}">${primaryTag}</span>
</p>
<h2 class="text-4xl font-extrabold leading-tight line-clamp-3">${article.title}</h2>
<p class="text-base mt-2 opacity-80 hidden md:block line-clamp-2">${article.summary}</p>
</div>
</a>
`;
} else if (config.class.includes('row-span-2') && config.hasImage) {
// 1x2 窄高磁贴 (图片在上,文字在下)
// 调整字体大小为 xl
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full flex flex-col ${defaultTextColor}">
<div class="h-1/2 w-full">
${imageTag}
</div>
<div class="p-3 flex flex-col justify-start h-1/2">
<p class="text-sm ${categoryClass} font-semibold mb-1">${categoryName}</p>
<h3 class="text-xl font-bold leading-tight line-clamp-3">${article.title}</h3>
</div>
</a>
`;
} else if (config.class.includes('col-span-2') && config.hasImage) {
// 2x1 宽磁贴 (标题和摘要,左侧图片)
// 调整字体大小为 2xl, 摘要为 base
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full p-4 flex items-center ${defaultTextColor}">
<div class="flex-shrink-0 w-24 h-full hidden sm:block mr-4 rounded overflow-hidden">
${imageTag}
</div>
<div class="flex-grow">
<p class="text-sm ${categoryClass} font-semibold mb-1">${categoryName}</p>
<h3 class="text-2xl font-bold truncate">${article.title}</h3>
<p class="text-base opacity-80 mt-1 hidden sm:block line-clamp-1">${article.summary}</p>
</div>
</a>
`;
} else {
// 1x1 或无图磁贴 (只有标题/摘要)
// 调整字体大小为 sm/base
contentHTML = `
<a href="${article.link}" target="_blank" class="block w-full h-full p-3 ${defaultTextColor}">
<p class="text-sm ${categoryClass} font-semibold mb-1">${article.source}专栏</p>
<h3 class="font-bold line-clamp-3">${article.title}</h3>
${config.class.includes('row-span-2') ? `<p class="text-base opacity-80 mt-2 line-clamp-4">${article.summary}</p>` : ''}
</a>
`;
}
const tileDiv = document.createElement('div');
tileDiv.className = `tile ${config.class}`;
tileDiv.innerHTML = contentHTML;
container.appendChild(tileDiv);
});
}
/**
* 启动函数:获取 RSS Feed 并渲染
*/
async function fetchFeed() {
const widgetContainer = document.getElementById('rss-tile-widget-container');
const container = widgetContainer ? widgetContainer.querySelector('#grid-container') : null;
if (container) {
// 确保加载文字和旋转图标在新的深色背景下可见
container.innerHTML = '<div class="col-span-4 p-8 text-center text-gray-400"><p>正在加载少数派和爱范儿资讯...</p><div class="mt-4 w-6 h-6 border-4 border-msn-blue border-t-transparent rounded-full animate-spin mx-auto"></div></div>';
} else {
return; // 如果容器不存在,则停止执行
}
try {
// 1. 同时获取两个 RSS Feed
const [sspaiResponse, ifanrResponse] = await Promise.all([
fetch(SSPAI_PROXY_URL),
fetch(IFANR_PROXY_URL),
]);
// 2. 检查响应状态 (使用 console.warn 避免在嵌入环境中显示红色错误)
if (!sspaiResponse.ok) {
console.warn(`[WARNING] SSPAI fetch failed with status ${sspaiResponse.status}. Using fallback.`);
}
if (!ifanrResponse.ok) {
console.warn(`[WARNING] IFANR fetch failed with status ${ifanrResponse.status}. Using fallback.`);
}
// 3. 解析 JSON
const sspaiJson = sspaiResponse.ok ? await sspaiResponse.json() : { status: 'error' };
const ifanrJson = ifanrResponse.ok ? await ifanrResponse.json() : { status: 'error' };
// 4. 解析文章
const sspaiArticles = sspaiJson.status === 'ok' ? parseFeed(sspaiJson, '少数派') : [];
const ifanrArticles = ifanrJson.status === 'ok' ? parseFeed(ifanrJson, '爱范儿') : [];
// 5. 合并、打乱并限制数量
let allArticles = shuffleArray([...sspaiArticles, ...ifanrArticles]);
if (allArticles.length === 0) {
throw new Error('两个 RSS Feed 内容均为空或无法解析。');
}
// 限制文章数量以匹配磁贴配置
allArticles = allArticles.slice(0, TILE_CONFIGS.length);
// 6. 渲染
renderTiles(allArticles);
} catch (error) {
console.error("Failed to fetch or parse RSS feed:", error);
if (container) {
container.innerHTML =
'<div class="col-span-4 p-8 text-center text-red-400 bg-red-900/50 rounded-lg">' +
'<p class="font-bold mb-2">资讯加载失败</p>' +
`错误信息: ${error.message}` +
'<p class="mt-2 text-sm">请检查 RSS 源是否可用,或代理服务是否正常工作。</p>' +
'</div>';
}
}
}
// 确保在整个嵌入容器加载完成后运行
document.addEventListener('DOMContentLoaded', fetchFeed);
</script>
</div>



