diff --git a/web/components/action-buttons/ActionButton/ActionButton.stories.tsx b/web/components/action-buttons/ActionButton/ActionButton.stories.tsx index e174782dc..9e8023129 100644 --- a/web/components/action-buttons/ActionButton/ActionButton.stories.tsx +++ b/web/components/action-buttons/ActionButton/ActionButton.stories.tsx @@ -1,9 +1,8 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { ActionButton } from './ActionButton'; -export default { +const meta = { title: 'owncast/Components/Action Buttons/Single button', component: ActionButton, parameters: { @@ -13,38 +12,45 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; + +export default meta; const itemSelected = a => { console.log('itemSelected', a); action(a.title); }; -const Template: ComponentStory = args => ( +const Template: StoryFn = args => ( ); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Example1 = Template.bind({}); -Example1.args = { - action: { - url: 'https://owncast.online/docs', - title: 'Documentation', - description: 'Owncast Documentation', - icon: 'https://owncast.online/images/logo.svg', - color: '#5232c8', - openExternally: false, +export const Example1 = { + render: Template, + + args: { + action: { + url: 'https://owncast.online/docs', + title: 'Documentation', + description: 'Owncast Documentation', + icon: 'https://owncast.online/images/logo.svg', + color: '#5232c8', + openExternally: false, + }, }, }; -export const Example2 = Template.bind({}); -Example2.args = { - action: { - url: 'https://opencollective.com/embed/owncast/donate', - title: 'Support Owncast', - description: 'Contribute to Owncast', - icon: 'https://opencollective.com/static/images/opencollective-icon.svg', - color: '#2b4863', - openExternally: false, +export const Example2 = { + render: Template, + + args: { + action: { + url: 'https://opencollective.com/embed/owncast/donate', + title: 'Support Owncast', + description: 'Contribute to Owncast', + icon: 'https://opencollective.com/static/images/opencollective-icon.svg', + color: '#2b4863', + openExternally: false, + }, }, }; diff --git a/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.stories.tsx b/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.stories.tsx index ee65d20b4..12769546f 100644 --- a/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.stories.tsx +++ b/web/components/action-buttons/ActionButtonMenu/ActionButtonMenu.stories.tsx @@ -1,20 +1,21 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { ActionButtonMenu } from './ActionButtonMenu'; -export default { +const meta = { title: 'owncast/Components/Action Buttons/Action Menu', component: ActionButtonMenu, parameters: {}, -} as ComponentMeta; +} satisfies Meta; + +export default meta; const itemSelected = a => { console.log('itemSelected', a); action(a.title); }; -const Template: ComponentStory = args => ( +const Template: StoryFn = args => ( itemSelected(a)} /> ); @@ -37,26 +38,38 @@ const actions = [ }, ]; -export const Example = Template.bind({}); -Example.args = { - actions, +export const Example = { + render: Template, + + args: { + actions, + }, }; -export const ShowFollowExample = Template.bind({}); -ShowFollowExample.args = { - actions, - showFollowItem: true, +export const ShowFollowExample = { + render: Template, + + args: { + actions, + showFollowItem: true, + }, }; -export const ShowNotifyExample = Template.bind({}); -ShowNotifyExample.args = { - actions, - showNotifyItem: true, +export const ShowNotifyExample = { + render: Template, + + args: { + actions, + showNotifyItem: true, + }, }; -export const ShowNotifyAndFollowExample = Template.bind({}); -ShowNotifyAndFollowExample.args = { - actions, - showNotifyItem: true, - showFollowItem: true, +export const ShowNotifyAndFollowExample = { + render: Template, + + args: { + actions, + showNotifyItem: true, + showFollowItem: true, + }, }; diff --git a/web/components/action-buttons/ActionButtonRow/ActionButtonRow.stories.tsx b/web/components/action-buttons/ActionButtonRow/ActionButtonRow.stories.tsx index d0afab5fd..4a549dd09 100644 --- a/web/components/action-buttons/ActionButtonRow/ActionButtonRow.stories.tsx +++ b/web/components/action-buttons/ActionButtonRow/ActionButtonRow.stories.tsx @@ -1,10 +1,9 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { action } from '@storybook/addon-actions'; import { ActionButtonRow } from './ActionButtonRow'; import { ActionButton } from '../ActionButton/ActionButton'; -export default { +const meta = { title: 'owncast/Components/Action Buttons/Buttons Row', component: ActionButtonRow, parameters: { @@ -15,15 +14,15 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = args => { +export default meta; + +const Template: StoryFn = args => { const { buttons } = args as any; return {buttons}; }; -// eslint-disable-next-line @typescript-eslint/no-unused-vars const actions = [ { url: 'https://owncast.online/docs', @@ -49,7 +48,11 @@ const itemSelected = a => { }; const buttons = actions.map(a => ); -export const Example1 = Template.bind({}); -Example1.args = { - buttons, + +export const Example1 = { + render: Template, + + args: { + buttons, + }, }; diff --git a/web/components/chat/ChatActionMessage/ChatActionMessage.stories.tsx b/web/components/chat/ChatActionMessage/ChatActionMessage.stories.tsx index 74c8c71b1..f1e78105b 100644 --- a/web/components/chat/ChatActionMessage/ChatActionMessage.stories.tsx +++ b/web/components/chat/ChatActionMessage/ChatActionMessage.stories.tsx @@ -1,9 +1,8 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatActionMessage } from './ChatActionMessage'; import Mock from '../../../stories/assets/mocks/chatmessage-action.png'; -export default { +const meta = { title: 'owncast/Chat/Messages/Chat action', component: ChatActionMessage, parameters: { @@ -17,11 +16,12 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const Basic = Template.bind({}); -Basic.args = { - body: 'This is a basic action message.', +export const Basic = { + args: { + body: 'This is a basic action message.', + }, }; diff --git a/web/components/chat/ChatContainer/ChatContainer.stories.tsx b/web/components/chat/ChatContainer/ChatContainer.stories.tsx index a9b034fea..57f25b7a0 100644 --- a/web/components/chat/ChatContainer/ChatContainer.stories.tsx +++ b/web/components/chat/ChatContainer/ChatContainer.stories.tsx @@ -1,10 +1,10 @@ -import React, { useState } from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { useState } from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { ChatContainer } from './ChatContainer'; import { ChatMessage } from '../../../interfaces/chat-message.model'; -export default { +const meta = { title: 'owncast/Chat/Chat messages container', component: ChatContainer, parameters: { @@ -19,7 +19,9 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; + +export default meta; const testMessages = `[ { @@ -586,37 +588,46 @@ const AddMessagesChatExample = args => { ); }; -const Template: ComponentStory = args => ; +const Template: StoryFn = args => ; -export const Example = Template.bind({}); -Example.args = { - loading: false, - messages, - usernameToHighlight: 'testuser', - chatUserId: 'testuser', - isModerator: true, - showInput: true, - chatAvailable: true, +export const Example = { + render: Template, + + args: { + loading: false, + messages, + usernameToHighlight: 'testuser', + chatUserId: 'testuser', + isModerator: true, + showInput: true, + chatAvailable: true, + }, }; -export const ChatDisabled = Template.bind({}); -ChatDisabled.args = { - loading: false, - messages, - usernameToHighlight: 'testuser', - chatUserId: 'testuser', - isModerator: true, - showInput: true, - chatAvailable: false, +export const ChatDisabled = { + render: Template, + + args: { + loading: false, + messages, + usernameToHighlight: 'testuser', + chatUserId: 'testuser', + isModerator: true, + showInput: true, + chatAvailable: false, + }, }; -export const SingleMessage = Template.bind({}); -SingleMessage.args = { - loading: false, - messages: [messages[0]], - usernameToHighlight: 'testuser', - chatUserId: 'testuser', - isModerator: true, - showInput: true, - chatAvailable: true, +export const SingleMessage = { + render: Template, + + args: { + loading: false, + messages: [messages[0]], + usernameToHighlight: 'testuser', + chatUserId: 'testuser', + isModerator: true, + showInput: true, + chatAvailable: true, + }, }; diff --git a/web/components/chat/ChatJoinMessage/ChatJoinMessage.stories.tsx b/web/components/chat/ChatJoinMessage/ChatJoinMessage.stories.tsx index 474931fb0..31d5888a4 100644 --- a/web/components/chat/ChatJoinMessage/ChatJoinMessage.stories.tsx +++ b/web/components/chat/ChatJoinMessage/ChatJoinMessage.stories.tsx @@ -1,9 +1,8 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatJoinMessage } from './ChatJoinMessage'; import Mock from '../../../stories/assets/mocks/chatmessage-action.png'; -export default { +const meta = { title: 'owncast/Chat/Messages/Chat Join', component: ChatJoinMessage, argTypes: { @@ -23,20 +22,22 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const Regular = Template.bind({}); -Regular.args = { - displayName: 'RandomChatter', - isAuthorModerator: false, - userColor: 3, +export const Regular = { + args: { + displayName: 'RandomChatter', + isAuthorModerator: false, + userColor: 3, + }, }; -export const Moderator = Template.bind({}); -Moderator.args = { - displayName: 'RandomChatter', - isAuthorModerator: true, - userColor: 2, +export const Moderator = { + args: { + displayName: 'RandomChatter', + isAuthorModerator: true, + userColor: 2, + }, }; diff --git a/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.stories.tsx b/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.stories.tsx index 80a24162a..249160b68 100644 --- a/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.stories.tsx +++ b/web/components/chat/ChatModerationActionMenu/ChatModerationActionMenu.stories.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { ChatModerationActionMenu } from './ChatModerationActionMenu'; @@ -64,7 +63,7 @@ const mocks = { ], }; -export default { +const meta = { title: 'owncast/Chat/Moderation menu', component: ChatModerationActionMenu, parameters: { @@ -79,10 +78,11 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = () => ( +export default meta; + +const Template: StoryFn = () => ( = () => ( ); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); +export const Basic = { + render: Template, +}; diff --git a/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.stories.tsx b/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.stories.tsx index 85d102d84..3b44e9ba6 100644 --- a/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.stories.tsx +++ b/web/components/chat/ChatModerationDetailsModal/ChatModerationDetailsModal.stories.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { ChatModerationDetailsModal } from './ChatModerationDetailsModal'; @@ -64,7 +63,7 @@ const mocks = { ], }; -export default { +const meta = { title: 'owncast/Chat/Moderation modal', component: ChatModerationDetailsModal, parameters: { @@ -79,14 +78,16 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = () => ( +export default meta; + +const Template: StoryFn = () => ( ); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Example = Template.bind({}); +export const Example = { + render: Template, +}; diff --git a/web/components/chat/ChatModeratorNotification/ChatModeratorNotification.stories.tsx b/web/components/chat/ChatModeratorNotification/ChatModeratorNotification.stories.tsx index 297f93c61..7cb1dec69 100644 --- a/web/components/chat/ChatModeratorNotification/ChatModeratorNotification.stories.tsx +++ b/web/components/chat/ChatModeratorNotification/ChatModeratorNotification.stories.tsx @@ -1,17 +1,12 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatModeratorNotification } from './ChatModeratorNotification'; -export default { +const meta = { title: 'owncast/Chat/Messages/Moderation Role Notification', component: ChatModeratorNotification, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = (args: object) => ( - -); +export default meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); +export const Basic = {}; diff --git a/web/components/chat/ChatNameChangeMessage/ChatNameChangeMessage.stories.tsx b/web/components/chat/ChatNameChangeMessage/ChatNameChangeMessage.stories.tsx index e778cc46b..e32c38b37 100644 --- a/web/components/chat/ChatNameChangeMessage/ChatNameChangeMessage.stories.tsx +++ b/web/components/chat/ChatNameChangeMessage/ChatNameChangeMessage.stories.tsx @@ -1,23 +1,21 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatNameChangeMessage } from './ChatNameChangeMessage'; -export default { +const meta = { title: 'owncast/Chat/Messages/Chat name change', component: ChatNameChangeMessage, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ( - -); +export default meta; -export const Basic = Template.bind({}); -Basic.args = { - message: { - oldName: 'JohnnyOldName', - user: { - displayName: 'JohnnyNewName', - displayColor: '3', +export const Basic = { + args: { + message: { + oldName: 'JohnnyOldName', + user: { + displayName: 'JohnnyNewName', + displayColor: '3', + }, }, }, }; diff --git a/web/components/chat/ChatPartMessage/ChatPartMessage.stories.tsx b/web/components/chat/ChatPartMessage/ChatPartMessage.stories.tsx index 92cbb9a0c..de62a4bbe 100644 --- a/web/components/chat/ChatPartMessage/ChatPartMessage.stories.tsx +++ b/web/components/chat/ChatPartMessage/ChatPartMessage.stories.tsx @@ -1,9 +1,8 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatPartMessage } from './ChatPartMessage'; import Mock from '../../../stories/assets/mocks/chatmessage-action.png'; -export default { +const meta = { title: 'owncast/Chat/Messages/Chat Part', component: ChatPartMessage, argTypes: { @@ -23,20 +22,22 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const Regular = Template.bind({}); -Regular.args = { - displayName: 'RandomChatter', - isAuthorModerator: false, - userColor: 3, +export const Regular = { + args: { + displayName: 'RandomChatter', + isAuthorModerator: false, + userColor: 3, + }, }; -export const Moderator = Template.bind({}); -Moderator.args = { - displayName: 'RandomChatter', - isAuthorModerator: true, - userColor: 2, +export const Moderator = { + args: { + displayName: 'RandomChatter', + isAuthorModerator: true, + userColor: 2, + }, }; diff --git a/web/components/chat/ChatSocialMessage/ChatSocialMessage.stories.tsx b/web/components/chat/ChatSocialMessage/ChatSocialMessage.stories.tsx index 51c51a938..39273d88f 100644 --- a/web/components/chat/ChatSocialMessage/ChatSocialMessage.stories.tsx +++ b/web/components/chat/ChatSocialMessage/ChatSocialMessage.stories.tsx @@ -1,66 +1,70 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatSocialMessage } from './ChatSocialMessage'; -export default { +const meta = { title: 'owncast/Chat/Messages/Social-fediverse event', component: ChatSocialMessage, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const Follow = Template.bind({}); -Follow.args = { - message: { - type: 'FEDIVERSE_ENGAGEMENT_FOLLOW', - body: '

james followed this live stream.

', - title: 'james@mastodon.social', - image: 'https://mastodon.social/avatars/original/missing.png', - link: 'https://mastodon.social/@james', +export const Follow = { + args: { + message: { + type: 'FEDIVERSE_ENGAGEMENT_FOLLOW', + body: '

james followed this live stream.

', + title: 'james@mastodon.social', + image: 'https://mastodon.social/avatars/original/missing.png', + link: 'https://mastodon.social/@james', + }, }, }; -export const Like = Template.bind({}); -Like.args = { - message: { - type: 'FEDIVERSE_ENGAGEMENT_LIKE', - body: '

james liked that this stream went live.

', - title: 'james@mastodon.social', - image: 'https://mastodon.social/avatars/original/missing.png', - link: 'https://mastodon.social/@james', +export const Like = { + args: { + message: { + type: 'FEDIVERSE_ENGAGEMENT_LIKE', + body: '

james liked that this stream went live.

', + title: 'james@mastodon.social', + image: 'https://mastodon.social/avatars/original/missing.png', + link: 'https://mastodon.social/@james', + }, }, }; -export const Repost = Template.bind({}); -Repost.args = { - message: { - type: 'FEDIVERSE_ENGAGEMENT_REPOST', - body: '

james shared this stream with their followers.

', - title: 'james@mastodon.social', - image: 'https://mastodon.social/avatars/original/missing.png', - link: 'https://mastodon.social/@james', +export const Repost = { + args: { + message: { + type: 'FEDIVERSE_ENGAGEMENT_REPOST', + body: '

james shared this stream with their followers.

', + title: 'james@mastodon.social', + image: 'https://mastodon.social/avatars/original/missing.png', + link: 'https://mastodon.social/@james', + }, }, }; -export const LongAccountName = Template.bind({}); -LongAccountName.args = { - message: { - type: 'FEDIVERSE_ENGAGEMENT_REPOST', - body: '

james shared this stream with their followers.

', - title: 'littlejimmywilliams@technology.biz.net.org.technology.gov', - image: 'https://mastodon.social/avatars/original/missing.png', - link: 'https://mastodon.social/@james', +export const LongAccountName = { + args: { + message: { + type: 'FEDIVERSE_ENGAGEMENT_REPOST', + body: '

james shared this stream with their followers.

', + title: 'littlejimmywilliams@technology.biz.net.org.technology.gov', + image: 'https://mastodon.social/avatars/original/missing.png', + link: 'https://mastodon.social/@james', + }, }, }; -export const InvalidAvatarImage = Template.bind({}); -InvalidAvatarImage.args = { - message: { - type: 'FEDIVERSE_ENGAGEMENT_REPOST', - body: '

james shared this stream with their followers.

', - title: 'james@mastodon.social', - image: 'https://xx.xx/avatars/original/missing.png', - link: 'https://mastodon.social/@james', +export const InvalidAvatarImage = { + args: { + message: { + type: 'FEDIVERSE_ENGAGEMENT_REPOST', + body: '

james shared this stream with their followers.

', + title: 'james@mastodon.social', + image: 'https://xx.xx/avatars/original/missing.png', + link: 'https://mastodon.social/@james', + }, }, }; diff --git a/web/components/chat/ChatSystemMessage/ChatSystemMessage.stories.tsx b/web/components/chat/ChatSystemMessage/ChatSystemMessage.stories.tsx index b0c207ace..580f5f420 100644 --- a/web/components/chat/ChatSystemMessage/ChatSystemMessage.stories.tsx +++ b/web/components/chat/ChatSystemMessage/ChatSystemMessage.stories.tsx @@ -1,10 +1,9 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ChatSystemMessage } from './ChatSystemMessage'; import Mock from '../../../stories/assets/mocks/chatmessage-system.png'; import { ChatMessage } from '../../../interfaces/chat-message.model'; -export default { +const meta = { title: 'owncast/Chat/Messages/System', component: ChatSystemMessage, parameters: { @@ -18,9 +17,9 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; const message: ChatMessage = JSON.parse(`{ "type": "SYSTEM", @@ -34,14 +33,15 @@ const message: ChatMessage = JSON.parse(`{ }, "body": "Test system message from the chat server."}`); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); -Basic.args = { - message, +export const Basic = { + args: { + message, + }, }; -export const HighlightExample = Template.bind({}); -HighlightExample.args = { - message, - highlightString: 'chat', +export const HighlightExample = { + args: { + message, + highlightString: 'chat', + }, }; diff --git a/web/components/chat/ChatTextField/ChatTextField.stories.tsx b/web/components/chat/ChatTextField/ChatTextField.stories.tsx index 5f1c7aea7..eb328f78a 100644 --- a/web/components/chat/ChatTextField/ChatTextField.stories.tsx +++ b/web/components/chat/ChatTextField/ChatTextField.stories.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { ChatTextField } from './ChatTextField'; import Mockup from '../../../stories/assets/mocks/chatinput-mock.png'; @@ -28,7 +27,7 @@ const mocks = { ], }; -export default { +const meta = { title: 'owncast/Chat/Input text field', component: ChatTextField, parameters: { @@ -48,43 +47,54 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ( +export default meta; + +const Template: StoryFn = args => ( ); -export const Example = Template.bind({}); -Example.args = { - enabled: true, +export const Example = { + render: Template, + + args: { + enabled: true, + }, }; -export const LongerMessage = Template.bind({}); -LongerMessage.args = { - enabled: true, - defaultText: - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', -}; +export const LongerMessage = { + render: Template, -LongerMessage.parameters = { - docs: { - description: { - story: 'Should display two lines of text and scroll to display more.', + args: { + enabled: true, + defaultText: + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', + }, + + parameters: { + docs: { + description: { + story: 'Should display two lines of text and scroll to display more.', + }, }, }, }; -export const DisabledChat = Template.bind({}); -DisabledChat.args = { - enabled: false, -}; +export const DisabledChat = { + render: Template, -DisabledChat.parameters = { - docs: { - description: { - story: 'Should not allow you to type anything and should state that chat is disabled.', + args: { + enabled: false, + }, + + parameters: { + docs: { + description: { + story: 'Should not allow you to type anything and should state that chat is disabled.', + }, }, }, }; diff --git a/web/components/chat/ChatUserBadge/ChatUserBadge.stories.tsx b/web/components/chat/ChatUserBadge/ChatUserBadge.stories.tsx index 640c931dd..eaa7e495f 100644 --- a/web/components/chat/ChatUserBadge/ChatUserBadge.stories.tsx +++ b/web/components/chat/ChatUserBadge/ChatUserBadge.stories.tsx @@ -1,11 +1,10 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { ChatUserBadge } from './ChatUserBadge'; import { ModerationBadge } from './ModerationBadge'; import { AuthedUserBadge } from './AuthedUserBadge'; import { BotUserBadge } from './BotUserBadge'; -export default { +const meta = { title: 'owncast/Chat/Messages/User Flag', component: ChatUserBadge, argTypes: { @@ -14,36 +13,43 @@ export default { control: { type: 'select' }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; -const ModerationTemplate: ComponentStory = args => ( - -); +export default meta; -const AuthedTemplate: ComponentStory = args => ( - -); +const ModerationTemplate: StoryFn = args => ; -const BotTemplate: ComponentStory = args => ; +const AuthedTemplate: StoryFn = args => ; -export const Authenticated = AuthedTemplate.bind({}); -Authenticated.args = { - userColor: '3', +const BotTemplate: StoryFn = args => ; + +export const Authenticated = { + render: AuthedTemplate, + + args: { + userColor: '3', + }, }; -export const Moderator = ModerationTemplate.bind({}); -Moderator.args = { - userColor: '5', +export const Moderator = { + render: ModerationTemplate, + + args: { + userColor: '5', + }, }; -export const Bot = BotTemplate.bind({}); -Bot.args = { - userColor: '7', +export const Bot = { + render: BotTemplate, + + args: { + userColor: '7', + }, }; -export const Generic = Template.bind({}); -Generic.args = { - badge: '?', - userColor: '6', +export const Generic = { + args: { + badge: '?', + userColor: '6', + }, }; diff --git a/web/components/chat/ChatUserMessage/ChatUserMessage.stories.tsx b/web/components/chat/ChatUserMessage/ChatUserMessage.stories.tsx index 09829c166..22a9fdf48 100644 --- a/web/components/chat/ChatUserMessage/ChatUserMessage.stories.tsx +++ b/web/components/chat/ChatUserMessage/ChatUserMessage.stories.tsx @@ -1,11 +1,10 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { ChatUserMessage } from './ChatUserMessage'; import { ChatMessage } from '../../../interfaces/chat-message.model'; import Mock from '../../../stories/assets/mocks/chatmessage-user.png'; -export default { +const meta = { title: 'owncast/Chat/Messages/Standard user', component: ChatUserMessage, parameters: { @@ -20,9 +19,11 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ( +export default meta; + +const Template: StoryFn = args => ( @@ -105,48 +106,69 @@ const botUserMessage: ChatMessage = JSON.parse(`{ }, "body": "I am a bot."}`); -export const WithoutModeratorMenu = Template.bind({}); -WithoutModeratorMenu.args = { - message: standardMessage, - showModeratorMenu: false, +export const WithoutModeratorMenu = { + render: Template, + + args: { + message: standardMessage, + showModeratorMenu: false, + }, }; -export const WithLinkAndCustomEmoji = Template.bind({}); -WithLinkAndCustomEmoji.args = { - message: messageWithLinkAndCustomEmoji, - showModeratorMenu: false, +export const WithLinkAndCustomEmoji = { + render: Template, + + args: { + message: messageWithLinkAndCustomEmoji, + showModeratorMenu: false, + }, }; -export const WithModeratorMenu = Template.bind({}); -WithModeratorMenu.args = { - message: standardMessage, - showModeratorMenu: true, +export const WithModeratorMenu = { + render: Template, + + args: { + message: standardMessage, + showModeratorMenu: true, + }, }; -export const FromModeratorUser = Template.bind({}); -FromModeratorUser.args = { - message: moderatorMessage, - showModeratorMenu: false, - isAuthorModerator: true, +export const FromModeratorUser = { + render: Template, + + args: { + message: moderatorMessage, + showModeratorMenu: false, + isAuthorModerator: true, + }, }; -export const FromAuthenticatedUser = Template.bind({}); -FromAuthenticatedUser.args = { - message: authenticatedUserMessage, - showModeratorMenu: false, - isAuthorAuthenticated: true, +export const FromAuthenticatedUser = { + render: Template, + + args: { + message: authenticatedUserMessage, + showModeratorMenu: false, + isAuthorAuthenticated: true, + }, }; -export const FromBotUser = Template.bind({}); -FromBotUser.args = { - message: botUserMessage, - showModeratorMenu: false, - isAuthorBot: true, +export const FromBotUser = { + render: Template, + + args: { + message: botUserMessage, + showModeratorMenu: false, + isAuthorBot: true, + }, }; -export const WithStringHighlighted = Template.bind({}); -WithStringHighlighted.args = { - message: standardMessage, - showModeratorMenu: false, - highlightString: 'message', +export const WithStringHighlighted = { + render: Template, + + args: { + message: standardMessage, + showModeratorMenu: false, + highlightString: 'message', + }, }; diff --git a/web/components/common/ContentHeader/ContentHeader.stories.tsx b/web/components/common/ContentHeader/ContentHeader.stories.tsx index dd313ffb2..b98496f09 100644 --- a/web/components/common/ContentHeader/ContentHeader.stories.tsx +++ b/web/components/common/ContentHeader/ContentHeader.stories.tsx @@ -1,76 +1,77 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ContentHeader } from './ContentHeader'; -export default { +const meta = { title: 'owncast/Components/Content Header', component: ContentHeader, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const Example = Template.bind({}); -Example.args = { - name: 'My Awesome Owncast Stream', - summary: 'A calvacade of glorious sights and sounds', - tags: ['word', 'tag with spaces', 'music'], - logo: 'https://watch.owncast.online/logo', - links: [ - { - platform: 'github', - url: 'https://github.com/owncast/owncast', - icon: 'https://watch.owncast.online/img/platformlogos/github.svg', - }, - { - platform: 'Documentation', - url: 'https://owncast.online', - icon: 'https://watch.owncast.online/img/platformlogos/link.svg', - }, - { - platform: 'mastodon', - url: 'https://fosstodon.org/users/owncast', - icon: 'https://watch.owncast.online/img/platformlogos/mastodon.svg', - }, - ], +export const Example = { + args: { + name: 'My Awesome Owncast Stream', + summary: 'A calvacade of glorious sights and sounds', + tags: ['word', 'tag with spaces', 'music'], + logo: 'https://watch.owncast.online/logo', + links: [ + { + platform: 'github', + url: 'https://github.com/owncast/owncast', + icon: 'https://watch.owncast.online/img/platformlogos/github.svg', + }, + { + platform: 'Documentation', + url: 'https://owncast.online', + icon: 'https://watch.owncast.online/img/platformlogos/link.svg', + }, + { + platform: 'mastodon', + url: 'https://fosstodon.org/users/owncast', + icon: 'https://watch.owncast.online/img/platformlogos/mastodon.svg', + }, + ], + }, }; -export const LongContent = Template.bind({}); -LongContent.args = { - name: 'My Awesome Owncast Stream, streaming the best of streams and some lorem ipsum too', - summary: - 'A calvacade of glorious sights and sounds. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', - tags: [ - 'word', - 'tag with spaces', - 'music', - 'more tags', - 'a bunch', - 'keep going', - 'and more', - 'just a few more', - 'video games', - 'things', - 'stuff', - 'ok some more', - 'this should do it', - ], - logo: 'https://watch.owncast.online/logo', - links: [ - { - platform: 'github', - url: 'https://github.com/owncast/owncast', - icon: 'https://watch.owncast.online/img/platformlogos/github.svg', - }, - { - platform: 'Documentation', - url: 'https://owncast.online', - icon: 'https://watch.owncast.online/img/platformlogos/link.svg', - }, - { - platform: 'mastodon', - url: 'https://fosstodon.org/users/owncast', - icon: 'https://watch.owncast.online/img/platformlogos/mastodon.svg', - }, - ], +export const LongContent = { + args: { + name: 'My Awesome Owncast Stream, streaming the best of streams and some lorem ipsum too', + summary: + 'A calvacade of glorious sights and sounds. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.', + tags: [ + 'word', + 'tag with spaces', + 'music', + 'more tags', + 'a bunch', + 'keep going', + 'and more', + 'just a few more', + 'video games', + 'things', + 'stuff', + 'ok some more', + 'this should do it', + ], + logo: 'https://watch.owncast.online/logo', + links: [ + { + platform: 'github', + url: 'https://github.com/owncast/owncast', + icon: 'https://watch.owncast.online/img/platformlogos/github.svg', + }, + { + platform: 'Documentation', + url: 'https://owncast.online', + icon: 'https://watch.owncast.online/img/platformlogos/link.svg', + }, + { + platform: 'mastodon', + url: 'https://fosstodon.org/users/owncast', + icon: 'https://watch.owncast.online/img/platformlogos/mastodon.svg', + }, + ], + }, }; diff --git a/web/components/common/OwncastLogo/OwncastLogo.stories.tsx b/web/components/common/OwncastLogo/OwncastLogo.stories.tsx index 3ceaabb4e..3481f26ad 100644 --- a/web/components/common/OwncastLogo/OwncastLogo.stories.tsx +++ b/web/components/common/OwncastLogo/OwncastLogo.stories.tsx @@ -1,25 +1,24 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { OwncastLogo } from './OwncastLogo'; -export default { +const meta = { title: 'owncast/Components/Header Logo', component: OwncastLogo, parameters: { chromatic: { diffThreshold: 0.8 }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = args => ; +export default meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Logo = Template.bind({}); -Logo.args = { - url: '/logo', +export const Logo = { + args: { + url: '/logo', + }, }; -export const DemoServer = Template.bind({}); -DemoServer.args = { - url: 'https://watch.owncast.online/logo', +export const DemoServer = { + args: { + url: 'https://watch.owncast.online/logo', + }, }; diff --git a/web/components/common/UserDropdown/UserDropdown.stories.tsx b/web/components/common/UserDropdown/UserDropdown.stories.tsx index 019452b83..6c907f295 100644 --- a/web/components/common/UserDropdown/UserDropdown.stories.tsx +++ b/web/components/common/UserDropdown/UserDropdown.stories.tsx @@ -1,15 +1,17 @@ -import React, { useEffect } from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { useEffect } from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; import { UserDropdown } from './UserDropdown'; import { CurrentUser } from '../../../interfaces/current-user'; import { currentUserAtom } from '../../stores/ClientConfigStore'; -export default { +const meta = { title: 'owncast/Components/User settings menu', component: UserDropdown, parameters: {}, -} as ComponentMeta; +} satisfies Meta; + +export default meta; // This component uses Recoil internally so wrap it in a RecoilRoot. const Example = args => { @@ -29,13 +31,16 @@ const Example = args => { return ; }; -const Template: ComponentStory = args => ( +const Template: StoryFn = args => ( ); -export const ChatEnabled = Template.bind({}); -ChatEnabled.args = { - username: 'test-user', +export const ChatEnabled = { + render: Template, + + args: { + username: 'test-user', + }, }; diff --git a/web/components/layouts/Main/Main.stories.tsx b/web/components/layouts/Main/Main.stories.tsx index 417dcae6c..fccf6329c 100644 --- a/web/components/layouts/Main/Main.stories.tsx +++ b/web/components/layouts/Main/Main.stories.tsx @@ -1,4 +1,4 @@ -import { ComponentMeta, ComponentStory } from '@storybook/react'; +import { Meta, StoryFn, StoryObj } from '@storybook/react'; import { MutableSnapshot, RecoilRoot } from 'recoil'; import { makeEmptyClientConfig } from '../../../interfaces/client-config.model'; import { ServerStatus, makeEmptyServerStatus } from '../../../interfaces/server-status.model'; @@ -30,12 +30,14 @@ import videoSettingsServiceMockOf from '../../../services/video-settings-service import { spidermanUser } from '../../../interfaces/user.fixture'; import { exampleChatHistory } from '../../../interfaces/chat-message.fixture'; -export default { +const meta = { title: 'owncast/Layout/Main', parameters: { layout: 'fullscreen', }, -} satisfies ComponentMeta; +} satisfies Meta; + +export default meta; // mock the Websocket to prevent ani webhook calls from being made in storybook // @ts-ignore @@ -92,7 +94,7 @@ const DefaultServerStatusServiceMock = serverStatusServiceMockOf(defaultServerSt const OnlineServerStatusServiceMock = serverStatusServiceMockOf(onlineServerStatus); const VideoSettingsServiceMock = videoSettingsServiceMockOf([]); -const Template: ComponentStory = ({ +const Template: StoryFn = ({ initializeState, ServerStatusServiceMock = DefaultServerStatusServiceMock, ...args @@ -113,57 +115,79 @@ const Template: ComponentStory = ({ ); -export const OfflineDesktop: typeof Template = Template.bind({}); -OfflineDesktop.parameters = { - chromatic: { diffThreshold: 0.88 }, -}; +export const OfflineDesktop: StoryObj = { + render: Template, -export const OfflineMobile: typeof Template = Template.bind({}); -OfflineMobile.args = { - initializeState: (mutableState: MutableSnapshot) => { - mutableState.set(isMobileAtom, true); - }, -}; -OfflineMobile.parameters = { - viewport: { - defaultViewport: 'mobile1', + parameters: { + chromatic: { diffThreshold: 0.88 }, }, }; -export const OfflineTablet: typeof Template = Template.bind({}); -OfflineTablet.parameters = { - viewport: { - defaultViewport: 'tablet', +export const OfflineMobile: StoryObj = { + render: Template, + + args: { + initializeState: (mutableState: MutableSnapshot) => { + mutableState.set(isMobileAtom, true); + }, + }, + + parameters: { + viewport: { + defaultViewport: 'mobile1', + }, }, }; -export const Online: typeof Template = Template.bind({}); -Online.args = { - ServerStatusServiceMock: OnlineServerStatusServiceMock, -}; -Online.parameters = { - chromatic: { diffThreshold: 0.88 }, -}; +export const OfflineTablet: StoryObj = { + render: Template, -export const OnlineMobile: typeof Template = Online.bind({}); -OnlineMobile.args = { - ServerStatusServiceMock: OnlineServerStatusServiceMock, - initializeState: (mutableState: MutableSnapshot) => { - mutableState.set(isMobileAtom, true); - }, -}; -OnlineMobile.parameters = { - viewport: { - defaultViewport: 'mobile1', + parameters: { + viewport: { + defaultViewport: 'tablet', + }, }, }; -export const OnlineTablet: typeof Template = Online.bind({}); -OnlineTablet.args = { - ServerStatusServiceMock: OnlineServerStatusServiceMock, -}; -OnlineTablet.parameters = { - viewport: { - defaultViewport: 'tablet', +export const Online: StoryObj = { + render: Template, + + args: { + ServerStatusServiceMock: OnlineServerStatusServiceMock, + }, + + parameters: { + chromatic: { diffThreshold: 0.88 }, + }, +}; + +export const OnlineMobile: StoryObj = { + render: Template, + + args: { + ServerStatusServiceMock: OnlineServerStatusServiceMock, + initializeState: (mutableState: MutableSnapshot) => { + mutableState.set(isMobileAtom, true); + }, + }, + + parameters: { + viewport: { + defaultViewport: 'mobile1', + }, + }, +}; + +export const OnlineTablet: StoryObj = { + render: Template, + + args: { + ServerStatusServiceMock: OnlineServerStatusServiceMock, + }, + + parameters: { + viewport: { + defaultViewport: 'tablet', + }, }, }; diff --git a/web/components/modals/AuthModal/AuthModal.stories.tsx b/web/components/modals/AuthModal/AuthModal.stories.tsx index 5906a2faa..ed5c252fa 100644 --- a/web/components/modals/AuthModal/AuthModal.stories.tsx +++ b/web/components/modals/AuthModal/AuthModal.stories.tsx @@ -1,5 +1,5 @@ -import React, { useEffect } from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { useEffect } from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; import { AuthModal } from './AuthModal'; import { currentUserAtom } from '../../stores/ClientConfigStore'; @@ -26,17 +26,20 @@ const Example = () => { ); }; -export default { +const meta = { title: 'owncast/Modals/Auth', component: AuthModal, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = () => ( +export default meta; + +const Template: StoryFn = () => ( ); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); +export const Basic = { + render: Template, +}; diff --git a/web/components/modals/BrowserNotifyModal/BrowserNotifyModal.stories.tsx b/web/components/modals/BrowserNotifyModal/BrowserNotifyModal.stories.tsx index 15110182f..090db1247 100644 --- a/web/components/modals/BrowserNotifyModal/BrowserNotifyModal.stories.tsx +++ b/web/components/modals/BrowserNotifyModal/BrowserNotifyModal.stories.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { BrowserNotifyModal } from './BrowserNotifyModal'; import BrowserNotifyModalMock from '../../../stories/assets/mocks/notify-modal.png'; @@ -10,7 +9,7 @@ const Example = () => ( ); -export default { +const meta = { title: 'owncast/Modals/Browser Notifications', component: BrowserNotifyModal, parameters: { @@ -31,14 +30,16 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = () => ( +export default meta; + +const Template: StoryFn = () => ( ); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); +export const Basic = { + render: Template, +}; diff --git a/web/components/modals/ChatModal/ChatModal.stories.tsx b/web/components/modals/ChatModal/ChatModal.stories.tsx index bcf7e31e2..50f3f8e70 100644 --- a/web/components/modals/ChatModal/ChatModal.stories.tsx +++ b/web/components/modals/ChatModal/ChatModal.stories.tsx @@ -1,21 +1,21 @@ -/* eslint-disable object-shorthand */ - -import React, { useEffect } from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { useEffect } from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; import { ChatModal, ChatModalProps } from './ChatModal'; import { ChatMessage } from '../../../interfaces/chat-message.model'; import { CurrentUser } from '../../../interfaces/current-user'; import { currentUserAtom } from '../../stores/ClientConfigStore'; -export default { +const meta = { title: 'owncast/Chat/Chat modal', component: ChatModal, parameters: { chromatic: { diffThreshold: 0.8 }, docs: {}, }, -} as ComponentMeta; +} satisfies Meta; + +export default meta; const testMessages = `[ { @@ -578,21 +578,24 @@ const Component = args => { return ; }; -const Template: ComponentStory = args => ( +const Template: StoryFn = args => ( ); -export const Example = Template.bind({}); -Example.args = { - loading: false, - messages: messages, - usernameToHighlight: 'testuser', - chatUserId: 'testuser', - isModerator: true, - showInput: true, - chatAvailable: true, - handleClose: () => {}, - currentUser: currentUser, -} as ChatModalProps; +export const Example = { + render: Template, + + args: { + loading: false, + messages, + usernameToHighlight: 'testuser', + chatUserId: 'testuser', + isModerator: true, + showInput: true, + chatAvailable: true, + handleClose: () => {}, + currentUser, + } as ChatModalProps, +}; diff --git a/web/components/modals/FatalErrorStateModal/FatalErrorStateModal.stories.tsx b/web/components/modals/FatalErrorStateModal/FatalErrorStateModal.stories.tsx index c68817e56..6a0d592f0 100644 --- a/web/components/modals/FatalErrorStateModal/FatalErrorStateModal.stories.tsx +++ b/web/components/modals/FatalErrorStateModal/FatalErrorStateModal.stories.tsx @@ -1,21 +1,17 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { FatalErrorStateModal } from './FatalErrorStateModal'; -export default { +const meta = { title: 'owncast/Modals/Global error state', component: FatalErrorStateModal, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = args => ( - -); +export default meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Example = Template.bind({}); -Example.args = { - title: 'Example error title', - message: 'Example error message', +export const Example = { + args: { + title: 'Example error title', + message: 'Example error message', + }, }; diff --git a/web/components/modals/FediAuthModal/FediAuthModal.stories.tsx b/web/components/modals/FediAuthModal/FediAuthModal.stories.tsx index b6274c500..ffde12fdd 100644 --- a/web/components/modals/FediAuthModal/FediAuthModal.stories.tsx +++ b/web/components/modals/FediAuthModal/FediAuthModal.stories.tsx @@ -1,9 +1,8 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { FediAuthModal } from './FediAuthModal'; import FediAuthModalMock from '../../../stories/assets/mocks/fediauth-modal.png'; -export default { +const meta = { title: 'owncast/Modals/FediAuth', component: FediAuthModal, parameters: { @@ -13,20 +12,22 @@ export default { scale: 0.5, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const NotYetAuthenticated = Template.bind({}); -NotYetAuthenticated.args = { - displayName: 'fake-user', - authenticated: false, - accessToken: '', +export const NotYetAuthenticated = { + args: { + displayName: 'fake-user', + authenticated: false, + accessToken: '', + }, }; -export const Authenticated = Template.bind({}); -Authenticated.args = { - displayName: 'fake-user', - authenticated: true, - accessToken: '', +export const Authenticated = { + args: { + displayName: 'fake-user', + authenticated: true, + accessToken: '', + }, }; diff --git a/web/components/modals/FollowModal/FollowModal.stories.tsx b/web/components/modals/FollowModal/FollowModal.stories.tsx index d535ec5ac..001b7d6a9 100644 --- a/web/components/modals/FollowModal/FollowModal.stories.tsx +++ b/web/components/modals/FollowModal/FollowModal.stories.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { FollowModal } from './FollowModal'; import FollowModalMock from '../../../stories/assets/mocks/follow-modal.png'; @@ -9,7 +8,7 @@ const Example = () => ( ); -export default { +const meta = { title: 'owncast/Modals/Follow', component: FollowModal, parameters: { @@ -29,10 +28,12 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = () => ; +export default meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); +const Template: StoryFn = () => ; + +export const Basic = { + render: Template, +}; diff --git a/web/components/modals/IndieAuthModal/IndieAuthModal.stories.tsx b/web/components/modals/IndieAuthModal/IndieAuthModal.stories.tsx index a4618fc93..a006667dc 100644 --- a/web/components/modals/IndieAuthModal/IndieAuthModal.stories.tsx +++ b/web/components/modals/IndieAuthModal/IndieAuthModal.stories.tsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { IndieAuthModal } from './IndieAuthModal'; import Mock from '../../../stories/assets/mocks/indieauth-modal.png'; @@ -9,7 +8,7 @@ const Example = () => ( ); -export default { +const meta = { title: 'owncast/Modals/IndieAuth', component: IndieAuthModal, parameters: { @@ -19,10 +18,12 @@ export default { scale: 0.5, }, }, -} as ComponentMeta; +} satisfies Meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const Template: ComponentStory = () => ; +export default meta; -// eslint-disable-next-line @typescript-eslint/no-unused-vars -export const Basic = Template.bind({}); +const Template: StoryFn = () => ; + +export const Basic = { + render: Template, +}; diff --git a/web/components/modals/NameChangeModal/NameChangeModal.stories.tsx b/web/components/modals/NameChangeModal/NameChangeModal.stories.tsx index ce9175f2b..1630d8864 100644 --- a/web/components/modals/NameChangeModal/NameChangeModal.stories.tsx +++ b/web/components/modals/NameChangeModal/NameChangeModal.stories.tsx @@ -1,15 +1,17 @@ -import React, { useEffect } from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { useEffect } from 'react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot, useSetRecoilState } from 'recoil'; import { NameChangeModal } from './NameChangeModal'; import { CurrentUser } from '../../../interfaces/current-user'; import { currentUserAtom } from '../../stores/ClientConfigStore'; -export default { +const meta = { title: 'owncast/Modals/Name Change', component: NameChangeModal, parameters: {}, -} as ComponentMeta; +} satisfies Meta; + +export default meta; const Example = () => { const setCurrentUser = useSetRecoilState(currentUserAtom); @@ -32,10 +34,12 @@ const Example = () => { ); }; -const Template: ComponentStory = () => ( +const Template: StoryFn = () => ( ); -export const Basic = Template.bind({}); +export const Basic = { + render: Template, +}; diff --git a/web/components/ui/ComponentError/ComponentError.stories.tsx b/web/components/ui/ComponentError/ComponentError.stories.tsx index 7087e82d5..8f011bda8 100644 --- a/web/components/ui/ComponentError/ComponentError.stories.tsx +++ b/web/components/ui/ComponentError/ComponentError.stories.tsx @@ -1,8 +1,7 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Meta } from '@storybook/react'; import { ComponentError } from './ComponentError'; -export default { +const meta = { title: 'owncast/Components/Component Error', component: ComponentError, parameters: { @@ -12,31 +11,35 @@ export default { }, }, }, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ; +export default meta; -export const DefaultMessage = Template.bind({}); -DefaultMessage.args = { - componentName: 'Test Component', -}; - -export const Error1 = Template.bind({}); -Error1.args = { message: 'This is a test error message.', componentName: 'Test Component' }; - -export const WithDetails = Template.bind({}); -WithDetails.args = { - message: 'This is a test error message.', - componentName: 'Test Component', - details: 'Here are some additional details about the error.', -}; - -export const CanRetry = Template.bind({}); -CanRetry.args = { - message: 'This is a test error message.', - componentName: 'Test Component', - details: 'Here are some additional details about the error.', - retryFunction: () => { - console.log('retrying'); +export const DefaultMessage = { + args: { + componentName: 'Test Component', + }, +}; + +export const Error1 = { + args: { message: 'This is a test error message.', componentName: 'Test Component' }, +}; + +export const WithDetails = { + args: { + message: 'This is a test error message.', + componentName: 'Test Component', + details: 'Here are some additional details about the error.', + }, +}; + +export const CanRetry = { + args: { + message: 'This is a test error message.', + componentName: 'Test Component', + details: 'Here are some additional details about the error.', + retryFunction: () => { + console.log('retrying'); + }, }, }; diff --git a/web/components/ui/CustomPageContent/CustomPageContent.stories.tsx b/web/components/ui/CustomPageContent/CustomPageContent.stories.tsx index 22abfdda1..d50269630 100644 --- a/web/components/ui/CustomPageContent/CustomPageContent.stories.tsx +++ b/web/components/ui/CustomPageContent/CustomPageContent.stories.tsx @@ -1,32 +1,42 @@ /* eslint-disable no-useless-escape */ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { CustomPageContent } from './CustomPageContent'; -export default { +const meta = { title: 'owncast/Components/Custom page content', component: CustomPageContent, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ( +export default meta; + +const Template: StoryFn = args => ( ); -export const Example1 = Template.bind({}); -Example1.args = { - content: `\u003cp\u003eOwncast TV is a 24/7 live stream run by the Owncast project as an example of the software in use. Learn more about how you can have your own live stream that you completely control at \u003ca href=\"https://owncast.online\"\u003eowncast.online\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThis example instance shows how you can customize the page by changing things like fonts and colors as well as how you can add custom action buttons such as a donation button.\u003c/p\u003e\n\u003cp\u003eStay tuned in to learn about Owncast, hear from some streamers about their experiences using it, some bits and pieces of Owncast promo material, and highlights from other projects that are pretty cool.\u003c/p\u003e\n\u003cp\u003eBut when you've seen what we have to share with you, do yourself a favor and visit the \u003ca href=\"https://directory.owncast.online\"\u003eOwncast Directory\u003c/a\u003e and find an awesome stream to check out!\u003c/p\u003e\n\u003chr\u003e\n\u003ch2\u003eLinks to content seen in this stream\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://owncast.online/quickstart/\"\u003eOwncast Install Quickstart\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://directory.owncast.online\"\u003eOwncast Directory\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://creativecommons.org\"\u003eCreative Commons\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://tilvids.com\"\u003eTILVids\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://studio.blender.org/\"\u003eBlender Studio\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://archive.org/details/computerchronicles\"\u003eComputer Chronicles\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://joinmastodon.org\"\u003eMastodon\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e",`, +export const Example1 = { + render: Template, + + args: { + content: `\u003cp\u003eOwncast TV is a 24/7 live stream run by the Owncast project as an example of the software in use. Learn more about how you can have your own live stream that you completely control at \u003ca href=\"https://owncast.online\"\u003eowncast.online\u003c/a\u003e.\u003c/p\u003e\n\u003cp\u003eThis example instance shows how you can customize the page by changing things like fonts and colors as well as how you can add custom action buttons such as a donation button.\u003c/p\u003e\n\u003cp\u003eStay tuned in to learn about Owncast, hear from some streamers about their experiences using it, some bits and pieces of Owncast promo material, and highlights from other projects that are pretty cool.\u003c/p\u003e\n\u003cp\u003eBut when you've seen what we have to share with you, do yourself a favor and visit the \u003ca href=\"https://directory.owncast.online\"\u003eOwncast Directory\u003c/a\u003e and find an awesome stream to check out!\u003c/p\u003e\n\u003chr\u003e\n\u003ch2\u003eLinks to content seen in this stream\u003c/h2\u003e\n\u003cul\u003e\n\u003cli\u003e\u003ca href=\"https://owncast.online/quickstart/\"\u003eOwncast Install Quickstart\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://directory.owncast.online\"\u003eOwncast Directory\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://creativecommons.org\"\u003eCreative Commons\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://tilvids.com\"\u003eTILVids\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://studio.blender.org/\"\u003eBlender Studio\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://archive.org/details/computerchronicles\"\u003eComputer Chronicles\u003c/a\u003e\u003c/li\u003e\n\u003cli\u003e\u003ca href=\"https://joinmastodon.org\"\u003eMastodon\u003c/a\u003e\u003c/li\u003e\n\u003c/ul\u003e",`, + }, }; -export const Example2 = Template.bind({}); -Example2.args = { - content: `

WHAT IS HAPPENING HERE

\n

Game That Tune Radio is live with fantastic video game music streaming around the clock! We've got music from NES, SNES, Sega Genesis, Nintendo 64, Playstation, PC, and more coming all the time! If it's been featured on our podcast, it's gonna be on this stream! We only play three songs from each game on our podcast, and we decided that everyone needs more tunes!

\n

We'll be updating this livestream with new games as they're played on the show, including your requests! To get priority in requesting games for the show, check out https://www.patreon.com/GameThatTune

\n

Be sure to check out our live recordings of the Game That Tune podcast! We broadcast every Wednesday night at 9 PM EST on our YouTube channel as well as https://www.twitch.tv/GameThatTune and https://www.facebook.com/GameThatTune\nTune in and join in on the fun! Find the podcast in iTunes every Wednesday morning or head to https://www.gamethattune.com!

\n

Visit https://www.patreon.com/GameThatTune to help us keep up this live stream and upgrade our equipment for the live show! We've got exclusive mixtapes for our patrons, and lots more stuff planned for the future, so consider helping us out!

\n

HOW IT WORKS

\n

Featuring music from over 1000 games! Check out https://music.gamethattune.com/songs for the full list and make a request from your favorite game!

\n

Now that you've seen the list of games, make a request in the chat!

\n

!sr + anything = general search
\n!gr + game title = random song from matching game
\n!cr + composer name = random song from matching composer
\n!tr + anything = random result only searching song titles
\n!rr + anything = random result from all searchable fields
\n!game gtt = starts a round of our guessing game for bonus points!

\n

We have gifs!

\n

Wanna see your favorite gif on screen? type !summon followed by the gif name! Want your favorite gif to take over the video? Type !spawn followed by the gif name!

\n

Still have questions? Ask the chatbot! type !info to...wait for it...get more info!

\n

Thanks for listening!

"`, +export const Example2 = { + render: Template, + + args: { + content: `

WHAT IS HAPPENING HERE

\n

Game That Tune Radio is live with fantastic video game music streaming around the clock! We've got music from NES, SNES, Sega Genesis, Nintendo 64, Playstation, PC, and more coming all the time! If it's been featured on our podcast, it's gonna be on this stream! We only play three songs from each game on our podcast, and we decided that everyone needs more tunes!

\n

We'll be updating this livestream with new games as they're played on the show, including your requests! To get priority in requesting games for the show, check out https://www.patreon.com/GameThatTune

\n

Be sure to check out our live recordings of the Game That Tune podcast! We broadcast every Wednesday night at 9 PM EST on our YouTube channel as well as https://www.twitch.tv/GameThatTune and https://www.facebook.com/GameThatTune\nTune in and join in on the fun! Find the podcast in iTunes every Wednesday morning or head to https://www.gamethattune.com!

\n

Visit https://www.patreon.com/GameThatTune to help us keep up this live stream and upgrade our equipment for the live show! We've got exclusive mixtapes for our patrons, and lots more stuff planned for the future, so consider helping us out!

\n

HOW IT WORKS

\n

Featuring music from over 1000 games! Check out https://music.gamethattune.com/songs for the full list and make a request from your favorite game!

\n

Now that you've seen the list of games, make a request in the chat!

\n

!sr + anything = general search
\n!gr + game title = random song from matching game
\n!cr + composer name = random song from matching composer
\n!tr + anything = random result only searching song titles
\n!rr + anything = random result from all searchable fields
\n!game gtt = starts a round of our guessing game for bonus points!

\n

We have gifs!

\n

Wanna see your favorite gif on screen? type !summon followed by the gif name! Want your favorite gif to take over the video? Type !spawn followed by the gif name!

\n

Still have questions? Ask the chatbot! type !info to...wait for it...get more info!

\n

Thanks for listening!

"`, + }, }; -export const Example3 = Template.bind({}); -Example3.args = { - content: `
\n

The upcoming streams

\n

Thursday, Apr. 28:

\n\n

Friday, Apr. 29:

\n\n

Saturday, Apr. 30:

\n
    \n
  • 19:00 CEST / 17:00 UTC / 1:00 pm EDT
    \nImmer Samstags:Syberia II“ (deutsch)
  • \n
  • 23:30 CEST / 21:30 UTC / 5:30 pm EDT
    \nNight Walk:Linux Game Jam 2022“ (english)
  • \n
\n

Sunday, May 1:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nSpacy Sunday:Mass Effect 2 LE“ (english)
  • \n
\n

Monday, May 2:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nMonday Tactics:BATTLETECH“ (english)
  • \n
\n

Tuesday, May 3:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nEpic Tuesday:Terraformers“ (english)
  • \n
\n

Wednesday, May 4:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nNarrative Wednesday:Zniw Adventure“ (english)
  • \n
\n


\nI plan a duration of about 4 to 5 hours per stream.

\n

The VODs of my streams will be available on YouTube channel and on my hatVODs PeerTube channel (the last 14 days). Some additional videos can also be found on my haTube PeerTube channel.

\n

If this channel is offline you might want to checkout other great Owncast streams at the Owncast Directory.

\n
\n

Pro-tips for new viewers

\n

Change chat name

\n

When you visit an Owncast channel for the first time then you've been given a random chat name. You see this name on the top right above the chat box. Click on that name in order to pick your own preferred chat name.

\n

Chat formatting

\n

The chat supports some basic Markdown, like *Italic*, **Bold** and \`Code blocks\` (from the Owncast docs)

\n

Player shortcuts

\n

The web video player has some keyboard shortcuts for you to use:

\n
    \n
  • Play/Pause - Spacebar
  • \n
  • Volume up - 0
  • \n
  • Volume down - 9
  • \n
  • Mute - m
  • \n
  • Toggle fullscreen - f
  • \n
  • Toggle chat - c
  • \n
\n

(from the Owncast docs)

\n

Watch Owncast via IPTV

\n

If you have a tv platform/set top box (apple, amazon, roku) that you can install IPTV apps on then you can add the url https://directory.owncast.online/api/iptv to watch this and other Owncast channels on the big screen.

\n

Watch the stream in a media player

\n

The stream is using HLS standard, so you can use your favorite media player to watch the stream using the url https://live.hatnix.net/hls/stream.m3u8

\n

Joining chat-only

\n

In case you want to join only the chat (because you're watching via IPTV?) you can do that using this url: https://live.hatnix.net/embed/chat/readwrite

\n
\n

About me and this channel

\n

My name is hatniX (or Frank), 48 years old. I'm a PC gamer for over 30 years now, playing games on Linux since 1998. And this is what you'll see here on this channel, me playing games on Linux. Preferable with a focus on storytelling and atmosphere, rather than "pro-gaming".

\n

Fediverse

\n

You can follow this server in the Fediverse: @hatnix@live.hatnix.net, in order to get announcements when the stream starts.

\n

Owncast

\n

This server is powered by Owncast. Check out the Owncast-Browser-Extension for Firefox or for Chrome browsers to see whether I'm live. Another great way to see when I (or other Owncast streamers) go online, is to follow the Owncast bots on Mastodon or Twitter.

\n

Chat bot

\n

I'm using an experimantal chat bot here, which I have written specifically for Owncast. Use !help in chat to get a list of the available commands. The source code of the bot is available at github.com/hatniX/hatbot (Public Domain).

\n

In case you wonder how I display the chat onscreen, incl. the fade effect, check out my CSS file.

\n

Music

\n

The music here, if not part of the game I'm playing, is provided by Jamando. I've got a license for livestream music for gaming.

\n
\n

How you can support me

\n

If you want to support me, visit my streams, either lurk or be active in chat. You can also help me getting more attention, by telling others about my channel, or just boosting my stream announcements on Mastodon or retweeting them on Twitter.

\n

Liberapay

\n

Liberapay is a non-profit subscription platform, which means that they don't take a share. If you like, you can support me there, either with a one-time or a regular donation. Thank you so much!

\n

Ko-fi

\n

In case you want to buy me a coffee then you can do so at ko-fi. I appreciate that a lot!

\n

Support is never required, but always much appreciated. Thank you very much! <3

\n
\n

My tech specs

\n

PC Hardware:

\n
    \n
  • CPU: AMD Ryzen 9 5900X
  • \n
  • RAM: 32 GB
  • \n
  • GPU: AMD Radeon RX 6900 XT (16 GB)
  • \n
  • Keyboard: Logitech K295
  • \n
  • Trackball: Kensington Expert Mouse Trackball
  • \n
  • Mouse 1: Logitech M220
  • \n
  • Mouse 2: Razer Naga Left Handed Edition
  • \n
  • Microphone: Blue Yeti
  • \n
  • Earbuds: Linklike Classic 2
  • \n
  • Headphone: beyerdynamic DT 990 Pro
  • \n
  • Webcam(s): Vitade 960A Pro
  • \n
\n

PC Software:

\n
    \n
  • OS: Manjaro Linux
  • \n
  • Kernel: 5.17.1-3-MANJARO x86_64
  • \n
  • Desktop: Xfce 4.16.0
  • \n
  • Mesa: 21.3.8
  • \n
  • Broadcaster software: OBS Studio 27.2.4
  • \n
\n

Stream Server: Hetzner Cloud „CPX11“

\n
    \n
  • 2 vCPU AMD
  • \n
  • 2 GB RAM
  • \n
  • 40 GB disc
  • \n
  • 20TB Traffic
  • \n
  • Owncast v0.0.11
  • \n
`, +export const Example3 = { + render: Template, + + args: { + content: `
\n

The upcoming streams

\n

Thursday, Apr. 28:

\n\n

Friday, Apr. 29:

\n\n

Saturday, Apr. 30:

\n
    \n
  • 19:00 CEST / 17:00 UTC / 1:00 pm EDT
    \nImmer Samstags:Syberia II“ (deutsch)
  • \n
  • 23:30 CEST / 21:30 UTC / 5:30 pm EDT
    \nNight Walk:Linux Game Jam 2022“ (english)
  • \n
\n

Sunday, May 1:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nSpacy Sunday:Mass Effect 2 LE“ (english)
  • \n
\n

Monday, May 2:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nMonday Tactics:BATTLETECH“ (english)
  • \n
\n

Tuesday, May 3:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nEpic Tuesday:Terraformers“ (english)
  • \n
\n

Wednesday, May 4:

\n
    \n
  • 22:00 CEST / 20:00 UTC / 4:00 pm EDT
    \nNarrative Wednesday:Zniw Adventure“ (english)
  • \n
\n


\nI plan a duration of about 4 to 5 hours per stream.

\n

The VODs of my streams will be available on YouTube channel and on my hatVODs PeerTube channel (the last 14 days). Some additional videos can also be found on my haTube PeerTube channel.

\n

If this channel is offline you might want to checkout other great Owncast streams at the Owncast Directory.

\n
\n

Pro-tips for new viewers

\n

Change chat name

\n

When you visit an Owncast channel for the first time then you've been given a random chat name. You see this name on the top right above the chat box. Click on that name in order to pick your own preferred chat name.

\n

Chat formatting

\n

The chat supports some basic Markdown, like *Italic*, **Bold** and \`Code blocks\` (from the Owncast docs)

\n

Player shortcuts

\n

The web video player has some keyboard shortcuts for you to use:

\n
    \n
  • Play/Pause - Spacebar
  • \n
  • Volume up - 0
  • \n
  • Volume down - 9
  • \n
  • Mute - m
  • \n
  • Toggle fullscreen - f
  • \n
  • Toggle chat - c
  • \n
\n

(from the Owncast docs)

\n

Watch Owncast via IPTV

\n

If you have a tv platform/set top box (apple, amazon, roku) that you can install IPTV apps on then you can add the url https://directory.owncast.online/api/iptv to watch this and other Owncast channels on the big screen.

\n

Watch the stream in a media player

\n

The stream is using HLS standard, so you can use your favorite media player to watch the stream using the url https://live.hatnix.net/hls/stream.m3u8

\n

Joining chat-only

\n

In case you want to join only the chat (because you're watching via IPTV?) you can do that using this url: https://live.hatnix.net/embed/chat/readwrite

\n
\n

About me and this channel

\n

My name is hatniX (or Frank), 48 years old. I'm a PC gamer for over 30 years now, playing games on Linux since 1998. And this is what you'll see here on this channel, me playing games on Linux. Preferable with a focus on storytelling and atmosphere, rather than "pro-gaming".

\n

Fediverse

\n

You can follow this server in the Fediverse: @hatnix@live.hatnix.net, in order to get announcements when the stream starts.

\n

Owncast

\n

This server is powered by Owncast. Check out the Owncast-Browser-Extension for Firefox or for Chrome browsers to see whether I'm live. Another great way to see when I (or other Owncast streamers) go online, is to follow the Owncast bots on Mastodon or Twitter.

\n

Chat bot

\n

I'm using an experimantal chat bot here, which I have written specifically for Owncast. Use !help in chat to get a list of the available commands. The source code of the bot is available at github.com/hatniX/hatbot (Public Domain).

\n

In case you wonder how I display the chat onscreen, incl. the fade effect, check out my CSS file.

\n

Music

\n

The music here, if not part of the game I'm playing, is provided by Jamando. I've got a license for livestream music for gaming.

\n
\n

How you can support me

\n

If you want to support me, visit my streams, either lurk or be active in chat. You can also help me getting more attention, by telling others about my channel, or just boosting my stream announcements on Mastodon or retweeting them on Twitter.

\n

Liberapay

\n

Liberapay is a non-profit subscription platform, which means that they don't take a share. If you like, you can support me there, either with a one-time or a regular donation. Thank you so much!

\n

Ko-fi

\n

In case you want to buy me a coffee then you can do so at ko-fi. I appreciate that a lot!

\n

Support is never required, but always much appreciated. Thank you very much! <3

\n
\n

My tech specs

\n

PC Hardware:

\n
    \n
  • CPU: AMD Ryzen 9 5900X
  • \n
  • RAM: 32 GB
  • \n
  • GPU: AMD Radeon RX 6900 XT (16 GB)
  • \n
  • Keyboard: Logitech K295
  • \n
  • Trackball: Kensington Expert Mouse Trackball
  • \n
  • Mouse 1: Logitech M220
  • \n
  • Mouse 2: Razer Naga Left Handed Edition
  • \n
  • Microphone: Blue Yeti
  • \n
  • Earbuds: Linklike Classic 2
  • \n
  • Headphone: beyerdynamic DT 990 Pro
  • \n
  • Webcam(s): Vitade 960A Pro
  • \n
\n

PC Software:

\n
    \n
  • OS: Manjaro Linux
  • \n
  • Kernel: 5.17.1-3-MANJARO x86_64
  • \n
  • Desktop: Xfce 4.16.0
  • \n
  • Mesa: 21.3.8
  • \n
  • Broadcaster software: OBS Studio 27.2.4
  • \n
\n

Stream Server: Hetzner Cloud „CPX11“

\n
    \n
  • 2 vCPU AMD
  • \n
  • 2 GB RAM
  • \n
  • 40 GB disc
  • \n
  • 20TB Traffic
  • \n
  • Owncast v0.0.11
  • \n
`, + }, }; diff --git a/web/components/ui/Footer/Footer.stories.tsx b/web/components/ui/Footer/Footer.stories.tsx index 40eb48975..42a0604f4 100644 --- a/web/components/ui/Footer/Footer.stories.tsx +++ b/web/components/ui/Footer/Footer.stories.tsx @@ -1,22 +1,25 @@ -import React from 'react'; -import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { StoryFn, Meta } from '@storybook/react'; import { RecoilRoot } from 'recoil'; import { Footer } from './Footer'; -export default { +const meta = { title: 'owncast/Layout/Footer', component: Footer, parameters: {}, -} as ComponentMeta; +} satisfies Meta; -const Template: ComponentStory = args => ( +export default meta; + +const Template: StoryFn = args => (