1059 字
5 分钟
给你的Fuwari加一个链接大卡片
🤖AI 摘要
fishcpy AI
25.8.26更新
更改了部分UI
TIP由于我没有实力,本篇文章修改文件部分为AI所写
CAUTION修改文件前请注意备份,防止修改失败无法回退
前言
今天在看liushen大佬文章时看到了个大卡片效果,感觉挺好看的,于是让AI给我加上了
清羽飞扬
循一缕风,入山偷得夏日凉
示例
自定义标题和描述
::link-card{url="https://www.fis.ink" title="fishcpy的主页" description="fishcpy的个人主页"}
fishcpy的主页
fishcpy的个人主页
带图片的链接卡片
::link-card{url="https://www.fis.ink" title="fishcpy的主页" description="fishcpy的个人主页" icon="https://github.com/github.png"}
fishcpy的主页
fishcpy的个人主页

自定义图标的链接卡片
::link-card{url="https://www.fis.ink" title="fishcpy的主页" description="fishcpy的个人主页" icon="https://www.fis.ink/img/logo.png"}
fishcpy的主页
fishcpy的个人主页
最终效果
::link-card{url="https://www.fis.ink" title="fishcpy的主页" description="fishcpy的个人主页" icon="https://www.fis.ink/img/logo.png" image="https://www.fis.ink/img/logo.png"}
fishcpy的主页
fishcpy的个人主页

