mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-02-07 23:42:11 -05:00
[Glitch] Change design of embed modal in web UI
Port 24ef8255b3f9b44cb54f49bc78fe3382a7070b1a to glitch-soc Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
parent
e705ec13db
commit
bd68d2ab21
@ -0,0 +1,90 @@
|
|||||||
|
import { useRef, useState, useCallback } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
|
||||||
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
|
import { useTimeout } from 'flavours/glitch/hooks/useTimeout';
|
||||||
|
|
||||||
|
export const CopyPasteText: React.FC<{ value: string }> = ({ value }) => {
|
||||||
|
const inputRef = useRef<HTMLTextAreaElement>(null);
|
||||||
|
const [copied, setCopied] = useState(false);
|
||||||
|
const [focused, setFocused] = useState(false);
|
||||||
|
const [setAnimationTimeout] = useTimeout();
|
||||||
|
|
||||||
|
const handleInputClick = useCallback(() => {
|
||||||
|
setCopied(false);
|
||||||
|
|
||||||
|
if (inputRef.current) {
|
||||||
|
inputRef.current.focus();
|
||||||
|
inputRef.current.select();
|
||||||
|
inputRef.current.setSelectionRange(0, value.length);
|
||||||
|
}
|
||||||
|
}, [setCopied, value]);
|
||||||
|
|
||||||
|
const handleButtonClick = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
void navigator.clipboard.writeText(value);
|
||||||
|
inputRef.current?.blur();
|
||||||
|
setCopied(true);
|
||||||
|
setAnimationTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 700);
|
||||||
|
},
|
||||||
|
[setCopied, setAnimationTimeout, value],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleKeyUp = useCallback(
|
||||||
|
(e: React.KeyboardEvent) => {
|
||||||
|
if (e.key !== ' ') return;
|
||||||
|
void navigator.clipboard.writeText(value);
|
||||||
|
setCopied(true);
|
||||||
|
setAnimationTimeout(() => {
|
||||||
|
setCopied(false);
|
||||||
|
}, 700);
|
||||||
|
},
|
||||||
|
[setCopied, setAnimationTimeout, value],
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleFocus = useCallback(() => {
|
||||||
|
setFocused(true);
|
||||||
|
}, [setFocused]);
|
||||||
|
|
||||||
|
const handleBlur = useCallback(() => {
|
||||||
|
setFocused(false);
|
||||||
|
}, [setFocused]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={classNames('copy-paste-text', { copied, focused })}
|
||||||
|
tabIndex={0}
|
||||||
|
role='button'
|
||||||
|
onClick={handleInputClick}
|
||||||
|
onKeyUp={handleKeyUp}
|
||||||
|
>
|
||||||
|
<textarea
|
||||||
|
readOnly
|
||||||
|
value={value}
|
||||||
|
ref={inputRef}
|
||||||
|
onClick={handleInputClick}
|
||||||
|
onFocus={handleFocus}
|
||||||
|
onBlur={handleBlur}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button className='button' onClick={handleButtonClick}>
|
||||||
|
<Icon id='copy' icon={ContentCopyIcon} />{' '}
|
||||||
|
{copied ? (
|
||||||
|
<FormattedMessage id='copypaste.copied' defaultMessage='Copied' />
|
||||||
|
) : (
|
||||||
|
<FormattedMessage
|
||||||
|
id='copypaste.copy_to_clipboard'
|
||||||
|
defaultMessage='Copy to clipboard'
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
@ -56,7 +56,7 @@ const messages = defineMessages({
|
|||||||
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
|
unmuteConversation: { id: 'status.unmute_conversation', defaultMessage: 'Unmute conversation' },
|
||||||
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
||||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||||
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
embed: { id: 'status.embed', defaultMessage: 'Get embed code' },
|
||||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||||
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
|
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
|
||||||
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
||||||
|
@ -34,8 +34,6 @@ import Status from 'flavours/glitch/components/status';
|
|||||||
import { deleteModal } from 'flavours/glitch/initial_state';
|
import { deleteModal } from 'flavours/glitch/initial_state';
|
||||||
import { makeGetStatus, makeGetPictureInPicture } from 'flavours/glitch/selectors';
|
import { makeGetStatus, makeGetPictureInPicture } from 'flavours/glitch/selectors';
|
||||||
|
|
||||||
import { showAlertForError } from '../actions/alerts';
|
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
const getStatus = makeGetStatus();
|
const getStatus = makeGetStatus();
|
||||||
const getPictureInPicture = makeGetPictureInPicture();
|
const getPictureInPicture = makeGetPictureInPicture();
|
||||||
@ -111,10 +109,7 @@ const mapDispatchToProps = (dispatch, { contextType }) => ({
|
|||||||
onEmbed (status) {
|
onEmbed (status) {
|
||||||
dispatch(openModal({
|
dispatch(openModal({
|
||||||
modalType: 'EMBED',
|
modalType: 'EMBED',
|
||||||
modalProps: {
|
modalProps: { id: status.get('id') },
|
||||||
id: status.get('id'),
|
|
||||||
onError: error => dispatch(showAlertForError(error)),
|
|
||||||
},
|
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -10,8 +10,8 @@ import { Link } from 'react-router-dom';
|
|||||||
import SwipeableViews from 'react-swipeable-views';
|
import SwipeableViews from 'react-swipeable-views';
|
||||||
|
|
||||||
import ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react';
|
import ArrowRightAltIcon from '@/material-icons/400-24px/arrow_right_alt.svg?react';
|
||||||
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
|
|
||||||
import { ColumnBackButton } from 'flavours/glitch/components/column_back_button';
|
import { ColumnBackButton } from 'flavours/glitch/components/column_back_button';
|
||||||
|
import { CopyPasteText } from 'flavours/glitch/components/copy_paste_text';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
import { Icon } from 'flavours/glitch/components/icon';
|
||||||
import { me, domain } from 'flavours/glitch/initial_state';
|
import { me, domain } from 'flavours/glitch/initial_state';
|
||||||
import { useAppSelector } from 'flavours/glitch/store';
|
import { useAppSelector } from 'flavours/glitch/store';
|
||||||
@ -20,67 +20,6 @@ const messages = defineMessages({
|
|||||||
shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' },
|
shareableMessage: { id: 'onboarding.share.message', defaultMessage: 'I\'m {username} on #Mastodon! Come follow me at {url}' },
|
||||||
});
|
});
|
||||||
|
|
||||||
class CopyPasteText extends PureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
value: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
copied: false,
|
|
||||||
focused: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
setRef = c => {
|
|
||||||
this.input = c;
|
|
||||||
};
|
|
||||||
|
|
||||||
handleInputClick = () => {
|
|
||||||
this.setState({ copied: false });
|
|
||||||
this.input.focus();
|
|
||||||
this.input.select();
|
|
||||||
this.input.setSelectionRange(0, this.props.value.length);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleButtonClick = e => {
|
|
||||||
e.stopPropagation();
|
|
||||||
|
|
||||||
const { value } = this.props;
|
|
||||||
navigator.clipboard.writeText(value);
|
|
||||||
this.input.blur();
|
|
||||||
this.setState({ copied: true });
|
|
||||||
this.timeout = setTimeout(() => this.setState({ copied: false }), 700);
|
|
||||||
};
|
|
||||||
|
|
||||||
handleFocus = () => {
|
|
||||||
this.setState({ focused: true });
|
|
||||||
};
|
|
||||||
|
|
||||||
handleBlur = () => {
|
|
||||||
this.setState({ focused: false });
|
|
||||||
};
|
|
||||||
|
|
||||||
componentWillUnmount () {
|
|
||||||
if (this.timeout) clearTimeout(this.timeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { value } = this.props;
|
|
||||||
const { copied, focused } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames('copy-paste-text', { copied, focused })} tabIndex='0' role='button' onClick={this.handleInputClick}>
|
|
||||||
<textarea readOnly value={value} ref={this.setRef} onClick={this.handleInputClick} onFocus={this.handleFocus} onBlur={this.handleBlur} />
|
|
||||||
|
|
||||||
<button className='button' onClick={this.handleButtonClick}>
|
|
||||||
<Icon id='copy' icon={ContentCopyIcon} /> {copied ? <FormattedMessage id='copypaste.copied' defaultMessage='Copied' /> : <FormattedMessage id='copypaste.copy_to_clipboard' defaultMessage='Copy to clipboard' />}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
class TipCarousel extends PureComponent {
|
class TipCarousel extends PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
|
@ -49,7 +49,7 @@ const messages = defineMessages({
|
|||||||
share: { id: 'status.share', defaultMessage: 'Share' },
|
share: { id: 'status.share', defaultMessage: 'Share' },
|
||||||
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
pin: { id: 'status.pin', defaultMessage: 'Pin on profile' },
|
||||||
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
unpin: { id: 'status.unpin', defaultMessage: 'Unpin from profile' },
|
||||||
embed: { id: 'status.embed', defaultMessage: 'Embed' },
|
embed: { id: 'status.embed', defaultMessage: 'Get embed code' },
|
||||||
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
|
||||||
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
|
admin_status: { id: 'status.admin_status', defaultMessage: 'Open this post in the moderation interface' },
|
||||||
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
admin_domain: { id: 'status.admin_domain', defaultMessage: 'Open moderation interface for {domain}' },
|
||||||
|
@ -1,101 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { defineMessages, FormattedMessage, injectIntl } from 'react-intl';
|
|
||||||
|
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
|
||||||
|
|
||||||
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
|
||||||
import api from 'flavours/glitch/api';
|
|
||||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
|
||||||
close: { id: 'lightbox.close', defaultMessage: 'Close' },
|
|
||||||
});
|
|
||||||
|
|
||||||
class EmbedModal extends ImmutablePureComponent {
|
|
||||||
|
|
||||||
static propTypes = {
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
onClose: PropTypes.func.isRequired,
|
|
||||||
onError: PropTypes.func.isRequired,
|
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
state = {
|
|
||||||
loading: false,
|
|
||||||
oembed: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
componentDidMount () {
|
|
||||||
const { id } = this.props;
|
|
||||||
|
|
||||||
this.setState({ loading: true });
|
|
||||||
|
|
||||||
api().get(`/api/web/embeds/${id}`).then(res => {
|
|
||||||
this.setState({ loading: false, oembed: res.data });
|
|
||||||
|
|
||||||
const iframeDocument = this.iframe.contentWindow.document;
|
|
||||||
|
|
||||||
iframeDocument.open();
|
|
||||||
iframeDocument.write(res.data.html);
|
|
||||||
iframeDocument.close();
|
|
||||||
|
|
||||||
iframeDocument.body.style.margin = 0;
|
|
||||||
this.iframe.width = iframeDocument.body.scrollWidth;
|
|
||||||
this.iframe.height = iframeDocument.body.scrollHeight;
|
|
||||||
}).catch(error => {
|
|
||||||
this.props.onError(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setIframeRef = c => {
|
|
||||||
this.iframe = c;
|
|
||||||
};
|
|
||||||
|
|
||||||
handleTextareaClick = (e) => {
|
|
||||||
e.target.select();
|
|
||||||
};
|
|
||||||
|
|
||||||
render () {
|
|
||||||
const { intl, onClose } = this.props;
|
|
||||||
const { oembed } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='modal-root__modal report-modal embed-modal'>
|
|
||||||
<div className='report-modal__target'>
|
|
||||||
<IconButton className='media-modal__close' title={intl.formatMessage(messages.close)} icon='times' iconComponent={CloseIcon} onClick={onClose} size={16} />
|
|
||||||
<FormattedMessage id='status.embed' defaultMessage='Embed' />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='report-modal__container embed-modal__container' style={{ display: 'block' }}>
|
|
||||||
<p className='hint'>
|
|
||||||
<FormattedMessage id='embed.instructions' defaultMessage='Embed this status on your website by copying the code below.' />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='embed-modal__html'
|
|
||||||
readOnly
|
|
||||||
value={oembed && oembed.html || ''}
|
|
||||||
onClick={this.handleTextareaClick}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<p className='hint'>
|
|
||||||
<FormattedMessage id='embed.preview' defaultMessage='Here is what it will look like:' />
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<iframe
|
|
||||||
className='embed-modal__iframe'
|
|
||||||
frameBorder='0'
|
|
||||||
ref={this.setIframeRef}
|
|
||||||
sandbox='allow-scripts allow-same-origin'
|
|
||||||
title='preview'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default injectIntl(EmbedModal);
|
|
@ -0,0 +1,116 @@
|
|||||||
|
import { useRef, useState, useEffect } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage } from 'react-intl';
|
||||||
|
|
||||||
|
import { showAlertForError } from 'flavours/glitch/actions/alerts';
|
||||||
|
import api from 'flavours/glitch/api';
|
||||||
|
import { Button } from 'flavours/glitch/components/button';
|
||||||
|
import { CopyPasteText } from 'flavours/glitch/components/copy_paste_text';
|
||||||
|
import { useAppDispatch } from 'flavours/glitch/store';
|
||||||
|
|
||||||
|
interface OEmbedResponse {
|
||||||
|
html: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const EmbedModal: React.FC<{
|
||||||
|
id: string;
|
||||||
|
onClose: () => void;
|
||||||
|
}> = ({ id, onClose }) => {
|
||||||
|
const iframeRef = useRef<HTMLIFrameElement>(null);
|
||||||
|
const intervalRef = useRef<ReturnType<typeof setInterval>>();
|
||||||
|
const [oembed, setOembed] = useState<OEmbedResponse | null>(null);
|
||||||
|
const dispatch = useAppDispatch();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
api()
|
||||||
|
.get(`/api/web/embeds/${id}`)
|
||||||
|
.then((res) => {
|
||||||
|
const data = res.data as OEmbedResponse;
|
||||||
|
|
||||||
|
setOembed(data);
|
||||||
|
|
||||||
|
const iframeDocument = iframeRef.current?.contentWindow?.document;
|
||||||
|
|
||||||
|
if (!iframeDocument) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
iframeDocument.open();
|
||||||
|
iframeDocument.write(data.html);
|
||||||
|
iframeDocument.close();
|
||||||
|
|
||||||
|
iframeDocument.body.style.margin = '0px';
|
||||||
|
|
||||||
|
// This is our best chance to ensure the parent iframe has the correct height...
|
||||||
|
intervalRef.current = setInterval(
|
||||||
|
() =>
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
if (iframeRef.current) {
|
||||||
|
iframeRef.current.width = `${iframeDocument.body.scrollWidth}px`;
|
||||||
|
iframeRef.current.height = `${iframeDocument.body.scrollHeight}px`;
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
|
||||||
|
return '';
|
||||||
|
})
|
||||||
|
.catch((error: unknown) => {
|
||||||
|
dispatch(showAlertForError(error));
|
||||||
|
});
|
||||||
|
}, [dispatch, id, setOembed]);
|
||||||
|
|
||||||
|
useEffect(
|
||||||
|
() => () => {
|
||||||
|
if (intervalRef.current) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='modal-root__modal dialog-modal'>
|
||||||
|
<div className='dialog-modal__header'>
|
||||||
|
<Button onClick={onClose}>
|
||||||
|
<FormattedMessage id='report.close' defaultMessage='Done' />
|
||||||
|
</Button>
|
||||||
|
<span className='dialog-modal__header__title'>
|
||||||
|
<FormattedMessage id='status.embed' defaultMessage='Get embed code' />
|
||||||
|
</span>
|
||||||
|
<Button secondary onClick={onClose}>
|
||||||
|
<FormattedMessage
|
||||||
|
id='confirmation_modal.cancel'
|
||||||
|
defaultMessage='Cancel'
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='dialog-modal__content'>
|
||||||
|
<div className='dialog-modal__content__form'>
|
||||||
|
<FormattedMessage
|
||||||
|
id='embed.instructions'
|
||||||
|
defaultMessage='Embed this status on your website by copying the code below.'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<CopyPasteText value={oembed?.html ?? ''} />
|
||||||
|
|
||||||
|
<FormattedMessage
|
||||||
|
id='embed.preview'
|
||||||
|
defaultMessage='Here is what it will look like:'
|
||||||
|
/>
|
||||||
|
|
||||||
|
<iframe
|
||||||
|
frameBorder='0'
|
||||||
|
ref={iframeRef}
|
||||||
|
sandbox='allow-scripts allow-same-origin'
|
||||||
|
title='Preview'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
|
export default EmbedModal;
|
@ -6741,6 +6741,50 @@ a.status-card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dialog-modal {
|
||||||
|
width: 588px;
|
||||||
|
max-height: 80vh;
|
||||||
|
flex-direction: column;
|
||||||
|
background: var(--modal-background-color);
|
||||||
|
backdrop-filter: var(--background-filter);
|
||||||
|
border: 1px solid var(--modal-border-color);
|
||||||
|
border-radius: 16px;
|
||||||
|
|
||||||
|
&__header {
|
||||||
|
border-bottom: 1px solid var(--modal-border-color);
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
flex-direction: row-reverse;
|
||||||
|
padding: 12px 24px;
|
||||||
|
|
||||||
|
&__title {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
letter-spacing: 0.15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
font-size: 14px;
|
||||||
|
line-height: 20px;
|
||||||
|
letter-spacing: 0.25px;
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
&__form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-paste-text {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.hotkey-combination {
|
.hotkey-combination {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -8273,69 +8317,6 @@ noscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.embed-modal {
|
|
||||||
width: auto;
|
|
||||||
max-width: 80vw;
|
|
||||||
max-height: 80vh;
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
padding: 30px;
|
|
||||||
font-weight: 500;
|
|
||||||
font-size: 16px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-modal__container {
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
.hint {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-modal__html {
|
|
||||||
outline: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
border: 0;
|
|
||||||
padding: 10px;
|
|
||||||
font-family: $font-monospace, monospace;
|
|
||||||
background: $ui-base-color;
|
|
||||||
color: $primary-text-color;
|
|
||||||
font-size: 14px;
|
|
||||||
margin: 0;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&::-moz-focus-inner {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::-moz-focus-inner,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
outline: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
background: lighten($ui-base-color, 4%);
|
|
||||||
}
|
|
||||||
|
|
||||||
@media screen and (width <= 600px) {
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.embed-modal__iframe {
|
|
||||||
width: 400px;
|
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
|
||||||
border: 0;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.moved-account-banner,
|
.moved-account-banner,
|
||||||
.follow-request-banner,
|
.follow-request-banner,
|
||||||
.account-memorial-banner {
|
.account-memorial-banner {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user