Skip to content

Commit

Permalink
feat: recent use (#53)
Browse files Browse the repository at this point in the history
![image](https://github.com/cnpm/cnpmweb/assets/5574625/22358463-11c6-4714-8d07-e61e751f1b4c)

* 添加最近访问 tag,默认保存至 localstorage
* github 链接添加 cnpm 及 rapid
  • Loading branch information
elrrrrrrr authored Nov 28, 2023
1 parent c15b6a0 commit 700c0df
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 23 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ next-env.d.ts
package-lock.json

dist/
.node
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@
"@gravatar/js": "^1.1.1",
"@monaco-editor/loader": "^1.3.3",
"@monaco-editor/react": "^4.4.2",
"@types/node": "20.4.1",
"@types/react": "18.2.14",
"@types/react-dom": "18.2.5",
"@vercel/node": "^2.15.5",
"antd": "^5.6.4",
Expand All @@ -41,6 +39,8 @@
"@types/lodash": "^4.14.197",
"@types/npm-package-arg": "^6.1.3",
"@types/semver": "^7.5.0",
"@types/node": "20.4.1",
"@types/react": "18.2.14",
"prettier": "^3.0.3"
}
}
29 changes: 29 additions & 0 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useRecent } from '@/hooks/useRecent';
import { GithubOutlined } from '@ant-design/icons';
import { Dropdown, Segmented } from 'antd';
import { createStyles, cx } from 'antd-style';
import Link from 'next/link';
import { useEffect } from 'react';

const useStyles = createStyles(({ token, css }) => {
return {
Expand All @@ -20,6 +22,17 @@ const useStyles = createStyles(({ token, css }) => {

export default function Header({ title, themeMode, setThemeMode }: any) {
const { styles } = useStyles();
const [recent, setRecent] = useRecent();

useEffect(() => {
if (recent === undefined) {
return;
}
if (title && !recent.includes(title)) {
setRecent([title, ...(recent || [])]);
}
}, [title, recent]);

return (
<header className={cx(styles.header)}>
<nav className={styles.container}>
Expand All @@ -45,6 +58,14 @@ export default function Header({ title, themeMode, setThemeMode }: any) {
<Dropdown
menu={{
items: [
{
key: 'cnpm',
label: (
<Link target="_blank" href={'https://github.com/cnpm/cnpm'}>
🔧 cnpm
</Link>
),
},
{
key: 'cnpmweb',
label: (
Expand All @@ -61,6 +82,14 @@ export default function Header({ title, themeMode, setThemeMode }: any) {
</Link>
),
},
{
key: 'rapid',
label: (
<Link target="_blank" href={'https://github.com/cnpm/rapid'}>
🚀 rapid
</Link>
),
},
],
}}
>
Expand Down
52 changes: 34 additions & 18 deletions src/components/LandingSearch.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
'use client';

import React, { useState } from 'react';
import { Input, Typography, AutoComplete } from 'antd';
import { Input, Typography, AutoComplete, Space } from 'antd';
import { useCachedSearch } from '@/hooks/useSearch';
import { useRouter } from 'next/router';
import Link from 'next/link';
import { PackageTag } from './PackageCard';
import { useRecent } from '@/hooks/useRecent';

export default function LandingSearch() {
const [search, setSearch] = useState('');
const [recent, setRecent] = useRecent();
const router = useRouter();

const { data: searchResult, isLoading } = useCachedSearch({
Expand Down Expand Up @@ -35,22 +38,35 @@ export default function LandingSearch() {
}, [searchResult]);

return (
<AutoComplete
style={{ width: '100%' }}
options={options}
onChange={setSearch}
onSelect={(search) => router.push(`/package/${search}`)}
>
<Input.Search
size="large"
placeholder="输入 NPM 包名、作者、关键字等信息即可搜索..."
enterButton
onSearch={(_, e) => {
e?.stopPropagation();
router.push(`/packages?q=${search}`);
}}
loading={!!(search && isLoading)}
/>
</AutoComplete>
<>
<AutoComplete
style={{ width: '100%' }}
options={options}
onChange={setSearch}
onSelect={(search) => router.push(`/package/${search}`)}
>
<Input.Search
size="large"
placeholder="输入 NPM 包名、作者、关键字等信息即可搜索..."
enterButton
onSearch={(_, e) => {
e?.stopPropagation();
router.push(`/packages?q=${search}`);
}}
loading={!!(search && isLoading)}
/>
</AutoComplete>
<div style={{ marginTop: 16 }}>
{recent && (
<PackageTag
tags={recent}
closeIcon
onClose={(v) => {
setRecent(recent.filter((i) => i !== v));
}}
/>
)}
</div>
</>
);
}
6 changes: 3 additions & 3 deletions src/components/PackageCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ dayjs.locale('zh-cn');

dayjs.extend(relativeTime);

export function PackageTag({ tags }: { tags: string[] }) {
export function PackageTag({ tags, closeIcon, onClose }: { tags: string[], closeIcon?: boolean, onClose?: (tag: string) => void }) {
if (!tags) {
return null;
}
Expand All @@ -25,11 +25,11 @@ export function PackageTag({ tags }: { tags: string[] }) {
maxCount="responsive"
data={tags}
renderItem={(tag: string) => (
<Tag key={tag} color="cyan">
<Tag key={tag} color="cyan" closeIcon={closeIcon} onClose={() => onClose?.(tag)}>
{tag}
</Tag>
)}
renderRest={() => <Tag key={'_others'}>...</Tag>}
renderRest={() => <Tag key={'_others'} color="cyan">...</Tag>}
/>
);
}
Expand Down
23 changes: 23 additions & 0 deletions src/hooks/useRecent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use client';
import { useEffect, useState } from 'react';

const LOCAL_STORAGE_RECENT = 'recent';

export function useRecent(): [string[] | undefined, (v: string[]) => void] {
const [recent, setRecent] = useState<string[] | undefined>(undefined);

useEffect(() => {
const recentInfo = localStorage?.getItem(LOCAL_STORAGE_RECENT);
if (recentInfo) {
setRecent(JSON.parse(recentInfo));
}
}, []);

useEffect(() => {
if (recent) {
localStorage.setItem(LOCAL_STORAGE_RECENT, JSON.stringify(recent.slice(0, 10)));
}
}, [recent]);

return [recent, setRecent];
}

0 comments on commit 700c0df

Please sign in to comment.