refactor(stories): co-locate stories with components (#2078)

* refactor: move ActionButton component

* refactor: move BanUserButton component

* refactor: move ChatActionMessage component

* refactor: move ChatContainer component

* refactor: move AuthModal component

* refactor: move BrowserNotifyModal component

* refactor: move ChatUserMessage component

* refactor: move ChatJoinMessage component

* refactor: move ChatTextField component

* refactor: move ChatUserBadge component

* refactor: move FollowerCollection and SingleFollower components

* fix: bad import path

* refactor: move FollowModal component

* refactor: move Modal component

* refactor: move ContentHeader component

* refactor: move ChatSystemMessage component

* refactor: move Header component

* refactor: move Footer component

* refactor: move StatusBar component

* refactor: move OfflineBanner component

* refactor: move OwncastPlayer component

* refactor: move IndieAuthModal component

* refactor: move SocialLinks component

* refactor: move VideoPoster component

* refactor: move FollowModal component

* refactor: move FediAuthModal.tsx component

* refactor: move UserDropdown component

* refactor: move ChatSocialMessage component

* refactor: move Logo component

* refactor: move NotifyReminderPopup component

* refactor: move NameChangeModal component

* refactor: move FatalErrorStateModal component

* refactor: move ChatModeratorNotification component

* refactor: move ChatModerationActionMenu and ChatModerationDetailsModal components

* refactor: move CustomPageContent component

* refactor: move storybook Introduction file

* refactor: update storybook story import path

* refactor: move storybook preview styles

* refactor: move storybook doc pages

* refactor: move Color and ImageAsset components

* fix: bad import path

* fix: bad import path in story file
This commit is contained in:
James Young
2022-09-03 20:38:52 +02:00
committed by GitHub
parent 9f550a87d2
commit 5ebbbb8bf2
82 changed files with 120 additions and 121 deletions

View File

@@ -18,23 +18,23 @@ import {
} from '../../stores/ClientConfigStore';
import { ClientConfig } from '../../../interfaces/client-config.model';
import CustomPageContent from '../CustomPageContent/CustomPageContent';
import OwncastPlayer from '../../video/OwncastPlayer';
import FollowerCollection from '../Followers/FollowersCollection';
import OwncastPlayer from '../../video/OwncastPlayer/OwncastPlayer';
import FollowerCollection from '../followers/FollowerCollection/FollowerCollection';
import s from './Content.module.scss';
import Sidebar from '../Sidebar';
import Footer from '../Footer';
// import ChatContainer from '../../chat/ChatContainer';
// import { ChatMessage } from '../../../interfaces/chat-message.model';
// import ChatTextField from '../../chat/ChatTextField/ChatTextField';
import ActionButtonRow from '../../action-buttons/ActionButtonRow';
import ActionButton from '../../action-buttons/ActionButton';
import ActionButtonRow from '../../action-buttons/ActionButtonRow/ActionButtonRow';
import ActionButton from '../../action-buttons/ActionButton/ActionButton';
import NotifyReminderPopup from '../NotifyReminderPopup/NotifyReminderPopup';
import OfflineBanner from '../OfflineBanner/OfflineBanner';
import { AppStateOptions } from '../../stores/application-state';
import FollowButton from '../../action-buttons/FollowButton';
import NotifyButton from '../../action-buttons/NotifyButton';
import Modal from '../Modal/Modal';
import BrowserNotifyModal from '../../modals/BrowserNotify/BrowserNotifyModal';
import BrowserNotifyModal from '../../modals/BrowserNotifyModal/BrowserNotifyModal';
import ContentHeader from '../../common/ContentHeader';
import { ServerStatus } from '../../../interfaces/server-status.model';
import { StatusBar } from '..';

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,17 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import Footer from './Footer';
export default {
title: 'owncast/Layout/Footer',
component: Footer,
parameters: {},
} as ComponentMeta<typeof Footer>;
const Template: ComponentStory<typeof Footer> = args => <Footer {...args} />;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const Example = Template.bind({});
Example.args = {
version: 'v1.2.3',
};

View File

@@ -0,0 +1,28 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import Header from './Header';
export default {
title: 'owncast/Layout/Header',
component: Header,
parameters: {},
} as ComponentMeta<typeof Header>;
const Template: ComponentStory<typeof Header> = args => (
<RecoilRoot>
<Header {...args} />
</RecoilRoot>
);
export const ChatAvailable = Template.bind({});
ChatAvailable.args = {
name: 'Example Stream Name',
chatAvailable: true,
};
export const ChatNotAvailable = Template.bind({});
ChatNotAvailable.args = {
name: 'Example Stream Name',
chatAvailable: false,
};

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import Modal from './Modal';
export default {
title: 'owncast/Modals/Container',
component: Modal,
parameters: {
docs: {
description: {
component: `This is the popup modal container that all modal content is rendered inside. It can be passed content nodes to render, or a URL to show an iframe.`,
},
},
},
} as ComponentMeta<typeof Modal>;
const Template: ComponentStory<typeof Modal> = args => {
const { children } = args;
return <Modal {...args}>{children}</Modal>;
};
export const Example = Template.bind({});
Example.args = {
title: 'Modal example with content nodes',
visible: true,
children: <div>Test 123</div>,
};
export const UrlExample = Template.bind({});
UrlExample.args = {
title: 'Modal example with URL',
visible: true,
url: 'https://owncast.online',
};

View File

@@ -0,0 +1,48 @@
/* eslint-disable no-alert */
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import NotifyReminderPopup from './NotifyReminderPopup';
import Mock from '../../../stories/assets/mocks/notify-popup.png';
const Example = args => (
<div style={{ margin: '20px', marginTop: '130px' }}>
<NotifyReminderPopup {...args}>
<button type="button">notify button</button>
</NotifyReminderPopup>
</div>
);
export default {
title: 'owncast/Components/Notify Reminder',
component: NotifyReminderPopup,
parameters: {
design: {
type: 'image',
url: Mock,
},
docs: {
description: {
component: `After visiting the page three times this popup reminding you that you can register for live stream notifications shows up.
Clicking it will make the notification modal display. Clicking the "X" will hide the modal and make it never show again.`,
},
},
},
} as ComponentMeta<typeof NotifyReminderPopup>;
const Template: ComponentStory<typeof NotifyReminderPopup> = args => <Example {...args} />;
export const Active = Template.bind({});
Active.args = {
visible: true,
notificationClicked: () => {
alert('notification clicked');
},
notificationClosed: () => {
alert('notification closed');
},
};
export const InActive = Template.bind({});
InActive.args = {
visible: false,
};

View File

@@ -0,0 +1,35 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import OfflineBanner from './OfflineBanner';
import OfflineState from '../../../stories/assets/mocks/offline-state.png';
export default {
title: 'owncast/Layout/Offline Banner',
component: OfflineBanner,
parameters: {
design: {
type: 'image',
url: OfflineState,
scale: 0.5,
},
docs: {
description: {
component: `When the stream is offline the player should be replaced by this banner that can support custom text and notify actions.`,
},
},
},
} as ComponentMeta<typeof OfflineBanner>;
const Template: ComponentStory<typeof OfflineBanner> = args => <OfflineBanner {...args} />;
export const ExampleDefault = Template.bind({});
ExampleDefault.args = {
name: 'Cool stream 42',
text: 'To get notifications when <server name> is back online you can follow or ask for notifications.',
};
export const ExampleCustom = Template.bind({});
ExampleCustom.args = {
name: 'Dull stream 31337',
text: 'This is some example offline text that a streamer can leave for a visitor of the page.',
};

View File

@@ -0,0 +1,39 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import SocialLinks from './SocialLinks';
export default {
title: 'owncast/Components/Social links',
component: SocialLinks,
parameters: {},
} as ComponentMeta<typeof SocialLinks>;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const Template: ComponentStory<typeof SocialLinks> = args => <SocialLinks {...args} />;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const Populated = Template.bind({});
Populated.args = {
links: [
{
platform: 'github',
url: 'https://github.com/owncast/owncast',
icon: '/img/platformlogos/github.svg',
},
{
platform: 'Documentation',
url: 'https://owncast.online',
icon: '/img/platformlogos/link.svg',
},
{
platform: 'mastodon',
url: 'https://fosstodon.org/users/owncast',
icon: '/img/platformlogos/mastodon.svg',
},
],
};
export const Empty = Template.bind({});
Empty.args = {
links: [],
};

View File

@@ -0,0 +1,25 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { subHours } from 'date-fns';
import Statusbar from './Statusbar';
export default {
title: 'owncast/Player/Status bar',
component: Statusbar,
parameters: {},
} as ComponentMeta<typeof Statusbar>;
const Template: ComponentStory<typeof Statusbar> = args => <Statusbar {...args} />;
export const Online = Template.bind({});
Online.args = {
online: true,
viewerCount: 42,
lastConnectTime: subHours(new Date(), 3),
};
export const Offline = Template.bind({});
Offline.args = {
online: false,
lastDisconnectTime: subHours(new Date(), 3),
};

View File

@@ -0,0 +1,3 @@
.followers {
width: 100%;
}

View File

@@ -0,0 +1,233 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import FollowerCollection from './FollowerCollection';
export default {
title: 'owncast/Components/Followers/Followers collection',
component: FollowerCollection,
parameters: {},
} as ComponentMeta<typeof FollowerCollection>;
const Template: ComponentStory<typeof FollowerCollection> = (args: object) => (
<FollowerCollection {...args} />
);
export const NoFollowers = Template.bind({});
NoFollowers.args = { followers: [] };
export const Example = Template.bind({});
Example.args = {
followers: [
{
link: 'https://sun.minuscule.space/users/mardijker',
name: 'mardijker',
username: 'mardijker@sun.minuscule.space',
image:
'https://sun.minuscule.space/media/336af7ae5a2bcb508308eddb30b661ee2b2e15004a50795ee3ba0653ab190a93.jpg',
timestamp: '2022-04-27T12:12:50Z',
disabledAt: null,
},
{
link: 'https://mastodon.online/users/Kallegro',
name: '',
username: 'Kallegro@mastodon.online',
image: '',
timestamp: '2022-04-26T15:24:09Z',
disabledAt: null,
},
{
link: 'https://mastodon.online/users/kerfuffle',
name: 'Kerfuffle',
username: 'kerfuffle@mastodon.online',
image:
'https://files.mastodon.online/accounts/avatars/000/133/698/original/6aa73caa898b2d36.gif',
timestamp: '2022-04-25T21:32:41Z',
disabledAt: null,
},
{
link: 'https://mastodon.uno/users/informapirata',
name: 'informapirata :privacypride:',
username: 'informapirata@mastodon.uno',
image:
'https://cdn.masto.host/mastodonuno/accounts/avatars/000/060/227/original/da4c44c716a339b8.png',
timestamp: '2022-04-25T11:38:23Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/Raeanus',
name: 'Raeanus',
username: 'Raeanus@gamethattune.club',
image:
'https://gamethattune.club/media/a6e6ccea-34f8-4c2e-b9dc-ad8cca7fafd3/DD14E3BF-1358-4961-A900-42F3495F6BE2.jpeg',
timestamp: '2022-04-23T00:46:56Z',
disabledAt: null,
},
{
link: 'https://mastodon.ml/users/latte',
name: 'Даниил',
username: 'latte@mastodon.ml',
image:
'https://mastodon.ml/system/accounts/avatars/107/837/409/059/601/386/original/c45ec2676489e363.png',
timestamp: '2022-04-19T13:06:09Z',
disabledAt: null,
},
{
link: 'https://wienermobile.rentals/users/jprjr',
name: 'Johnny',
username: 'jprjr@wienermobile.rentals',
image: '',
timestamp: '2022-04-14T14:48:11Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/johnny',
name: 'John Regan',
username: 'johnny@gamethattune.club',
image:
'https://gamethattune.club/media/3c10cd89-866b-4604-ae40-39387fe17061/profile_large.jpg',
timestamp: '2022-04-14T14:42:48Z',
disabledAt: null,
},
{
link: 'https://mastodon.social/users/MightyOwlbear',
name: 'Haunted Owlbear',
username: 'MightyOwlbear@mastodon.social',
image:
'https://files.mastodon.social/accounts/avatars/107/246/961/007/605/352/original/a86fc3db97a6de04.jpg',
timestamp: '2022-04-14T13:33:03Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/thelinkfloyd',
name: 'thelinkfloyd',
username: 'thelinkfloyd@gamethattune.club',
image: '',
timestamp: '2022-04-05T12:23:32Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/TheBaffler',
name: 'TheBaffler',
username: 'TheBaffler@gamethattune.club',
image: '',
timestamp: '2022-04-04T19:50:08Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/Gttjessie',
name: 'Gttjessie',
username: 'Gttjessie@gamethattune.club',
image: '',
timestamp: '2022-03-30T20:18:47Z',
disabledAt: null,
},
{
link: 'https://cybre.space/users/fractal',
name: 'Le fractal',
username: 'fractal@cybre.space',
image:
'https://cybre.ams3.digitaloceanspaces.com/accounts/avatars/000/405/126/original/f1f2832a7bf1a967.png',
timestamp: '2022-03-30T19:46:17Z',
disabledAt: null,
},
{
link: 'https://fosstodon.org/users/jumboshrimp',
name: 'alex 👑🦐',
username: 'jumboshrimp@fosstodon.org',
image: 'https://cdn.fosstodon.org/accounts/avatars/000/320/316/original/de43cda8653ade7f.jpg',
timestamp: '2022-03-30T18:09:54Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/nvrslep303',
name: 'Tay',
username: 'nvrslep303@gamethattune.club',
image: 'https://gamethattune.club/media/5cf9bc27-8821-445a-86ce-8aa3704acf2d/pfp.jpg',
timestamp: '2022-03-30T15:27:49Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/anKerrigan',
name: 'anKerrigan',
username: 'anKerrigan@gamethattune.club',
image: '',
timestamp: '2022-03-30T14:47:04Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/jgangsta187',
name: 'jgangsta187',
username: 'jgangsta187@gamethattune.club',
image: '',
timestamp: '2022-03-30T14:42:52Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/aekre',
name: 'aekre',
username: 'aekre@gamethattune.club',
image: '',
timestamp: '2022-03-30T14:41:32Z',
disabledAt: null,
},
{
link: 'https://gamethattune.club/users/mork',
name: 'mork',
username: 'mork@gamethattune.club',
image: '',
timestamp: '2022-03-30T14:37:10Z',
disabledAt: null,
},
{
link: 'https://fosstodon.org/users/owncast',
name: 'Owncast',
username: 'owncast@fosstodon.org',
image:
'https://cdn.fosstodon.org/accounts/avatars/107/017/218/425/829/465/original/f98ba4cd61f483ab.png',
timestamp: '2022-03-29T21:38:02Z',
disabledAt: null,
},
{
link: 'https://cybre.space/users/wklew',
name: 'wally',
username: 'wklew@cybre.space',
image:
'https://cybre.ams3.digitaloceanspaces.com/accounts/avatars/000/308/727/original/7453e74f3e09b27b.jpg',
timestamp: '2022-03-29T18:24:29Z',
disabledAt: null,
},
{
link: 'https://mastodon.social/users/nvrslep303',
name: 'Tay',
username: 'nvrslep303@mastodon.social',
image:
'https://files.mastodon.social/accounts/avatars/108/041/196/166/285/851/original/fc444dd6096381af.jpg',
timestamp: '2022-03-29T18:19:31Z',
disabledAt: null,
},
{
link: 'https://mastodon.social/users/morky',
name: '',
username: 'morky@mastodon.social',
image: '',
timestamp: '2022-03-29T18:17:59Z',
disabledAt: null,
},
{
link: 'https://mastodon.social/users/jgangsta187',
name: 'John H.',
username: 'jgangsta187@mastodon.social',
image: '',
timestamp: '2022-03-29T18:15:48Z',
disabledAt: null,
},
{
link: 'https://fosstodon.org/users/meisam',
name: 'Meisam 🇪🇺:archlinux:',
username: 'meisam@fosstodon.org',
image: 'https://cdn.fosstodon.org/accounts/avatars/000/264/096/original/54b4e6db97206bda.jpg',
timestamp: '2022-03-29T18:12:21Z',
disabledAt: null,
},
],
};

View File

@@ -1,8 +1,8 @@
import { useEffect, useState } from 'react';
import { Col, Pagination, Row } from 'antd';
import { Follower } from '../../../interfaces/follower';
import SingleFollower from './Follower';
import s from './Followers.module.scss';
import { Follower } from '../../../../interfaces/follower';
import SingleFollower from '../SingleFollower/SingleFollower';
import s from '../SingleFollower/SingleFollower.module.scss';
export default function FollowerCollection() {
const ENDPOINT = '/api/followers';

View File

@@ -0,0 +1,33 @@
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import SingleFollower from './SingleFollower';
import SingleFollowerMock from '../../../../stories/assets/mocks/single-follower.png';
export default {
title: 'owncast/Components/Followers/Single Follower',
component: SingleFollower,
parameters: {
design: {
type: 'image',
url: SingleFollowerMock,
},
docs: {
description: {
component: `Represents a single follower.`,
},
},
},
} as ComponentMeta<typeof SingleFollower>;
const Template: ComponentStory<typeof SingleFollower> = args => <SingleFollower {...args} />;
export const Example = Template.bind({});
Example.args = {
follower: {
name: 'John Doe',
description: 'User',
username: '@account@domain.tld',
image: 'https://avatars0.githubusercontent.com/u/1234?s=460&v=4',
link: 'https://yahoo.com',
},
};

View File

@@ -1,7 +1,7 @@
import { Avatar, Col, Row } from 'antd';
import React from 'react';
import { Follower } from '../../../interfaces/follower';
import s from './Followers.module.scss';
import { Follower } from '../../../../interfaces/follower';
import s from './SingleFollower.module.scss';
interface Props {
follower: Follower;