添加教程
再次提示
TIP由于我没有实力,下方内容为AI所写
CAUTION修改文件前请注意备份,防止修改失败无法回退
1. 创建组件文件
首先,在 src/plugins/
目录下创建 rehype-component-link-card.mjs
文件:
/// <reference types="mdast" />import { h } from "hastscript";
/** * Creates a Link Card component for third-party links. */export function LinkCardComponent(properties, children) { if (Array.isArray(children) && children.length !== 0) return h("div", { class: "hidden" }, [ 'Invalid directive. ("link-card" directive must be leaf type "::link-card{url="https://example.com"}"))', ]);
if (!properties.url || !properties.url.startsWith('http')) return h( "div", { class: "hidden" }, 'Invalid URL. ("url" attribute must be a valid HTTP/HTTPS URL)', );
const url = properties.url; const customTitle = properties.title; const customDescription = properties.description; const customImage = properties.image; const customIcon = properties.icon; const cardUuid = `LC${Math.random().toString(36).slice(-6)}`;
// Extract domain from URL for display const domain = new URL(url).hostname;
// Use custom icon if provided, otherwise use Google favicon service const iconUrl = customIcon || `https://www.google.com/s2/favicons?domain=${domain}&sz=32`; const nFavicon = h(`div#${cardUuid}-favicon`, { class: "lc-favicon", style: `background-image: url(${iconUrl})` });
// 隐藏域名显示的标题栏 const nTitle = h("div", { class: "lc-titlebar" }, [ h("div", { class: "lc-titlebar-left" }, [ // h("div", { class: "lc-site" }, domain), // 已注释掉域名显示 ]), h("div", { class: "lc-external-icon" }), ]);
const nCardTitle = h( `div#${cardUuid}-title`, { class: "lc-card-title" }, customTitle || "Link", );
const nDescription = h( `div#${cardUuid}-description`, { class: "lc-description" }, customDescription || "Click to visit", );
const nImage = h( `div#${cardUuid}-image`, { class: "lc-image" }, customImage ? h("img", { src: customImage, alt: "Link preview" }) : null );
// Only fetch metadata if custom data is not provided const needsFetch = !customTitle || !customDescription;
const nScript = needsFetch ? h( `script#${cardUuid}-script`, { type: "text/javascript", defer: true }, ` // Simple metadata extraction for link cards try { const cardElement = document.getElementById('${cardUuid}-card'); const titleElement = document.getElementById('${cardUuid}-title'); const descElement = document.getElementById('${cardUuid}-description');
// Set default values if custom ones weren't provided if (!titleElement.dataset.hasCustomTitle) { titleElement.innerText = 'Link'; } if (!descElement.dataset.hasCustomDesc) { descElement.innerText = 'Click to visit'; }
cardElement.classList.remove("fetch-waiting"); console.log("[LINK-CARD] Loaded card for ${url} | ${cardUuid}."); } catch (err) { const c = document.getElementById('${cardUuid}-card'); c?.classList.add("fetch-error"); console.warn("[LINK-CARD] (Error) Loading card for ${url} | ${cardUuid}."); } `, ) : null;
// Set data attributes for custom content if (customTitle) { nCardTitle.properties['data-has-custom-title'] = 'true'; } if (customDescription) { nDescription.properties['data-has-custom-desc'] = 'true'; }
const cardContent = [ nTitle, nCardTitle, nDescription, ];
if (customImage) { cardContent.push(nImage); }
if (nScript) { cardContent.push(nScript); }
return h( `a#${cardUuid}-card`, { class: needsFetch ? "card-link fetch-waiting no-styling" : "card-link no-styling", href: url, target: "_blank", rel: "noopener noreferrer", 'data-url': url, }, cardContent, );}
2. 添加CSS样式
在 src/styles/markdown-extend.styl
文件中添加以下样式:
// Link Card Stylesa.card-link display: block text-decoration: none border: 1px solid var(--line-divider) border-radius: 8px padding: 16px margin: 16px 0 background-color: var(--card-bg) transition: all 0.2s ease position: relative overflow: hidden color: inherit
&:hover background-color: var(--btn-regular-bg-hover)
.lc-titlebar .lc-external-icon opacity: 1
&:active transform: translateY(0) box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1)
// 隐藏标题栏以移除域名显示和空白区域 .lc-titlebar display: none
.lc-titlebar-left display: flex align-items: center
.lc-site display: flex align-items: center gap: 8px
.lc-favicon width: 16px height: 16px background-size: contain background-repeat: no-repeat background-position: center flex-shrink: 0
.lc-domain font-size: 14px color: var(--text-color-secondary) font-weight: 500
.lc-external-icon width: 16px height: 16px opacity: 0.6 transition: opacity 0.2s ease background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path><polyline points="15,3 21,3 21,9"></polyline><line x1="10" y1="14" x2="21" y2="3"></line></svg>') background-size: contain background-repeat: no-repeat background-position: center
.lc-card-title font-size: 18px font-weight: 600 color: var(--text-color-primary) margin-bottom: 8px line-height: 1.3
.lc-description font-size: 14px color: var(--text-color-secondary) line-height: 1.4 margin-bottom: 12px
// 移除图片上方的空白区域 .lc-image margin-top: 0
img width: 100% max-height: 200px object-fit: cover border-radius: 4px
&.fetch-waiting .lc-card-title, .lc-description animation: pulse 1.5s ease-in-out infinite
&.fetch-error border-color: var(--error-color) background-color: var(--error-bg)
@keyframes pulse 0%, 100% opacity: 1 50% opacity: 0.5
3. 配置Astro
在 astro.config.mjs
文件中导入组件并注册:
// 添加导入import { LinkCardComponent } from "./src/plugins/rehype-component-link-card.mjs";
// 在 rehypeComponents 配置中添加rehypeComponents,{ components: { github: GithubCardComponent, "link-card": LinkCardComponent, // 添加这一行 note: (x, y) => AdmonitionComponent(x, y, "note"), // ... 其他组件 },},
4. 使用方法
配置完成后,你就可以在Markdown文件中使用链接卡片了:
// 基本用法::link-card{url="https://example.com"}
// 自定义标题和描述::link-card{url="https://github.com" title="GitHub" description="代码托管平台"}
// 带自定义图片::link-card{url="https://vercel.com" title="Vercel" description="部署平台" image="https://example.com/image.png"}
// 自定义图标::link-card{url="https://github.com" title="GitHub" description="代码托管平台" icon="https://github.com/favicon.ico"}
5. 注意事项
- 确保URL以
http://
或https://
开头 - 自定义图片建议使用合适的尺寸和格式
现在你的博客就拥有了美观的第三方链接大卡片功能!