mirror of
				https://github.com/owncast/owncast.git
				synced 2025-11-04 13:27:21 +08:00 
			
		
		
		
	Add Followers list and single follower component. Closes #1861
This commit is contained in:
		@ -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