Skip to content
This repository has been archived by the owner on Jun 17, 2023. It is now read-only.

Commit

Permalink
feat: watch up following support
Browse files Browse the repository at this point in the history
  • Loading branch information
Lmmmmmm-bb committed Sep 17, 2022
1 parent 219df5b commit fae7735
Show file tree
Hide file tree
Showing 16 changed files with 499 additions and 744 deletions.
21 changes: 21 additions & 0 deletions components/empty/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
@use '../../popup/variables' as v;

.wrapper {
width: 100%;
&::after {
height: 450px;
display: block;
content: attr(data-content);
font-size: 14px;
color: v.$secondary-text-color;
border-radius: 4px;
background: {
position: 50%;
repeat: no-repeat;
image: url('../../assets/nodata.png');
}
overflow: hidden;
line-height: 640px;
text-align: center;
}
}
17 changes: 17 additions & 0 deletions components/empty/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { FC } from 'react';

import styles from './index.module.scss';

interface IEmptyProps {
content: string;
}

const Empty: FC<IEmptyProps> = (props) => (
<div
className={styles.wrapper}
style={{ content: 'Hello' }}
data-content={props.content}
/>
);

export default Empty;
64 changes: 41 additions & 23 deletions components/up-avatar/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import type { FC } from 'react';
import { useStorage } from '@plasmohq/storage';
import { useNavigate } from 'react-router-dom';
import {
ContextMenu,
ContextMenuItem,
ContextMenuTrigger
} from 'rctx-contextmenu';
import { useSortable } from '@dnd-kit/sortable';
import type { FC } from 'react';
import { CSS } from '@dnd-kit/utilities';
import { useStorage } from '@plasmohq/storage';
import { useNavigate } from 'react-router-dom';
import { useSortable } from '@dnd-kit/sortable';

import type { IUpInfo } from '~types';
import { FOLLOW_X_KEY } from '~layouts/follow/config';

import styles from './index.module.scss';

interface UpAvatarProps {
Expand Down Expand Up @@ -45,6 +47,40 @@ const UpAvatar: FC<UpAvatarProps> = (props) => {
});
};

const handleToUpFollowing = () => {
navigator(`/following/${up.mid}`, {
state: { up }
});
};

const renderContextItem = (
<ContextMenu
id={up.mid.toString()}
className={styles.contextMenu}
appendTo='body'
animation='fade'
>
<ContextMenuItem
attributes={{ title: `访问 ${up.name} 主页` }}
onClick={handleVisitUp}
>
{`访问 ${up.name}`}
</ContextMenuItem>
<ContextMenuItem
attributes={{ title: `查看 ${up.name} 的关注列表` }}
onClick={handleToUpFollowing}
>
查看关注列表
</ContextMenuItem>
<ContextMenuItem
attributes={{ title: `删除 ${up.name}` }}
onClick={handleRemoveUp}
>
删除
</ContextMenuItem>
</ContextMenu>
);

return (
<ContextMenuTrigger id={up.mid.toString()}>
<div
Expand All @@ -61,25 +97,7 @@ const UpAvatar: FC<UpAvatarProps> = (props) => {
<p className={styles.upName}>{up.name}</p>
</div>
</div>
<ContextMenu
id={up.mid.toString()}
className={styles.contextMenu}
appendTo='body'
animation='fade'
>
<ContextMenuItem
attributes={{ title: `访问 ${up.name} 主页` }}
onClick={handleVisitUp}
>
{`访问 ${up.name}`}
</ContextMenuItem>
<ContextMenuItem
attributes={{ title: `删除 ${up.name}` }}
onClick={handleRemoveUp}
>
删除
</ContextMenuItem>
</ContextMenu>
{renderContextItem}
</ContextMenuTrigger>
);
};
Expand Down
52 changes: 52 additions & 0 deletions components/up-card/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
.wrapper {
padding: 4px 12px;
display: flex;
border-radius: 4px;
transition: background-color 0.3s ease-in-out;
cursor: pointer;

&:hover {
background-color: #f5f5f5;
}

.avatar {
margin-right: 8px;
width: 34px;
height: 34px;
border: 1px solid #e5e5e5 {
radius: 50%;
}
transition: width 0.2s ease-in-out, height 0.2s ease-in-out;
}

.contentWrapper {
height: 38px;

.section {
margin: 0;
width: 120px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}

.name {
font: {
size: 14px;
weight: 500;
}
}

.sign {
color: #1c1f239f;
font: {
size: 12px;
weight: 300;
}
}
}
}

.select {
background-color: #f5f5f5;
}
41 changes: 41 additions & 0 deletions components/up-card/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { FC, useMemo } from 'react';
import { useStorage } from '@plasmohq/storage';

import { FOLLOW_X_KEY } from '~layouts/follow/config';
import type { FollowingInfoType, IUpInfo } from '~types';

import styles from './index.module.scss';

interface IUpCardProps {
up: FollowingInfoType;
}

const UpCard: FC<IUpCardProps> = (props) => {
const { up } = props;
const [follow] = useStorage<IUpInfo[]>(
FOLLOW_X_KEY,
(v: IUpInfo[]) => v || []
);

const ids = useMemo(() => follow.map((item) => item.mid), [follow]);

return (
<div
className={`${styles.wrapper} ${
ids.includes(up.mid) ? styles.select : ''
}`}
>
<img className={styles.avatar} src={up.face} />
<div className={styles.contentWrapper}>
<h3 className={`${styles.section} ${styles.name}`} title={up.uname}>
{up.uname}
</h3>
<p className={`${styles.section} ${styles.sign}`} title={up.sign}>
{up.sign}
</p>
</div>
</div>
);
};

