embed screen style adjustments (#4063)
* restyle and relayout embed screen to account for smaller screen displays. - address https://github.com/owncast/owncast/issues/3683 to address overflow issues - address https://github.com/owncast/owncast/issues/4051 to move the name of the stream * Javascript formatting autofixes * clean up; restore package lock * accommodate cases when there's no follow option; put follow form on one line, but wrap if need * clean up * separate out follow form into separate standalone component to be used in multiple places * improve follow error styling; rm defaultProps for Modal to get rid of warning * improve styling of follow form and components for legibility * prettyify scss * prettyify scss again * one more time * prettify ant file * simplify layout, center everything * just use gap * tweak and lint * lint, again --------- Co-authored-by: Owncast <owncast@owncast.online>
This commit is contained in:
103
web/components/modals/FollowModal/FollowForm.tsx
Normal file
103
web/components/modals/FollowModal/FollowForm.tsx
Normal file
@@ -0,0 +1,103 @@
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
import { Input, Button, Alert, Spin, Space } from 'antd';
|
||||
import { FC, useState } from 'react';
|
||||
import styles from './FollowModal.module.scss';
|
||||
import { isValidFediverseAccount } from '../../../utils/validators';
|
||||
|
||||
const ENDPOINT = '/api/remotefollow';
|
||||
|
||||
export type FollowFormProps = {
|
||||
handleClose?: () => void;
|
||||
};
|
||||
|
||||
export const FollowForm: FC<FollowFormProps> = ({ handleClose }: FollowFormProps) => {
|
||||
const [remoteAccount, setRemoteAccount] = useState(null);
|
||||
const [valid, setValid] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState(null);
|
||||
|
||||
const handleAccountChange = a => {
|
||||
setRemoteAccount(a);
|
||||
if (isValidFediverseAccount(a)) {
|
||||
setValid(true);
|
||||
} else {
|
||||
setValid(false);
|
||||
}
|
||||
};
|
||||
|
||||
const joinButtonPressed = () => {
|
||||
window.open('https://owncast.online/join-fediverse', '_blank');
|
||||
};
|
||||
|
||||
const remoteFollowButtonPressed = async () => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const sanitizedAccount = remoteAccount.replace(/^@+/, '');
|
||||
const request = { account: sanitizedAccount };
|
||||
const rawResponse = await fetch(ENDPOINT, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(request),
|
||||
});
|
||||
const result = await rawResponse.json();
|
||||
|
||||
if (result.redirectUrl) {
|
||||
window.open(result.redirectUrl, '_blank');
|
||||
handleClose();
|
||||
}
|
||||
if (!result.success) {
|
||||
setErrorMessage(result.message);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
if (!result.redirectUrl) {
|
||||
setErrorMessage('Unable to follow.');
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
setErrorMessage(e.message);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Spin spinning={loading}>
|
||||
{errorMessage && (
|
||||
<Alert
|
||||
message="Follow Error"
|
||||
description={errorMessage}
|
||||
type="error"
|
||||
closable
|
||||
className={styles.errorAlert}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className={styles.inputContainer}>
|
||||
<div className={styles.instructions}>Enter your username @server to follow</div>
|
||||
<Input
|
||||
value={remoteAccount}
|
||||
size="large"
|
||||
onChange={e => handleAccountChange(e.target.value)}
|
||||
placeholder="Your fediverse account @account@server"
|
||||
defaultValue={remoteAccount}
|
||||
/>
|
||||
<div className={styles.footer}>
|
||||
You'll be redirected to your Fediverse server and asked to confirm the action.
|
||||
</div>
|
||||
</div>
|
||||
<Space className={styles.buttons}>
|
||||
<Button onClick={joinButtonPressed} type="text">
|
||||
Join the Fediverse
|
||||
</Button>
|
||||
<Button disabled={!valid} type="primary" onClick={remoteFollowButtonPressed}>
|
||||
Follow
|
||||
</Button>
|
||||
</Space>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
@@ -9,16 +9,21 @@
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.instructions {
|
||||
.inputContainer {
|
||||
font-family: var(--theme-text-display-font-family);
|
||||
font-size: 0.7rem;
|
||||
font-weight: 600;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
margin-bottom: 10px;
|
||||
|
||||
.footer {
|
||||
font-size: 0.5rem;
|
||||
.instructions {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
margin: 5px 2px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
font-size: 10px;
|
||||
margin: 2px;
|
||||
color: var(--theme-color-components-primary-button-text-disabled);
|
||||
}
|
||||
}
|
||||
|
||||
.account {
|
||||
@@ -50,3 +55,17 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.errorAlert {
|
||||
margin-bottom: 1.25rem;
|
||||
font-family: var(--theme-text-display-font-family);
|
||||
|
||||
:global(.ant-alert-message) {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
:global(.ant-alert-description) {
|
||||
font-size: 12px;
|
||||
font-family: monospace;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/* eslint-disable react/no-unescaped-entities */
|
||||
import { Input, Button, Alert, Spin, Space } from 'antd';
|
||||
import { FC, useState } from 'react';
|
||||
import { Space } from 'antd';
|
||||
import { FC } from 'react';
|
||||
import styles from './FollowModal.module.scss';
|
||||
import { isValidFediverseAccount } from '../../../utils/validators';
|
||||
|
||||
const ENDPOINT = '/api/remotefollow';
|
||||
import { FollowForm } from './FollowForm';
|
||||
|
||||
export type FollowModalProps = {
|
||||
handleClose: () => void;
|
||||
@@ -12,106 +10,24 @@ export type FollowModalProps = {
|
||||
name: string;
|
||||
};
|
||||
|
||||
export const FollowModal: FC<FollowModalProps> = ({ handleClose, account, name }) => {
|
||||
const [remoteAccount, setRemoteAccount] = useState(null);
|
||||
const [valid, setValid] = useState(false);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [errorMessage, setErrorMessage] = useState(null);
|
||||
|
||||
const handleAccountChange = a => {
|
||||
setRemoteAccount(a);
|
||||
if (isValidFediverseAccount(a)) {
|
||||
setValid(true);
|
||||
} else {
|
||||
setValid(false);
|
||||
}
|
||||
};
|
||||
|
||||
const joinButtonPressed = () => {
|
||||
window.open('https://owncast.online/join-fediverse', '_blank');
|
||||
};
|
||||
|
||||
const remoteFollowButtonPressed = async () => {
|
||||
if (!valid) {
|
||||
return;
|
||||
}
|
||||
|
||||
setLoading(true);
|
||||
|
||||
try {
|
||||
const sanitizedAccount = remoteAccount.replace(/^@+/, '');
|
||||
const request = { account: sanitizedAccount };
|
||||
const rawResponse = await fetch(ENDPOINT, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(request),
|
||||
});
|
||||
const result = await rawResponse.json();
|
||||
|
||||
if (result.redirectUrl) {
|
||||
window.open(result.redirectUrl, '_blank');
|
||||
handleClose();
|
||||
}
|
||||
if (!result.success) {
|
||||
setErrorMessage(result.message);
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
if (!result.redirectUrl) {
|
||||
setErrorMessage('Unable to follow.');
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
setErrorMessage(e.message);
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<Space direction="vertical" id="follow-modal">
|
||||
<div className={styles.header}>
|
||||
By following this stream you'll get notified on the Fediverse when it goes live. Now is a
|
||||
great time to
|
||||
<a href="https://owncast.online/join-fediverse" target="_blank" rel="noreferrer">
|
||||
learn about the Fediverse
|
||||
</a>
|
||||
if it's new to you.
|
||||
export const FollowModal: FC<FollowModalProps> = ({ handleClose, account, name }) => (
|
||||
<Space direction="vertical" id="follow-modal">
|
||||
<div className={styles.header}>
|
||||
By following this stream you'll get notified on the Fediverse when it goes live. Now is a
|
||||
great time to
|
||||
<a href="https://owncast.online/join-fediverse" target="_blank" rel="noreferrer">
|
||||
learn about the Fediverse
|
||||
</a>
|
||||
if it's new to you.
|
||||
</div>
|
||||
<div className={styles.account}>
|
||||
<img src="/logo" alt="logo" className={styles.logo} />
|
||||
<div className={styles.username}>
|
||||
<div className={styles.name}>{name}</div>
|
||||
<div>{account}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Spin spinning={loading}>
|
||||
{errorMessage && (
|
||||
<Alert message="Follow Error" description={errorMessage} type="error" showIcon />
|
||||
)}
|
||||
<div className={styles.account}>
|
||||
<img src="/logo" alt="logo" className={styles.logo} />
|
||||
<div className={styles.username}>
|
||||
<div className={styles.name}>{name}</div>
|
||||
<div>{account}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div className={styles.instructions}>Enter your username @server to follow</div>
|
||||
<Input
|
||||
value={remoteAccount}
|
||||
size="large"
|
||||
onChange={e => handleAccountChange(e.target.value)}
|
||||
placeholder="Your fediverse account @account@server"
|
||||
defaultValue={remoteAccount}
|
||||
/>
|
||||
<div className={styles.footer}>
|
||||
You'll be redirected to your Fediverse server and asked to confirm the action.
|
||||
</div>
|
||||
</div>
|
||||
<Space className={styles.buttons}>
|
||||
<Button disabled={!valid} type="primary" onClick={remoteFollowButtonPressed}>
|
||||
Follow
|
||||
</Button>
|
||||
<Button onClick={joinButtonPressed} type="primary">
|
||||
Join the Fediverse
|
||||
</Button>
|
||||
</Space>
|
||||
</Spin>
|
||||
</Space>
|
||||
);
|
||||
};
|
||||
<FollowForm handleClose={handleClose} />
|
||||
</Space>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user