Commit 1a02a03

HPCesia <me@hpcesia.com>
2025-04-18 14:06:39
refactor(user components): repo card
1 parent d4320aa
Changed files (1)
src
components
src/components/user/RepoCard.astro
@@ -11,7 +11,7 @@ interface Props {
   platform: 'github';
 }
 
-const { repo, platform } = Astro.props as Props;
+const { repo, platform } = Astro.props;
 const repoName = typeof repo === 'string' ? repo : `${repo.owner}/${repo.name}`;
 
 let url: string;
@@ -62,65 +62,86 @@ switch (platform) {
 </a>
 
 <script>
-  import { request as githubApiRequest } from '@octokit/request';
-
-  type Platform = 'github';
+  const allPlatform = ['github'] as const;
+  type Platform = (typeof allPlatform)[number];
+
+  interface RepoMeta {
+    description: string | null;
+    language: string | null;
+    license: string | null;
+    stars: number;
+    forks: number;
+  }
 
-  function init() {
-    const repoCards = document.querySelectorAll('.card[data-repo]');
-    repoCards.forEach(async (card) => {
-      const repoName = card.getAttribute('data-repo')!;
-      const platform = card.getAttribute('data-platform')! as Platform;
+  function updateCardUI(card: Element, meta: RepoMeta) {
+    const descriptionNode = card.querySelector('.repo-card-desc')!;
+    const languageNode = card.querySelector('.repo-card-lang')!;
+    const licenseNode = card.querySelector('.repo-card-license')!;
+    const forksNode = card.querySelector('.repo-card-fork')!.querySelector('span')!;
+    const starsNode = card.querySelector('.repo-card-star')!.querySelector('span')!;
 
-      let description: string | null;
-      let language: string | null;
-      let license: string | null;
-      let stars: number;
-      let forks: number;
+    descriptionNode.innerHTML = meta.description || '';
 
-      switch (platform) {
-        case 'github': {
-          const [owner, repo] = repoName.split('/');
-          const meta = await githubApiRequest('GET /repos/{owner}/{repo}', {
-            owner,
-            repo,
-            headers: {
-              'X-GitHub-Api-Version': '2022-11-28',
-            },
-          });
-          description = meta.data.description;
-          language = meta.data.language;
-          license = meta.data.license?.name || null;
-          forks = meta.data.forks_count;
-          stars = meta.data.stargazers_count;
-        }
-      }
+    if (meta.language) {
+      languageNode.classList.remove('hidden');
+      languageNode.classList.add('flex');
+      languageNode.querySelector('span')!.innerText = meta.language;
+    }
 
-      const descriptionNode = card.querySelector('.repo-card-desc')!;
-      const languageNode = card.querySelector('.repo-card-lang')!;
-      const licenseNode = card.querySelector('.repo-card-license')!;
-      const forksNode = card.querySelector('.repo-card-fork')!.querySelector('span')!;
-      const starsNode = card.querySelector('.repo-card-star')!.querySelector('span')!;
+    if (meta.license) {
+      licenseNode.classList.remove('hidden');
+      licenseNode.classList.add('flex');
+      licenseNode.querySelector('span')!.innerText = meta.license;
+    }
 
-      descriptionNode.innerHTML = description || '';
+    forksNode.classList.remove('skeleton', 'h-4', 'w-6');
+    forksNode.innerText = meta.forks.toString();
 
-      if (language) {
-        languageNode.classList.remove('hidden');
-        languageNode.classList.add('flex');
-        languageNode.querySelector('span')!.innerText = language;
-      }
+    starsNode.classList.remove('skeleton', 'h-4', 'w-6');
+    starsNode.innerText = meta.stars.toString();
+  }
 
-      if (license) {
-        licenseNode.classList.remove('hidden');
-        licenseNode.classList.add('flex');
-        licenseNode.querySelector('span')!.innerText = license;
+  async function init() {
+    const repoCards = document.querySelectorAll('.card[data-repo]');
+    const cardsByPlatform = allPlatform.reduce(
+      (acc, platform) => {
+        acc[platform] = Array.from(repoCards).filter(
+          (card) => card.getAttribute('data-platform') === platform
+        );
+        return acc;
+      },
+      {} as Record<Platform, Element[]>
+    );
+
+    Object.entries(cardsByPlatform).forEach(async ([platform, cards]) => {
+      switch (platform as Platform) {
+        case 'github': {
+          const { request: githubApiRequest } = await import('@octokit/request');
+          cards.forEach(async (card) => {
+            const repoName = card.getAttribute('data-repo')!;
+            const [owner, repo] = repoName.split('/');
+
+            const meta = await githubApiRequest('GET /repos/{owner}/{repo}', {
+              owner,
+              repo,
+              headers: {
+                'X-GitHub-Api-Version': '2022-11-28',
+              },
+            });
+
+            const repoMeta: RepoMeta = {
+              description: meta.data.description,
+              language: meta.data.language,
+              license: meta.data.license?.name || null,
+              forks: meta.data.forks_count,
+              stars: meta.data.stargazers_count,
+            };
+
+            updateCardUI(card, repoMeta);
+          });
+          break;
+        }
       }
-
-      forksNode.classList.remove('skeleton', 'h-4', 'w-6');
-      forksNode.innerText = forks.toString();
-
-      starsNode.classList.remove('skeleton', 'h-4', 'w-6');
-      starsNode.innerText = stars.toString();
     });
   }