octicon-rss(16/)
You've already forked owncast
mirror of
https://github.com/owncast/owncast.git
synced 2025-11-10 00:39:22 +08:00
Add Followers list and single follower component. Closes #1861
This commit is contained in:
octicon-git-branch(16/)
octicon-tag(16/)
octicon-diff(16/tw-mr-1) 8 changed files with 111 additions and 46 deletions
@@ -1,19 +0,0 @@
|
|||||||
import { Avatar, Comment } from 'antd';
|
|
||||||
import React from 'react';
|
|
||||||
import { Follower } from '../interfaces/follower';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
follower: Follower;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function SingleFollower(props: Props) {
|
|
||||||
const { follower } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Comment
|
|
||||||
author={follower.username}
|
|
||||||
avatar={<Avatar src={follower.image} alt="Han Solo" />}
|
|
||||||
content={follower.name}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { Pagination } from 'antd';
|
|
||||||
import { Follower } from '../interfaces/follower';
|
|
||||||
import SingleFollower from './Follower';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
total: number;
|
|
||||||
followers: Follower[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function FollowerCollection(props: Props) {
|
|
||||||
const ITEMS_PER_PAGE = 24;
|
|
||||||
|
|
||||||
const { followers, total } = props;
|
|
||||||
const pages = Math.ceil(total / ITEMS_PER_PAGE);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{followers.map(follower => (
|
|
||||||
<SingleFollower key={follower.link} follower={follower} />
|
|
||||||
))}
|
|
||||||
<Pagination current={1} pageSize={ITEMS_PER_PAGE} total={pages || 1} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -18,7 +18,7 @@ import {
|
|||||||
import { ClientConfig } from '../../../interfaces/client-config.model';
|
import { ClientConfig } from '../../../interfaces/client-config.model';
|
||||||
import CustomPageContent from '../CustomPageContent/CustomPageContent';
|
import CustomPageContent from '../CustomPageContent/CustomPageContent';
|
||||||
import OwncastPlayer from '../../video/OwncastPlayer';
|
import OwncastPlayer from '../../video/OwncastPlayer';
|
||||||
import FollowerCollection from '../../FollowersCollection';
|
import FollowerCollection from '../Followers/FollowersCollection';
|
||||||
import s from './Content.module.scss';
|
import s from './Content.module.scss';
|
||||||
import Sidebar from '../Sidebar';
|
import Sidebar from '../Sidebar';
|
||||||
import Footer from '../Footer';
|
import Footer from '../Footer';
|
||||||
|
|||||||
30
web/components/ui/Followers/Follower.tsx
Normal file
30
web/components/ui/Followers/Follower.tsx
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { Avatar, Col, Row } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import { Follower } from '../../../interfaces/follower';
|
||||||
|
import s from './Followers.module.scss';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
follower: Follower;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function SingleFollower(props: Props) {
|
||||||
|
const { follower } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.follower}>
|
||||||
|
<a href={follower.link} target="_blank" rel="noreferrer">
|
||||||
|
<Row wrap={false}>
|
||||||
|
<Col span={6}>
|
||||||
|
<Avatar src={follower.image} alt="Avatar" className={s.avatar}>
|
||||||
|
<img src="/logo" alt="Logo" className={s.placeholder} />
|
||||||
|
</Avatar>
|
||||||
|
</Col>
|
||||||
|
<Col>
|
||||||
|
<Row>{follower.name}</Row>
|
||||||
|
<Row className={s.account}>{follower.username}</Row>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
37
web/components/ui/Followers/Followers.module.scss
Normal file
37
web/components/ui/Followers/Followers.module.scss
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
.follower {
|
||||||
|
border-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
padding: 10px 10px;
|
||||||
|
border-radius: 15px;
|
||||||
|
height: 75px;
|
||||||
|
width: 250px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: var(--theme-text-link);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
border-color: rgba(0, 0, 0, 0.3);
|
||||||
|
border-width: 1px;
|
||||||
|
border-style: solid;
|
||||||
|
}
|
||||||
|
|
||||||
|
.account {
|
||||||
|
color: var(--theme-text-secondary);
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.followers {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
38
web/components/ui/Followers/FollowersCollection.tsx
Normal file
38
web/components/ui/Followers/FollowersCollection.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { Col, Pagination, Row } from 'antd';
|
||||||
|
import { Follower } from '../../../interfaces/follower';
|
||||||
|
import SingleFollower from './Follower';
|
||||||
|
import s from './Followers.module.scss';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
total: number;
|
||||||
|
followers: Follower[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function FollowerCollection(props: Props) {
|
||||||
|
const ITEMS_PER_PAGE = 24;
|
||||||
|
|
||||||
|
const { followers, total } = props;
|
||||||
|
const pages = Math.ceil(total / ITEMS_PER_PAGE);
|
||||||
|
|
||||||
|
const noFollowers = (
|
||||||
|
<div>A message explaining how to follow goes here since there are no followers.</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
if (followers.length === 0) {
|
||||||
|
return noFollowers;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.followers}>
|
||||||
|
<Row wrap gutter={[10, 10]} justify="space-around">
|
||||||
|
{followers.map(follower => (
|
||||||
|
<Col>
|
||||||
|
<SingleFollower key={follower.link} follower={follower} />
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Pagination current={1} pageSize={ITEMS_PER_PAGE} total={pages || 1} hideOnSinglePage />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
import SingleFollower from '../components/Follower';
|
import SingleFollower from '../components/ui/Followers/Follower';
|
||||||
import SingleFollowerMock from './assets/mocks/single-follower.png';
|
import SingleFollowerMock from './assets/mocks/single-follower.png';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
import FollowerCollection from '../components/FollowersCollection';
|
import FollowerCollection from '../components/ui/Followers/FollowersCollection';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'owncast/Components/Followers/Followers collection',
|
title: 'owncast/Components/Followers/Followers collection',
|
||||||
@@ -12,6 +12,9 @@ const Template: ComponentStory<typeof FollowerCollection> = args => (
|
|||||||
<FollowerCollection {...args} />
|
<FollowerCollection {...args} />
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const NoFollowers = Template.bind({});
|
||||||
|
NoFollowers.args = { followers: [] };
|
||||||
|
|
||||||
export const Example = Template.bind({});
|
export const Example = Template.bind({});
|
||||||
Example.args = {
|
Example.args = {
|
||||||
followers: [
|
followers: [
|
||||||
|
|||||||
Reference in New Issue
Block a user