Commit 05e975c

HPCesia <me@hpcesia.com>
2025-09-03 08:46:16
refactor: extract meta list
1 parent f93369a
Changed files (6)
src/components/misc/PostInfo.astro
@@ -1,6 +1,6 @@
 ---
 import { articleConfig, siteConfig } from '@/config';
-import MetaIcon from '@components/widgets/MetaIcon.astro';
+import { default as MetaList, type MetaItem } from '@components/widgets/MetaList.astro';
 import { getCategoryUrl, getTagUrl } from '@utils/content-utils';
 import { t } from '@utils/i18n';
 import type { HTMLAttributes } from 'astro/types';
@@ -28,16 +28,7 @@ const {
   ...rest
 } = Astro.props;
 
-interface MetaInfo {
-  text: string;
-  link?: string;
-  time?: Date;
-}
-
-const metas: (
-  | ({ icon: string; title?: string } & (MetaInfo | { group: MetaInfo[] }))
-  | undefined
-)[] = [
+const metas: MetaItem[] = [
   publishedAt && {
     icon: 'material-symbols:calendar-clock-outline-rounded',
     title: t.meta.publishedAt(),
@@ -81,43 +72,5 @@ const metas: (
 
 <div id="post-info" class:list={['flex flex-col max-md:px-3', className]} {...rest}>
   <h1 class="text-3xl font-bold">{title}</h1>
-  {
-    metas.filter((item) => Boolean(item)).length > 0 && (
-      <div id="post-meta" class="mt-4 flex flex-wrap gap-3">
-        {metas.map((meta) => {
-          return (
-            meta && (
-              <div class="flex flex-wrap items-center gap-1">
-                <MetaIcon name={meta.icon} title={meta.title} aria-label={meta.title} />
-                {(() => {
-                  const process = (info: MetaInfo) => {
-                    const text = info.time ? (
-                      <time datetime={info.time?.toISOString()}>{info.text}</time>
-                    ) : (
-                      <span>{info.text}</span>
-                    );
-                    return info.link ? (
-                      <a href={info.link} title={info.text} class="link-hover not-hover:link">
-                        {text}
-                      </a>
-                    ) : (
-                      text
-                    );
-                  };
-                  if ('group' in meta) {
-                    return meta.group
-                      .map(process)
-                      .flatMap((item, index, arr) =>
-                        index === arr.length - 1 ? [item] : [item, '/']
-                      );
-                  }
-                  return process(meta);
-                })()}
-              </div>
-            )
-          );
-        })}
-      </div>
-    )
-  }
+  <MetaList metas={metas} />
 </div>
src/components/widgets/MetaList.astro
@@ -0,0 +1,63 @@
+---
+import MetaIcon from '@components/widgets/MetaIcon.astro';
+import type { HTMLAttributes } from 'astro/types';
+
+interface MetaInfo {
+  text: string;
+  link?: string;
+  time?: Date;
+}
+
+interface MetaIconInfo {
+  icon: string;
+  title?: string;
+}
+
+export type MetaItem = (MetaIconInfo & (MetaInfo | { group: MetaInfo[] })) | undefined;
+
+interface Props extends HTMLAttributes<'div'> {
+  metas: MetaItem[];
+}
+
+const { metas, class: className, ...rest } = Astro.props;
+---
+
+{
+  metas.filter((item) => Boolean(item)).length > 0 && (
+    <div class:list={['flex flex-wrap gap-x-3 gap-y-2', className]} {...rest}>
+      {metas.map((meta) => {
+        return (
+          meta && (
+            <div class="flex flex-wrap items-center gap-1">
+              <MetaIcon name={meta.icon} title={meta.title} aria-label={meta.title} />
+              {(() => {
+                const process = (info: MetaInfo) => {
+                  const text = info.time ? (
+                    <time datetime={info.time?.toISOString()}>{info.text}</time>
+                  ) : (
+                    <span>{info.text}</span>
+                  );
+                  return info.link ? (
+                    <a href={info.link} title={info.text} class="link-hover not-hover:link">
+                      {text}
+                    </a>
+                  ) : (
+                    text
+                  );
+                };
+                if ('group' in meta) {
+                  return meta.group
+                    .map(process)
+                    .flatMap((item, index, arr) =>
+                      index === arr.length - 1 ? [item] : [item, '/']
+                    );
+                }
+                return process(meta);
+              })()}
+            </div>
+          )
+        );
+      })}
+    </div>
+  )
+}
src/components/widgets/PostCard.astro
@@ -3,7 +3,7 @@ import { siteConfig } from '@/config';
 import { getCategoryUrl, getTagUrl } from '@utils/content-utils';
 import { t } from '@utils/i18n';
 import type { ImageMetadata } from 'astro';
-import MetaIcon from './MetaIcon.astro';
+import MetaList from './MetaList.astro';
 import PostCardCover from './PostCardCover.astro';
 import ReadMoreButton from './ReadMoreButton.astro';
 
@@ -68,43 +68,7 @@ const metas: (
 >
   <div class="card-body">
     <a href={url} class="card-title">{title}</a>
-    <div class="text-base-content/60 mb-3 flex flex-wrap items-center gap-3 text-sm">
-      {
-        metas.map((meta) => {
-          return (
-            meta && (
-              <div class="flex flex-wrap items-center gap-1">
-                <MetaIcon name={meta.icon} title={meta.title} aria-label={meta.title} />
-                {(() => {
-                  const process = (info: MetaInfo) => {
-                    const text = info.time ? (
-                      <time datetime={info.time?.toISOString()}>{info.text}</time>
-                    ) : (
-                      <span>{info.text}</span>
-                    );
-                    return info.link ? (
-                      <a href={info.link} title={info.text} class="link-hover not-hover:link">
-                        {text}
-                      </a>
-                    ) : (
-                      text
-                    );
-                  };
-                  if ('group' in meta) {
-                    return meta.group
-                      .map(process)
-                      .flatMap((item, index, arr) =>
-                        index === arr.length - 1 ? [item] : [item, '/']
-                      );
-                  }
-                  return process(meta);
-                })()}
-              </div>
-            )
-          );
-        })
-      }
-    </div>
+    <MetaList class="text-base-content/60 mt-2 items-start text-sm" metas={metas} />
   </div>
   {
     hasCover ? (
src/pages/archives/categories/index.astro
@@ -9,7 +9,7 @@ import {
 import ProfileCard from '@components/aside/ProfileCard.astro';
 import TOC from '@components/aside/TOC.astro';
 import Button from '@components/widgets/Button.astro';
-import MetaIcon from '@components/widgets/MetaIcon.astro';
+import MetaList from '@components/widgets/MetaList.astro';
 import MainLayout from '@layouts/MainLayout.astro';
 import { t } from '@utils/i18n';
 import { Icon } from 'astro-icon/components';
@@ -89,37 +89,25 @@ if (uncategorizedPosts.length > 0)
                       >
                         {data.title}
                       </a>
-                      <div class="text-base-content/60 mt-2 flex flex-wrap items-start gap-x-4 gap-y-2 text-sm">
-                        {[
+                      <MetaList
+                        class="text-base-content/60 mt-2 items-start text-sm"
+                        metas={[
                           {
                             icon: 'material-symbols:category-outline-rounded',
                             text: data.category || t.meta.unCategorized(),
                             link: getCategoryUrl(data.category),
                           },
-                          ...(data.tags?.map((tag) => {
-                            return {
+                          {
+                            icon: 'material-symbols:tag-rounded',
+                            title: t.meta.tags(),
+                            group: data.tags.map((tag) => ({
                               icon: 'material-symbols:tag-rounded',
                               text: tag,
                               link: getTagUrl(tag),
-                            };
-                          }) || []),
-                        ].map((meta) => (
-                          <div class="flex items-center gap-1">
-                            <MetaIcon name={meta.icon} />
-                            {meta.link ? (
-                              <a
-                                href={meta.link}
-                                class="meta-text link-hover not-hover:link"
-                                title={meta.text}
-                              >
-                                {meta.text}
-                              </a>
-                            ) : (
-                              <span class="meta-text">{meta.text}</span>
-                            )}
-                          </div>
-                        ))}
-                      </div>
+                            })),
+                          },
+                        ]}
+                      />
                     </div>
                   </li>
                 ))}
src/pages/archives/tags/index.astro
@@ -4,7 +4,7 @@ import { getCategoryUrl, getSortedPosts, getTags, getTagUrl } from '@/utils/cont
 import ProfileCard from '@components/aside/ProfileCard.astro';
 import TOC from '@components/aside/TOC.astro';
 import Button from '@components/widgets/Button.astro';
-import MetaIcon from '@components/widgets/MetaIcon.astro';
+import MetaList from '@components/widgets/MetaList.astro';
 import MainLayout from '@layouts/MainLayout.astro';
 import { t } from '@utils/i18n';
 import { Icon } from 'astro-icon/components';
@@ -86,37 +86,25 @@ if (untaggedPosts.length > 0) tagPosts.set(t.meta.unTagged(), untaggedPosts);
                       >
                         {data.title}
                       </a>
-                      <div class="text-base-content/60 mt-2 flex flex-wrap items-start gap-x-4 gap-y-2 text-sm">
-                        {[
+                      <MetaList
+                        class="text-base-content/60 mt-2 items-start text-sm"
+                        metas={[
                           {
                             icon: 'material-symbols:category-outline-rounded',
                             text: data.category || t.meta.unCategorized(),
                             link: getCategoryUrl(data.category),
                           },
-                          ...data.tags.map((tag) => {
-                            return {
+                          {
+                            icon: 'material-symbols:tag-rounded',
+                            title: t.meta.tags(),
+                            group: data.tags.map((tag) => ({
                               icon: 'material-symbols:tag-rounded',
                               text: tag,
                               link: getTagUrl(tag),
-                            };
-                          }),
-                        ].map((meta) => (
-                          <div class="flex items-center gap-1">
-                            <MetaIcon name={meta.icon} />
-                            {meta.link ? (
-                              <a
-                                href={meta.link}
-                                class="meta-text link-hover not-hover:link"
-                                title={meta.text}
-                              >
-                                {meta.text}
-                              </a>
-                            ) : (
-                              <span class="meta-text">{meta.text}</span>
-                            )}
-                          </div>
-                        ))}
-                      </div>
+                            })),
+                          },
+                        ]}
+                      />
                     </div>
                   </li>
                 ))}
src/pages/archives/[...time].astro
@@ -3,7 +3,7 @@ import { siteConfig } from '@/config';
 import type { BlogPostData } from '@/types/data';
 import ProfileCard from '@components/aside/ProfileCard.astro';
 import TOC from '@components/aside/TOC.astro';
-import MetaIcon from '@components/widgets/MetaIcon.astro';
+import MetaList from '@components/widgets/MetaList.astro';
 import MainLayout from '@layouts/MainLayout.astro';
 import { getCategoryUrl, getPostsCount, getSortedPosts, getTagUrl } from '@utils/content-utils';
 import { t } from '@utils/i18n';
@@ -92,37 +92,25 @@ const postCount = await getPostsCount();
                     >
                       {data.title}
                     </a>
-                    <div class="text-base-content/60 mt-2 flex flex-wrap items-start gap-x-4 gap-y-2 text-sm">
-                      {[
+                    <MetaList
+                      class="text-base-content/60 mt-2 items-start text-sm"
+                      metas={[
                         {
                           icon: 'material-symbols:category-outline-rounded',
                           text: data.category || t.meta.unCategorized(),
                           link: getCategoryUrl(data.category),
                         },
-                        ...data.tags.map((tag) => {
-                          return {
+                        {
+                          icon: 'material-symbols:tag-rounded',
+                          title: t.meta.tags(),
+                          group: data.tags.map((tag) => ({
                             icon: 'material-symbols:tag-rounded',
                             text: tag,
                             link: getTagUrl(tag),
-                          };
-                        }),
-                      ].map((meta) => (
-                        <div class="flex items-center gap-1">
-                          <MetaIcon name={meta.icon} />
-                          {meta.link ? (
-                            <a
-                              href={meta.link}
-                              title={meta.text}
-                              class="meta-text link-hover not-hover:link"
-                            >
-                              {meta.text}
-                            </a>
-                          ) : (
-                            <span class="meta-text">{meta.text}</span>
-                          )}
-                        </div>
-                      ))}
-                    </div>
+                          })),
+                        },
+                      ]}
+                    />
                   </div>
                   <time
                     datetime={data.published.toISOString()}