Files
NapCatQQ/packages/napcat-webui-frontend/src/components/napcat_repo_info.tsx
手瓜一十雪 ed19c52f25 refactor: 整体重构 (#1381)
* feat: pnpm new

* Refactor build and release workflows, update dependencies

Switch build scripts and workflows from npm to pnpm, update build and artifact paths, and simplify release workflow by removing version detection and changelog steps. Add new dependencies (silk-wasm, express, ws, node-pty-prebuilt-multiarch), update exports in package.json files, and add vite config for napcat-framework. Also, rename manifest.json for framework package and fix static asset copying in shell build config.
2025-11-13 15:39:42 +08:00

246 lines
6.5 KiB
TypeScript

import { Listbox, ListboxItem } from '@heroui/listbox';
import { Spinner } from '@heroui/spinner';
import { useRequest } from 'ahooks';
import { MdError } from 'react-icons/md';
import IconWrapper from '@/components/github_info/icon_wrapper';
import ItemCounter from '@/components/github_info/item_counter';
import GithubRelease from '@/components/github_info/release';
import {
BookIcon,
BugIcon,
PullRequestIcon,
StarIcon,
TagIcon,
UsersIcon,
WatchersIcon,
} from '@/components/icons';
import { request } from '@/utils/request';
import { openUrl } from '@/utils/url';
import type {
GirhubRepo,
GithubContributor,
GithubPullRequest,
GithubRelease as GithubReleaseType,
} from '@/types/github';
function displayData (data: number, loading: boolean, error?: Error) {
if (error) {
return <MdError className='text-primary-400' />;
}
if (loading) {
return <Spinner size='sm' />;
}
return <ItemCounter number={data} />;
}
export default function NapCatRepoInfo () {
// repo info
const {
data: repoOriData,
error: repoError,
loading: repoLoading,
} = useRequest(() =>
request.get<GirhubRepo>('https://api.github.com/repos/NapNeko/NapCatQQ')
);
// release info
const {
data: releaseOriData,
error: releaseError,
loading: releaseLoading,
} = useRequest(() =>
request.get<GithubReleaseType[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/releases'
)
);
// pr info
const {
data: prData,
error: prError,
loading: prLoading,
} = useRequest(() =>
request.get<GithubPullRequest[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/pulls'
)
);
// contributors info
const {
data: contributorsData,
error: contributorsError,
loading: contributorsLoading,
} = useRequest(() =>
request.get<GithubContributor[]>(
'https://api.github.com/repos/NapNeko/NapCatQQ/contributors'
)
);
const repoData = repoOriData?.data;
const releaseData = releaseOriData?.data?.[0];
const prCount = prData?.data?.length || 0;
const contributorsCount = contributorsData?.data?.length || 0;
const releaseCount = releaseOriData?.data?.length || 0;
return (
<Listbox
aria-label='NapCat Repo Info'
className='p-0 gap-0 divide-y divide-default-300/50 dark:divide-default-100/80 bg-content1 max-w-[300px] overflow-visible shadow-small rounded-medium bg-opacity-50 backdrop-blur-sm'
itemClasses={{
base: 'px-3 first:rounded-t-medium last:rounded-b-medium rounded-none gap-3 h-12 data-[hover=true]:bg-default-100/80',
}}
onAction={(key: React.Key) => {
switch (key) {
case 'releases':
openUrl('https://github.com/NapNeko/NapCatQQ/releases', true);
break;
case 'contributors':
openUrl(
'https://github.com/NapNeko/NapCatQQ/graphs/contributors',
true
);
break;
case 'license':
openUrl(
'https://github.com/NapNeko/NapCatQQ/blob/main/LICENSE',
true
);
break;
case 'watchers':
openUrl('https://github.com/NapNeko/NapCatQQ/watchers', true);
break;
case 'star':
openUrl('https://github.com/NapNeko/NapCatQQ/stargazers', true);
break;
case 'issues':
openUrl('https://github.com/NapNeko/NapCatQQ/issues', true);
break;
case 'pull_requests':
openUrl('https://github.com/NapNeko/NapCatQQ/pulls', true);
break;
default:
openUrl('https://github.com/NapNeko/NapCatQQ', true);
}
}}
>
<ListboxItem
key='star'
endContent={displayData(
repoData?.stargazers_count ?? 0,
false,
repoError
)}
startContent={
<IconWrapper className='bg-success/10 text-success'>
<StarIcon className='text-lg' />
</IconWrapper>
}
>
Star
</ListboxItem>
<ListboxItem
key='issues'
endContent={displayData(
repoData?.open_issues_count ?? 0,
false,
repoError
)}
startContent={
<IconWrapper className='bg-success/10 text-success'>
<BugIcon className='text-lg' />
</IconWrapper>
}
>
Issues
</ListboxItem>
<ListboxItem
key='pull_requests'
endContent={displayData(prCount, prLoading, prError)}
startContent={
<IconWrapper className='bg-primary/10 text-primary'>
<PullRequestIcon className='text-lg' />
</IconWrapper>
}
>
Pull Requests
</ListboxItem>
<ListboxItem
key='releases'
className='group h-auto py-3'
endContent={
releaseError
? (
<MdError className='text-primary-400' />
)
: releaseLoading
? (
<Spinner size='sm' />
)
: (
<ItemCounter number={releaseCount} />
)
}
startContent={
<IconWrapper className='bg-primary/10 text-primary'>
<TagIcon className='text-lg' />
</IconWrapper>
}
textValue='Releases'
>
{releaseData && <GithubRelease releaseData={releaseData} />}
</ListboxItem>
<ListboxItem
key='contributors'
endContent={displayData(
contributorsCount,
contributorsLoading,
contributorsError
)}
startContent={
<IconWrapper className='bg-warning/10 text-warning'>
<UsersIcon />
</IconWrapper>
}
>
Contributors
</ListboxItem>
<ListboxItem
key='watchers'
endContent={displayData(
repoData?.watchers_count ?? 0,
repoLoading,
repoError
)}
startContent={
<IconWrapper className='bg-default/50 text-foreground'>
<WatchersIcon />
</IconWrapper>
}
>
Watchers
</ListboxItem>
<ListboxItem
key='license'
endContent={
<span className='text-small text-default-400'>
{repoData?.license?.name ?? 'unknown'}
</span>
}
startContent={
<IconWrapper className='bg-primary/10 text-primary dark:text-primary-500'>
<BookIcon />
</IconWrapper>
}
>
License
</ListboxItem>
</Listbox>
);
}