export default UpCard;
10 changes: 6 additions & 4 deletions layouts/follow/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import { FC, KeyboardEvent, useRef } from 'react';
import { useStorage } from '@plasmohq/storage';
import {
DndContext,
DragEndEvent,
MouseSensor,
useSensor,
useSensors
} from '@dnd-kit/core';
import { useStorage } from '@plasmohq/storage';
import { FC, KeyboardEvent, useRef } from 'react';
import { SortableContext, arrayMove } from '@dnd-kit/sortable';

import { useFetchType } from '~hooks';
import type { IUpInfo } from '~types';
import { uniqByKey, fetchUpInfo } from '~utils';
import UpAvatar from '~components/up-avatar';
import BiliBili from '~components/bilibili';
import UpAvatar from '~components/up-avatar';
import { uniqByKey, fetchUpInfo } from '~utils';

import { FOLLOW_X_KEY } from './config';
import styles from './index.module.scss';

Expand Down
10 changes: 10 additions & 0 deletions layouts/following/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
.wrapper {
width: 400px;
padding: 16px;

.contentWrapper {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-gap: 8px;
}
}
59 changes: 59 additions & 0 deletions layouts/following/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { FC, useEffect, useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';

import Empty from '~components/empty';
import UpCard from '~components/up-card';
import { fetchUpFollowing } from '~utils';
import type { FollowingInfoType, IUpInfo } from '~types';
import UpSpaceNavigate from '~components/up-space-navigate';
import UpSpacePagination from '~components/up-space-pagination';

import styles from './index.module.scss';

const Following: FC = () => {
const { state } = useLocation();
const { uid } = useParams<{ uid: string }>();
const [isPrivate, setIsPrivate] = useState(false);
const [total, setTotal] = useState(0);
const [page, setPage] = useState(1);
const [followList, setFollowList] = useState<FollowingInfoType[]>([]);

const fetchFollow = async (pn = 1) => {
setPage(pn);
const response = await fetchUpFollowing({ vmid: uid, pn });
if (response) {
setTotal(Math.max(response.total - (pn - 1) * 50, 0));
setFollowList(response.list);
} else {
setIsPrivate(true);
}
};

useEffect(() => {
fetchFollow();
}, []);

return (
<div className={styles.wrapper}>
<UpSpaceNavigate up={(state as { up: IUpInfo }).up} />
{isPrivate ? (
<Empty content='由于该用户隐私设置,关注列表不可见' />
) : (
<>
<div className={styles.contentWrapper}>
{followList.map((item) => (
<UpCard key={item.mid} up={item} />
))}
</div>
<UpSpacePagination
total={total}
onNextClick={() => fetchFollow(page + 1)}
onPrevClick={() => fetchFollow(page - 1)}
/>
</>
)}
</div>
);
};

export default Following;
6 changes: 5 additions & 1 deletion layouts/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import type { FC, PropsWithChildren } from 'react';
import type { FC } from 'react';
import { Route, Routes } from 'react-router-dom';

import ErrorBoundary from '~components/error-boundary';

import Follow from './follow';
import UpSpace from './up-space';
import Following from './following';

const WrapperErrorBoundary = (FunctionComponent: FC) => (
<ErrorBoundary>
Expand All @@ -14,6 +17,7 @@ const _Router: FC = () => (
<Routes>
<Route path='/' element={<Follow />} />
<Route path='/up/:uid' element={<UpSpace />} />
<Route path='/following/:uid' element={<Following />} />
</Routes>
);

Expand Down
20 changes: 0 additions & 20 deletions layouts/up-space/index.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,26 +7,6 @@
padding: 16px;
user-select: none;

.noData {
width: 100%;
&::after {
height: 450px;
display: block;
content: '空间主人还没有投过视频哦~~';
font-size: 14px;
color: v.$secondary-text-color;
border-radius: 4px;
background: {
position: 50%;
repeat: no-repeat;
image: url('../../assets/nodata.png');
}
overflow: hidden;
line-height: 640px;
text-align: center;
}
}

.videoWrapper {
display: grid;
grid-template-columns: 1fr 1fr;
Expand Down
7 changes: 5 additions & 2 deletions layouts/up-space/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import { FC, useEffect, useState } from 'react';
import { useLocation, useParams } from 'react-router-dom';

import Empty from '~components/empty';
import { fetchUpSpaceInfo } from '~utils';
import VideoCard from '~components/video-card';
import UpSpaceNavigate from '~components/up-space-navigate';
import UpSpacePagination from '~components/up-space-pagination';
import type { IBSpaceQuery, ISpaceVideo, IUpInfo } from '~types';
import { fetchUpSpaceInfo } from '~utils';

import styles from './index.module.scss';

const UpSpace: FC = () => {
Expand Down Expand Up @@ -35,7 +38,7 @@ const UpSpace: FC = () => {
<div className={styles.wrapper}>
<UpSpaceNavigate up={(state as { up: IUpInfo }).up} />
{videoList.length === 0 ? (
<div className={styles.noData} />
<Empty content='空间主人还没有投过视频哦~~' />
) : (
<div className={styles.videoWrapper}>
{videoList.map((video) => (
Expand Down
Loading

0 comments on commit fae7735

Please sign in to comment.