Add action buttons and status bar
This commit is contained in:
parent
448c23d097
commit
f835ae5086
@ -2,7 +2,7 @@ import { Menu, Dropdown } from 'antd';
|
|||||||
import { DownOutlined } from '@ant-design/icons';
|
import { DownOutlined } from '@ant-design/icons';
|
||||||
import { useRecoilState } from 'recoil';
|
import { useRecoilState } from 'recoil';
|
||||||
import { ChatVisibilityState, ChatState } from '../interfaces/application-state';
|
import { ChatVisibilityState, ChatState } from '../interfaces/application-state';
|
||||||
import { chatVisibilityAtom as chatVisibilityAtom } from './stores/ClientConfigStore';
|
import { chatVisibilityAtom } from './stores/ClientConfigStore';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
username: string;
|
username: string;
|
||||||
|
7
web/components/action-buttons/ActionButton.module.scss
Normal file
7
web/components/action-buttons/ActionButton.module.scss
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
.button {
|
||||||
|
margin: 3px;
|
||||||
|
.icon {
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 3px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,18 @@
|
|||||||
import { Button } from 'antd';
|
import { Button } from 'antd';
|
||||||
import { ExternalAction } from '../interfaces/external-action.interface';
|
import { ExternalAction } from '../interfaces/external-action.interface';
|
||||||
|
import s from './ActionButton.module.scss';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
action: ExternalAction;
|
action: ExternalAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function ExternalActionButton(props: Props) {
|
export default function ActionButton(props: Props) {
|
||||||
const { action } = props;
|
const { action } = props;
|
||||||
const { url, title, description, icon, color, openExternally } = action;
|
const { url, title, description, icon, color, openExternally } = action;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button type="primary" style={{ backgroundColor: color }}>
|
<Button type="primary" className={`${s.button}`} style={{ backgroundColor: color }}>
|
||||||
<img src={icon} width="30px" alt={description} />
|
<img src={icon} className={`${s.icon}`} alt={description} />
|
||||||
{title}
|
{title}
|
||||||
</Button>
|
</Button>
|
||||||
);
|
);
|
12
web/components/action-buttons/ActionButtonRow.tsx
Normal file
12
web/components/action-buttons/ActionButtonRow.tsx
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import s from './ActionButtons.module.scss';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
children: React.ReactNode[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function ActionButtonRow(props: Props) {
|
||||||
|
const { children } = props;
|
||||||
|
|
||||||
|
return <div className={`${s.row}`}>{children}</div>;
|
||||||
|
}
|
10
web/components/action-buttons/ActionButtons.module.scss
Normal file
10
web/components/action-buttons/ActionButtons.module.scss
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.row {
|
||||||
|
margin: 5px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-end;
|
||||||
|
button {
|
||||||
|
margin-left: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
@ -1,19 +0,0 @@
|
|||||||
import { ExternalAction } from '../interfaces/external-action.interface';
|
|
||||||
import ExternalActionButton from './ExternalActionButton';
|
|
||||||
import s from './ExternalActionButtons.module.scss';
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
actions: ExternalAction[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function ExternalActionButtonRow(props: Props) {
|
|
||||||
const { actions } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={`${s.row}`}>
|
|
||||||
{actions.map(action => (
|
|
||||||
<ExternalActionButton key={action.id} action={action} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,5 +1,5 @@
|
|||||||
import { useRecoilValue } from 'recoil';
|
import { useRecoilValue } from 'recoil';
|
||||||
import { Layout, Row, Col, Tabs } from 'antd';
|
import { Layout, Button, Col, Tabs } from 'antd';
|
||||||
import Grid from 'antd/lib/card/Grid';
|
import Grid from 'antd/lib/card/Grid';
|
||||||
import {
|
import {
|
||||||
chatVisibilityAtom,
|
chatVisibilityAtom,
|
||||||
@ -7,6 +7,7 @@ import {
|
|||||||
chatMessagesAtom,
|
chatMessagesAtom,
|
||||||
chatStateAtom,
|
chatStateAtom,
|
||||||
} from '../../stores/ClientConfigStore';
|
} from '../../stores/ClientConfigStore';
|
||||||
|
import { serverStatusState } from '../../stores/ServerStatusStore';
|
||||||
import { ClientConfig } from '../../../interfaces/client-config.model';
|
import { ClientConfig } from '../../../interfaces/client-config.model';
|
||||||
import CustomPageContent from '../../CustomPageContent';
|
import CustomPageContent from '../../CustomPageContent';
|
||||||
import OwncastPlayer from '../../video/OwncastPlayer';
|
import OwncastPlayer from '../../video/OwncastPlayer';
|
||||||
@ -18,40 +19,59 @@ import ChatContainer from '../../chat/ChatContainer';
|
|||||||
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
import { ChatMessage } from '../../../interfaces/chat-message.model';
|
||||||
import { ChatState, ChatVisibilityState } from '../../../interfaces/application-state';
|
import { ChatState, ChatVisibilityState } from '../../../interfaces/application-state';
|
||||||
import ChatTextField from '../../chat/ChatTextField/ChatTextField';
|
import ChatTextField from '../../chat/ChatTextField/ChatTextField';
|
||||||
import ExternalActionButtonRow from '../../action-buttons/ExternalActionButtonRow';
|
import ActionButtonRow from '../../action-buttons/ActionButtonRow';
|
||||||
|
import ActionButton from '../../action-buttons/ActionButton';
|
||||||
|
import Statusbar from '../Statusbar/Statusbar';
|
||||||
|
import { ServerStatus } from '../../../interfaces/server-status.model';
|
||||||
|
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
const { Content } = Layout;
|
const { Content } = Layout;
|
||||||
|
|
||||||
export default function FooterComponent() {
|
export default function FooterComponent() {
|
||||||
|
const status = useRecoilValue<ServerStatus>(serverStatusState);
|
||||||
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
|
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
|
||||||
const chatOpen = useRecoilValue<ChatVisibilityState>(chatVisibilityAtom);
|
const chatOpen = useRecoilValue<ChatVisibilityState>(chatVisibilityAtom);
|
||||||
const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom);
|
const messages = useRecoilValue<ChatMessage[]>(chatMessagesAtom);
|
||||||
const chatState = useRecoilValue<ChatState>(chatStateAtom);
|
const chatState = useRecoilValue<ChatState>(chatStateAtom);
|
||||||
|
|
||||||
const { extraPageContent } = clientConfig;
|
const { extraPageContent } = clientConfig;
|
||||||
|
const { online, viewerCount, lastConnectTime, lastDisconnectTime, streamTitle } = status;
|
||||||
|
|
||||||
const followers: Follower[] = [];
|
const followers: Follower[] = [];
|
||||||
|
|
||||||
const total = 0;
|
const total = 0;
|
||||||
|
|
||||||
|
// This is example content. It should be removed.
|
||||||
|
const externalActions = [
|
||||||
|
{
|
||||||
|
url: 'https://owncast.online/docs',
|
||||||
|
title: 'Example button',
|
||||||
|
description: 'Example button description',
|
||||||
|
icon: 'https://owncast.online/images/logo.svg',
|
||||||
|
color: '#5232c8',
|
||||||
|
openExternally: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const externalActionButtons = externalActions.map(action => (
|
||||||
|
<ActionButton key={action.url} action={action} />
|
||||||
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Content className={`${s.root}`} data-columns={chatOpen ? 2 : 1}>
|
<Content className={`${s.root}`} data-columns={chatOpen ? 2 : 1}>
|
||||||
<div className={`${s.leftCol}`}>
|
<div className={`${s.leftCol}`}>
|
||||||
<OwncastPlayer source="https://watch.owncast.online" />
|
<OwncastPlayer source="https://watch.owncast.online" />
|
||||||
<ExternalActionButtonRow
|
<Statusbar
|
||||||
actions={[
|
online={online}
|
||||||
{
|
lastConnectTime={lastConnectTime}
|
||||||
url: 'https://owncast.online/docs',
|
lastDisconnectTime={lastDisconnectTime}
|
||||||
title: 'Example button',
|
viewerCount={viewerCount}
|
||||||
description: 'Example button description',
|
|
||||||
icon: 'https://owncast.online/images/logo.svg',
|
|
||||||
color: '#5232c8',
|
|
||||||
openExternally: true,
|
|
||||||
},
|
|
||||||
]}
|
|
||||||
/>
|
/>
|
||||||
|
<ActionButtonRow>
|
||||||
|
{externalActionButtons}
|
||||||
|
<Button>Follow</Button>
|
||||||
|
<Button>Notify</Button>
|
||||||
|
</ActionButtonRow>
|
||||||
<div className={`${s.lowerRow}`}>
|
<div className={`${s.lowerRow}`}>
|
||||||
<Tabs defaultActiveKey="1" type="card">
|
<Tabs defaultActiveKey="1" type="card">
|
||||||
<TabPane tab="About" key="1" className={`${s.pageContentSection}`}>
|
<TabPane tab="About" key="1" className={`${s.pageContentSection}`}>
|
||||||
|
10
web/components/ui/Statusbar/Statusbar.module.scss
Normal file
10
web/components/ui/Statusbar/Statusbar.module.scss
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
.statusbar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 10px;
|
||||||
|
padding-right: 10px;
|
||||||
|
justify-content: space-between;
|
||||||
|
height: 30px;
|
||||||
|
width: 100%;
|
||||||
|
background-color: black;
|
||||||
|
}
|
50
web/components/ui/Statusbar/Statusbar.tsx
Normal file
50
web/components/ui/Statusbar/Statusbar.tsx
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
|
||||||
|
import formatDistanceToNowStrict from 'date-fns/formatDistanceToNowStrict';
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
|
||||||
|
import s from './Statusbar.module.scss';
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
online: Boolean;
|
||||||
|
lastConnectTime?: Date;
|
||||||
|
lastDisconnectTime?: Date;
|
||||||
|
viewerCount: number;
|
||||||
|
}
|
||||||
|
export default function Statusbar(props: Props) {
|
||||||
|
const [now, setNow] = useState(new Date());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const interval = setInterval(() => setNow(new Date()), 1000);
|
||||||
|
return () => {
|
||||||
|
clearInterval(interval);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const { online, lastConnectTime, lastDisconnectTime, viewerCount } = props;
|
||||||
|
|
||||||
|
let onlineMessage = '';
|
||||||
|
let rightSideMessage = '';
|
||||||
|
if (online && lastConnectTime) {
|
||||||
|
const diff = formatDistanceToNowStrict(new Date(lastConnectTime));
|
||||||
|
onlineMessage = online ? `Streaming for ${diff}` : 'Offline';
|
||||||
|
rightSideMessage = `${viewerCount} viewers`;
|
||||||
|
} else {
|
||||||
|
onlineMessage = 'Offline';
|
||||||
|
if (lastDisconnectTime) {
|
||||||
|
rightSideMessage = `Last live ${formatDistanceToNow(lastDisconnectTime)} ago.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={s.statusbar}>
|
||||||
|
{/* <div>{streamStartedAt}</div> */}
|
||||||
|
<div>{onlineMessage}</div>
|
||||||
|
<div>{rightSideMessage}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Statusbar.defaultProps = {
|
||||||
|
lastConnectTime: null,
|
||||||
|
lastDisconectTime: null,
|
||||||
|
};
|
@ -1,5 +1,5 @@
|
|||||||
.player {
|
.player {
|
||||||
height: 90vh;
|
height: 80vh;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: green;
|
background-color: green;
|
||||||
}
|
}
|
@ -1,9 +0,0 @@
|
|||||||
interface Props {
|
|
||||||
online: boolean;
|
|
||||||
viewers: number;
|
|
||||||
timer: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function StatusBar(props: Props) {
|
|
||||||
return <div>Stream status bar goes here</div>;
|
|
||||||
}
|
|
@ -1,17 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
import ExternalActionButton from '../components/action-buttons/ExternalActionButton';
|
import ActionButton from '../components/action-buttons/ActionButton';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'owncast/External action button',
|
title: 'owncast/External action button',
|
||||||
component: ExternalActionButton,
|
component: ActionButton,
|
||||||
parameters: {},
|
parameters: {},
|
||||||
} as ComponentMeta<typeof ExternalActionButton>;
|
} as ComponentMeta<typeof ActionButton>;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const Template: ComponentStory<typeof ExternalActionButton> = args => (
|
const Template: ComponentStory<typeof ActionButton> = args => <ActionButton {...args} />;
|
||||||
<ExternalActionButton {...args} />
|
|
||||||
);
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
export const Example1 = Template.bind({});
|
export const Example1 = Template.bind({});
|
41
web/stories/ActionButtonRow.stories.tsx
Normal file
41
web/stories/ActionButtonRow.stories.tsx
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
|
import ActionButtonRow from '../components/action-buttons/ActionButtonRow';
|
||||||
|
import ActionButton from '../components/action-buttons/ActionButton';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'owncast/External action button row',
|
||||||
|
component: ActionButtonRow,
|
||||||
|
parameters: {},
|
||||||
|
} as ComponentMeta<typeof ActionButtonRow>;
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const Template: ComponentStory<typeof ActionButtonRow> = args => (
|
||||||
|
<ActionButtonRow>{args.buttons}</ActionButtonRow>
|
||||||
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const actions = [
|
||||||
|
{
|
||||||
|
url: 'https://owncast.online/docs',
|
||||||
|
title: 'Documentation',
|
||||||
|
description: 'Owncast Documentation',
|
||||||
|
icon: 'https://owncast.online/images/logo.svg',
|
||||||
|
color: '#5232c8',
|
||||||
|
openExternally: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const buttons = actions.map(action => <ActionButton action={action} />);
|
||||||
|
export const Example1 = Template.bind({});
|
||||||
|
Example1.args = {
|
||||||
|
buttons,
|
||||||
|
};
|
@ -24,7 +24,7 @@ import {Color, ColorRow} from './Color';
|
|||||||
<ColorRow colors={['theme-text-color', 'theme-text-color-secondary', 'theme-link-color']} />
|
<ColorRow colors={['theme-text-color', 'theme-text-color-secondary', 'theme-link-color']} />
|
||||||
|
|
||||||
## Backgrounds
|
## Backgrounds
|
||||||
<ColorRow colors={['theme-background', 'popover-background']} />
|
<ColorRow colors={['theme-background', 'theme-background-secondary', 'popover-background']} />
|
||||||
|
|
||||||
## Status
|
## Status
|
||||||
<ColorRow colors={['theme-success-color', 'theme-info-color', 'theme-warning-color', 'theme-error-color']} />
|
<ColorRow colors={['theme-success-color', 'theme-info-color', 'theme-warning-color', 'theme-error-color']} />
|
||||||
|
@ -1,37 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
|
||||||
import ExternalActionButtonRow from '../components/action-buttons/ExternalActionButtonRow';
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: 'owncast/External action button row',
|
|
||||||
component: ExternalActionButtonRow,
|
|
||||||
parameters: {},
|
|
||||||
} as ComponentMeta<typeof ExternalActionButtonRow>;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
const Template: ComponentStory<typeof ExternalActionButtonRow> = args => (
|
|
||||||
<ExternalActionButtonRow {...args} />
|
|
||||||
);
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
export const Example1 = Template.bind({});
|
|
||||||
Example1.args = {
|
|
||||||
actions: [
|
|
||||||
{
|
|
||||||
url: 'https://owncast.online/docs',
|
|
||||||
title: 'Documentation',
|
|
||||||
description: 'Owncast Documentation',
|
|
||||||
icon: 'https://owncast.online/images/logo.svg',
|
|
||||||
color: '#5232c8',
|
|
||||||
openExternally: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
@ -1,25 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
import { ComponentStory, ComponentMeta } from '@storybook/react';
|
||||||
import StatusBar from '../components/video/StatusBar';
|
import { subHours } from 'date-fns';
|
||||||
|
import Statusbar from '../components/ui/Statusbar/Statusbar';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
title: 'owncast/Status bar',
|
title: 'owncast/Status bar',
|
||||||
component: StatusBar,
|
component: Statusbar,
|
||||||
parameters: {},
|
parameters: {},
|
||||||
} as ComponentMeta<typeof StatusBar>;
|
} as ComponentMeta<typeof Statusbar>;
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
const Template: ComponentStory<typeof Statusbar> = args => <Statusbar {...args} />;
|
||||||
const Template: ComponentStory<typeof StatusBar> = args => <StatusBar {...args} />;
|
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
export const Online = Template.bind({});
|
export const Online = Template.bind({});
|
||||||
Online.args = {
|
Online.args = {
|
||||||
online: true,
|
online: true,
|
||||||
viewers: 42,
|
viewerCount: 42,
|
||||||
timer: '10:42',
|
lastConnectTime: subHours(new Date(), 3),
|
||||||
};
|
};
|
||||||
|
|
||||||
export const Offline = Template.bind({});
|
export const Offline = Template.bind({});
|
||||||
Offline.args = {
|
Offline.args = {
|
||||||
online: false,
|
online: false,
|
||||||
|
lastDisconnectTime: subHours(new Date(), 3),
|
||||||
};
|
};
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
# These are the variables used in the user interface.
|
# These are the variables used in the user interface.
|
||||||
# They can be overwritten to customize the look and feel.
|
# They can be overwritten to customize the look and feel.
|
||||||
# We should write some documentation on how to do that when the time comes.
|
# We should write some documentation on how to do that when the time comes.
|
||||||
# The fewer there are the better as it'll be easier to customize and document.
|
# The fewer there are the easier it'll be easier to customize and document.
|
||||||
|
|
||||||
theme:
|
theme:
|
||||||
primary-color:
|
primary-color:
|
||||||
@ -24,7 +24,7 @@ theme:
|
|||||||
comment: "A secondary background color used in sections and controls."
|
comment: "A secondary background color used in sections and controls."
|
||||||
rounded-corners:
|
rounded-corners:
|
||||||
value: "5px"
|
value: "5px"
|
||||||
comment: "The radius of rounded corners."
|
comment: "The radius of rounded corners used in places."
|
||||||
|
|
||||||
success-color:
|
success-color:
|
||||||
value: "{color.owncast.green.500.value}"
|
value: "{color.owncast.green.500.value}"
|
||||||
|
@ -22,7 +22,9 @@
|
|||||||
--theme-text-color: #d0d5dd; /* The color of the text in the application. */
|
--theme-text-color: #d0d5dd; /* The color of the text in the application. */
|
||||||
--theme-text-color-secondary: #667085;
|
--theme-text-color-secondary: #667085;
|
||||||
--theme-link-color: #9e77ed;
|
--theme-link-color: #9e77ed;
|
||||||
--theme-font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
--theme-font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||||
|
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
--theme-background: #1b1a26; /* The main background color of the page. */
|
--theme-background: #1b1a26; /* The main background color of the page. */
|
||||||
--theme-background-secondary: #16151f; /* A secondary background color used in sections and controls. */
|
--theme-background-secondary: #16151f; /* A secondary background color used in sections and controls. */
|
||||||
--theme-rounded-corners: 5px; /* The radius of rounded corners. */
|
--theme-rounded-corners: 5px; /* The radius of rounded corners. */
|
||||||
@ -60,7 +62,9 @@
|
|||||||
--color-owncast-logo-blue: #2086e1;
|
--color-owncast-logo-blue: #2086e1;
|
||||||
--color-owncast-background: #1b1a26;
|
--color-owncast-background: #1b1a26;
|
||||||
--color-owncast-background-secondary: #16151f;
|
--color-owncast-background-secondary: #16151f;
|
||||||
--font-owncast-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';
|
--font-owncast-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
||||||
|
'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
|
||||||
|
'Segoe UI Symbol', 'Noto Color Emoji';
|
||||||
--owncast-purple: #7871ff;
|
--owncast-purple: #7871ff;
|
||||||
--owncast-purple-25: rgba(120, 113, 255, 0.25);
|
--owncast-purple-25: rgba(120, 113, 255, 0.25);
|
||||||
--owncast-purple-50: rgba(120, 113, 255, 0.5);
|
--owncast-purple-50: rgba(120, 113, 255, 0.5);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user