Commit f934277
Changed files (4)
src
components
user
content
posts
plugins
src/components/user/index.ts
@@ -1,4 +1,5 @@
export { default as Collapse } from './Collapse.astro';
+export { default as LinkCard } from './LinkCard.astro';
export { default as Repl } from './Repl.astro';
export { default as RepoCard } from './RepoCard.astro';
export { default as Tabs } from './Tabs.astro';
src/components/user/LinkCard.astro
@@ -0,0 +1,23 @@
+---
+import { Icon } from 'astro-icon/components';
+
+interface Props {
+ title: string;
+ description: string;
+ url: string;
+}
+
+let { title, description, url } = Astro.props;
+---
+
+<a href={url} title={title} class="card border-base-content/25 my-4 overflow-hidden border">
+ <div class="card-body flex flex-row items-center justify-between p-4">
+ <div>
+ <div class="card-title">
+ {title}
+ </div>
+ <div class="card-desc text-base-content/50">{description}</div>
+ </div>
+ <Icon name="material-symbols:arrow-right-alt-rounded" class="text-3xl" />
+ </div>
+</a>
src/content/posts/components.mdx
@@ -9,7 +9,7 @@ tags:
published: 2025-02-10T21:23:23+08:00
---
-import { Collapse, Repl, RepoCard, TabItem, Tabs, Tooltip } from '@components/user';
+import { Collapse, LinkCard, Repl, RepoCard, TabItem, Tabs, Tooltip } from '@components/user';
Components let you easily reuse a piece of UI or styling consistently. You can use them not just in `.astro` files, but also in `.mdx` files.
@@ -203,4 +203,42 @@ Components let you easily reuse a piece of UI or styling consistently. You can u
<RepoCard repo="withastro/astro" platform='github' />
```
</Fragment>
+</Repl>
+
+### LinkCard
+<Repl>
+ <LinkCard
+ title="Astral Halo"
+ description="A static blog template developed with Astro"
+ url="https://github.com/HPCesia/astral-halo"
+ />
+ <LinkCard
+ title="Astro"
+ description="The all-in-one web framework designed for speed."
+ url="https://astro.build/"
+ />
+ <Fragment slot="desc">
+ <Tabs>
+ <TabItem label="mdx" active>
+ ```jsx
+ <LinkCard
+ title="Astral Halo"
+ description="A static blog template developed with Astro"
+ url="https://github.com/HPCesia/astral-halo"
+ />
+ <LinkCard
+ title="Astro"
+ description="The all-in-one web framework designed for speed."
+ url="https://astro.build/"
+ />
+ ```
+ </TabItem>
+ <TabItem label="md">
+ ```md
+ ::linkcard{title="Astral Halo" description="A static blog template developed with Astro" url="https://github.com/HPCesia/astral-halo"}
+ ::linkcard{title="Astro" description="The all-in-one web framework designed for speed." url="https://astro.build/"}
+ ```
+ </TabItem>
+ </Tabs>
+ </Fragment>
</Repl>
\ No newline at end of file
src/plugins/rehype-components-list.ts
@@ -1,6 +1,8 @@
/**
* All components in this file should sync with the components in `src/components/user`
*/
+import { icons as MaterialSymbols } from '@iconify-json/material-symbols';
+import { getIconData, iconToHTML, iconToSVG } from '@iconify/utils';
import { h } from 'hastscript';
import type { Child } from 'hastscript';
@@ -26,6 +28,39 @@ const Collapse = function (
return h('div', { class: wrapperClassName }, [inputNode, titleNode, contentNode]);
};
+const LinkCard = function (props: { title: string; description: string; url: string }) {
+ const { title, description, url } = props;
+ const wrapperClassName = 'card border-base-content/25 my-4 overflow-hidden border';
+ const bodyClassName = 'card-body flex flex-row items-center justify-between p-4';
+ const titleClassName = 'card-title';
+ const descClassName = 'card-desc text-base-content/50';
+
+ const titleNode = h('div', { class: titleClassName }, title);
+ const descNode = h('div', { class: descClassName }, description);
+ const contentNode = h('div', null, [titleNode, descNode]);
+
+ const iconData = getIconData(MaterialSymbols, 'arrow-right-alt-rounded');
+ if (!iconData) {
+ console.error('LinkCard icon not found: material-symbols:arrow-right-alt-rounded');
+ return h('a', { class: wrapperClassName, href: url, title }, 'Link card error');
+ }
+ const { attributes, body } = iconToSVG(iconData);
+ const iconHtml = iconToHTML(body, attributes);
+ const iconNode = h(
+ 'span',
+ {
+ class: 'text-3xl',
+ },
+ {
+ type: 'raw',
+ value: iconHtml,
+ }
+ );
+ const bodyNode = h('div', { class: bodyClassName }, [contentNode, iconNode]);
+
+ return h('a', { class: wrapperClassName, href: url, title }, bodyNode);
+};
+
const Tooltip = function (
props: {
tip: string;
@@ -38,4 +73,8 @@ const Tooltip = function (
return h('div', { class: wrapperClassName, 'data-tip': tip }, children);
};
-export const rehypeComponentsList = { collapse: Collapse, tooltip: Tooltip };
+export const rehypeComponentsList = {
+ collapse: Collapse,
+ linkcard: LinkCard,
+ tooltip: Tooltip,
+};