Commit 4687c9a
Changed files (8)
src
content
spec
i18n
pages
types
src/content/spec/links.md
@@ -0,0 +1,12 @@
+---
+title: Links
+---
+
+
+## Lorem
+
+Lorem ipsum dolor sit amet, consectetur adipiscing elit.
+
+## Ipsum
+
+Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
\ No newline at end of file
src/i18n/langs/en.ts
@@ -6,6 +6,7 @@ export const en: Translation = {
[Key.about]: 'About',
[Key.archive]: 'Archive',
[Key.search]: 'Search',
+ [Key.links]: 'Links',
[Key.tags]: 'Tags',
[Key.categories]: 'Categories',
src/i18n/langs/zh_CN.ts
@@ -6,6 +6,7 @@ export const zh_CN: Translation = {
[Key.about]: '关于',
[Key.archive]: '归档',
[Key.search]: '搜索',
+ [Key.links]: '友链',
[Key.tags]: '标签',
[Key.categories]: '分类',
src/i18n/langs/zh_TW.ts
@@ -6,6 +6,7 @@ export const zh_TW: Translation = {
[Key.about]: '關於',
[Key.archive]: '彙整',
[Key.search]: '搜尋',
+ [Key.links]: '連結',
[Key.tags]: '標籤',
[Key.categories]: '分類',
src/i18n/I18nKey.ts
@@ -3,6 +3,7 @@ enum I18nKey {
about = 'about',
archive = 'archive',
search = 'search',
+ links = 'links',
tags = 'tags',
categories = 'categories',
src/pages/links.astro
@@ -0,0 +1,83 @@
+---
+import { linksConfig } from '@/config';
+import PostInfo from '@components/misc/PostInfo.astro';
+import ImageWrapper from '@components/utils/ImageWrapper.astro';
+import Markdown from '@components/utils/Markdown.astro';
+import I18nKey from '@i18n/I18nKey';
+import { i18n } from '@i18n/translation';
+import PostPageLayout from '@layouts/PostPageLayout.astro';
+import { getEntry, render } from 'astro:content';
+
+const linksMd = await getEntry('spec', 'links');
+const groupHeadings = linksConfig.items.map((item) => ({
+ depth: 2,
+ slug: `links-group-${item.groupName.toLowerCase().replace(/\s/g, '-')}`,
+ text: item.groupName,
+}));
+const { Content, headings } = linksMd
+ ? await render(linksMd)
+ : { Content: Fragment, headings: [] };
+---
+
+<PostPageLayout
+ title={i18n(I18nKey.links) as string}
+ comment={linksMd?.data.comment}
+ headings={[...groupHeadings, ...headings]}
+>
+ <Fragment slot="header-content">
+ <PostInfo title={i18n(I18nKey.links) as string} />
+ </Fragment>
+ {
+ linksConfig.items.map((item) => (
+ <Fragment>
+ <h2
+ class="mt-4 mb-1 flex items-baseline justify-between gap-4 text-2xl font-bold"
+ id={`links-group-${item.groupName.toLowerCase().replace(/\s/g, '-')}`}
+ >
+ {item.groupName}
+ {item.groupDescription && (
+ <span class="text-base-content/60 line-clamp-1 text-sm font-medium">
+ {item.groupDescription}
+ </span>
+ )}
+ </h2>
+ <hr class="text-base-content/25 my-1" />
+ <div class="flex flex-wrap">
+ {item.groupItems.map((item) => (
+ <div class="card bg-base-200 max-md:card-side m-1 w-full md:w-[calc(25%-calc(var(--spacing)*2))] lg:w-[calc(20%-calc(var(--spacing)*2))]">
+ <figure class="min-w-23">
+ <a
+ href={item.url}
+ target="_blank"
+ rel="noopener noreferrer"
+ class="w-fit"
+ title={item.name}
+ >
+ <ImageWrapper src={item.avatar} class="max-md:w-23" />
+ </a>
+ </figure>
+ <div class="card-body px-4 py-2">
+ <a
+ href={item.url}
+ target="_blank"
+ rel="noopener noreferrer"
+ class="w-fit"
+ title={item.name}
+ >
+ <h3 class="card-title line-clamp-1">{item.name}</h3>
+ </a>
+ {item.description && (
+ <p class="text-base-content/60 line-clamp-2 text-sm">{item.description}</p>
+ )}
+ </div>
+ </div>
+ ))}
+ </div>
+ </Fragment>
+ ))
+ }
+ <hr class="text-base-content/25 mt-8" />
+ <Markdown>
+ <Content />
+ </Markdown>
+</PostPageLayout>
src/types/config.ts
@@ -225,6 +225,59 @@ export type ProfileConfig = {
}[];
};
+export type LinksConfig = {
+ /**
+ * The items displayed in the links.
+ *
+ * 在友情链接中显示的项目。
+ */
+ items: {
+ /**
+ * The name of the group.
+ *
+ * 组的名称。
+ */
+ groupName: string;
+ /**
+ * The description of the group.
+ *
+ * 组的描述。
+ */
+ groupDescription?: string;
+ /**
+ * The items displayed in the group.
+ *
+ * 在组中显示的项目。
+ */
+ groupItems: {
+ /**
+ * The name of the link.
+ *
+ * 链接的名称。
+ */
+ name: string;
+ /**
+ * The URL of the link.
+ *
+ * 链接的 URL。
+ */
+ url: string;
+ /**
+ * The avatar of the link.
+ *
+ * 链接的头像。
+ */
+ avatar: string;
+ /**
+ * The description of the link.
+ *
+ * 链接的描述。
+ */
+ description?: string;
+ }[];
+ }[];
+};
+
export type NavbarConfig = {
/**
* The items displayed in the center of the navbar.
src/config.ts
@@ -4,6 +4,7 @@ import type {
CommentConfig,
FooterConfig,
LicenseConfig,
+ LinksConfig,
NavbarConfig,
ProfileConfig,
SearchConfig,
@@ -41,7 +42,7 @@ export const profileConfig: ProfileConfig = {
avatar: 'assets/img/avatar.jpg',
name: 'Lorem Ipsum',
bio: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
- links: [
+ socialLinks: [
{
name: 'GitHub',
url: 'https://github.com/example',
@@ -55,11 +56,31 @@ export const profileConfig: ProfileConfig = {
],
};
+export const linksConfig: LinksConfig = {
+ items: [
+ {
+ groupName: 'Lorem Ipsum',
+ groupDescription: 'Lorem ipsum dolor sit amet.',
+ groupItems: [
+ { name: 'Item 1', url: 'https://example.com', avatar: 'assets/img/avatar.jpg' },
+ {
+ name: 'Item 2',
+ url: 'https://example.com',
+ avatar: 'assets/img/avatar.jpg',
+ description: 'Lorem ipsum dolor sit amet.',
+ },
+ { name: 'Item 3', url: 'https://example.com', avatar: 'assets/img/avatar.jpg' },
+ ],
+ },
+ ],
+};
+
export const navbarConfig: NavbarConfig = {
navbarCenterItems: [
{ text: I18nKey.archive, href: '/archives/' },
{ text: I18nKey.categories, href: '/archives/categories/' },
{ text: I18nKey.tags, href: '/archives/tags/' },
+ { text: I18nKey.links, href: '/links/' },
{ text: I18nKey.about, href: '/about/' },
],
navbarRightItems: {