Skip to content

Commit

Permalink
feat: add user page (#59)
Browse files Browse the repository at this point in the history
> 添加用户详情页,兼容 cnpm 客户端 user 命令,closes #58 
* 添加个人详情页 `/user/:name`
* 支持 `/~xxx` 形式页面跳转
* 包详情首页部分添加用户详情链接


![image](https://github.com/cnpm/cnpmweb/assets/5574625/ac86dcf0-19b1-4458-8f09-bfcf2bd0ab03)
  • Loading branch information
elrrrrrrr authored Dec 6, 2023
1 parent 0f04ed6 commit dc5eea9
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/components/Gravatar.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import GravatarLink from '@gravatar/js';
import { Avatar, Tooltip } from 'antd';
import Link from 'next/link';

type GAvatarProps = {
email: string;
name: string;
size?: number;
link?: boolean;
};
export function Gravatar({ email, name }: GAvatarProps) {
export function Gravatar({ email, name, size = 32, link = true }: GAvatarProps) {
const avatarLink = GravatarLink({
email: email || '',
size: 200,
Expand All @@ -19,7 +22,13 @@ export function Gravatar({ email, name }: GAvatarProps) {

return (
<Tooltip title={name}>
<Avatar src={newLink.toString()} />
{link ? (
<Link href={`/user/${name}`} shallow>
<Avatar src={newLink.toString()} size={size} />
</Link>
) : (
<Avatar src={newLink.toString()} size={size} />
)}
</Tooltip>
);
}
31 changes: 31 additions & 0 deletions src/hooks/useUser.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { REGISTRY } from '@/config';
import useSwr from 'swr';
import { PackageManifest } from './useManifest';

export default function useUser(user?: string) {
return useSwr(user ? `user:${user}` : null, async () => {
const pkgRes = await fetch(`${REGISTRY}/-/org/npm:${user}/package`);

if (pkgRes.ok === false) {
return {
pkgs: [],
user: {
name: user,
email: '',
},
};
}

const pkgs = Object.keys(await pkgRes.json()).map(_ => ({ name: _ }));
const pkgInfo = await fetch(`${REGISTRY}/${pkgs[0].name}`).then(res => res.json()) as PackageManifest;
const email = pkgInfo?.maintainers?.find(m => m.name === user)?.email;

return {
pkgs,
user: {
name: user,
email,
},
};
});
}
5 changes: 5 additions & 0 deletions src/pages/[...npa]/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ export default function Redirect() {
}
}, [originNpa]);

if (originNpa?.[0]?.startsWith('~')) {
router.replace(`/user/${originNpa[0].slice(1)}`);
return <></>;
}

if (redirectInfo) {
router.replace(`/package/${redirectInfo.name}?version=${redirectInfo.fetchSpec}`);
return <></>;
Expand Down
106 changes: 106 additions & 0 deletions src/pages/user/[name].tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import React from 'react';
import 'antd/dist/reset.css';
import Footer from '@/components/Footer';
import { ThemeMode, ThemeProvider as _ThemeProvider } from 'antd-style';
import Header from '@/components/Header';
import { useTheme } from '@/hooks/useTheme';
import AdHire from '@/components/AdHire';
import { useRouter } from 'next/router';
import useUser from '@/hooks/useUser';
import { Card, Col, Row, Space, Spin, Table, TableColumnsType, Typography } from 'antd';
import SizeContainer from '@/components/SizeContainer';
import { Gravatar } from '@/components/Gravatar';
import Link from 'next/link';

const ThemeProvider = _ThemeProvider as any;

export default function Home() {
const [themeMode, setThemeMode] = useTheme();
const { query } = useRouter();

const {data: resData, isLoading} = useUser(query.name as string | undefined);

if (isLoading) {
return (
<Spin
style={{
position: 'fixed',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%)',
}}
/>
);
}

const columns: TableColumnsType = [
{
title: '包名',
dataIndex: 'name',
key: 'name',
onCell: () => ({
style: {
maxWidth: 0,
},
}),
render: (title: string) => {
return (
<>
<div>{title}</div>
</>
);
},
},
{
width: 200,
align: 'center',
key: 'name',
render: (_, name: any) => {
return (
<Space size="middle">
<Link href={`/${name.name}`} target='_blank'>查看</Link>
</Space>
);
},
},
];

return (
<ThemeProvider themeMode={themeMode as ThemeMode}>
<AdHire />
<Header themeMode={themeMode} setThemeMode={setThemeMode} />
<main style={{ minHeight: 'calc( 100vh - 110px )' }}>
<SizeContainer maxWidth={1184}>
<Row gutter={16} style={{ width: 1184 }}>
<Col flex="none">
<Card style={{ width: 280, textAlign: 'center' }}>
<Gravatar
email={resData?.user.email || ''}
name={resData?.user?.name || ''}
link={false}
size={64}
/>
<Typography.Title level={4} style={{ marginTop: 16 }} ellipsis={{ tooltip: true }}>
{resData?.user.name}
</Typography.Title>
<Typography.Text>{resData?.user.email}</Typography.Text>
</Card>
</Col>
<Col flex="auto" style={{ width: 0 }}>
<Card title={'TA 管理的'}>
<Table
loading={isLoading}
dataSource={resData?.pkgs}
columns={columns as any}
rowKey={'name'}
pagination={{ showSizeChanger: (resData?.pkgs || []).length > 10 }}
/>
</Card>
</Col>
</Row>
</SizeContainer>
</main>
<Footer />
</ThemeProvider>
);
}

0 comments on commit dc5eea9

Please sign in to comment.