mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-24 19:37:26 +00:00
[Glitch] Change icons in web UI
Port 134de736dc to glitch-soc
Co-authored-by: Renaud Chaput <renchap@gmail.com>
Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
@@ -7,7 +7,9 @@ import classNames from 'classnames';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { ReactComponent as LinkIcon } from '@material-symbols/svg-600/outlined/link.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
|
||||
const filename = url => url.split('/').pop().split('#')[0].split('?')[0];
|
||||
|
||||
@@ -25,7 +27,7 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
<div className={classNames('attachment-list', { compact })}>
|
||||
{!compact && (
|
||||
<div className='attachment-list__icon'>
|
||||
<Icon id='link' />
|
||||
<Icon id='link' icon={LinkIcon} />
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -36,7 +38,7 @@ export default class AttachmentList extends ImmutablePureComponent {
|
||||
return (
|
||||
<li key={attachment.get('id')}>
|
||||
<a href={displayUrl} target='_blank' rel='noopener noreferrer'>
|
||||
{compact && <Icon id='link' />}
|
||||
{compact && <Icon id='link' icon={LinkIcon} />}
|
||||
{compact && ' ' }
|
||||
{displayUrl ? filename(displayUrl) : <FormattedMessage id='attachments_list.unprocessed' defaultMessage='(unprocessed)' />}
|
||||
</a>
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
export const Check: React.FC = () => (
|
||||
<svg
|
||||
xmlns='http://www.w3.org/2000/svg'
|
||||
viewBox='0 0 20 20'
|
||||
fill='currentColor'
|
||||
>
|
||||
<path
|
||||
fillRule='evenodd'
|
||||
d='M16.704 4.153a.75.75 0 01.143 1.052l-8 10.5a.75.75 0 01-1.127.075l-4.5-4.5a.75.75 0 011.06-1.06l3.894 3.893 7.48-9.817a.75.75 0 011.05-.143z'
|
||||
clipRule='evenodd'
|
||||
/>
|
||||
</svg>
|
||||
);
|
||||
@@ -6,6 +6,8 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||
|
||||
@@ -34,7 +36,7 @@ export class ColumnBackButton extends PureComponent {
|
||||
|
||||
const component = (
|
||||
<button onClick={this.handleClick} className='column-back-button'>
|
||||
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</button>
|
||||
);
|
||||
|
||||
@@ -4,6 +4,8 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||
|
||||
@@ -29,7 +31,7 @@ class ColumnBackButtonSlim extends PureComponent {
|
||||
return (
|
||||
<div className='column-back-button--slim'>
|
||||
<div role='button' tabIndex={0} onClick={this.handleClick} className='column-back-button column-back-button--slim-button'>
|
||||
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -7,6 +7,13 @@ import { FormattedMessage, injectIntl, defineMessages } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { ReactComponent as AddIcon } from '@material-symbols/svg-600/outlined/add.svg';
|
||||
import { ReactComponent as ArrowBackIcon } from '@material-symbols/svg-600/outlined/arrow_back.svg';
|
||||
import { ReactComponent as ChevronLeftIcon } from '@material-symbols/svg-600/outlined/chevron_left.svg';
|
||||
import { ReactComponent as ChevronRightIcon } from '@material-symbols/svg-600/outlined/chevron_right.svg';
|
||||
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
|
||||
import { ReactComponent as TuneIcon } from '@material-symbols/svg-600/outlined/tune.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||
|
||||
@@ -27,6 +34,7 @@ class ColumnHeader extends PureComponent {
|
||||
intl: PropTypes.object.isRequired,
|
||||
title: PropTypes.node,
|
||||
icon: PropTypes.string,
|
||||
iconComponent: PropTypes.func,
|
||||
active: PropTypes.bool,
|
||||
multiColumn: PropTypes.bool,
|
||||
extraButton: PropTypes.node,
|
||||
@@ -87,7 +95,7 @@ class ColumnHeader extends PureComponent {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { title, icon, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
|
||||
const { title, icon, iconComponent, active, children, pinned, multiColumn, extraButton, showBackButton, intl: { formatMessage }, placeholder, appendContent, collapseIssues, history } = this.props;
|
||||
const { collapsed, animating } = this.state;
|
||||
|
||||
const wrapperClassName = classNames('column-header__wrapper', {
|
||||
@@ -118,22 +126,22 @@ class ColumnHeader extends PureComponent {
|
||||
}
|
||||
|
||||
if (multiColumn && pinned) {
|
||||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
|
||||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='times' icon={CloseIcon} /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>;
|
||||
|
||||
moveButtons = (
|
||||
<div key='move-buttons' className='column-header__setting-arrows'>
|
||||
<button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='icon-button column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' /></button>
|
||||
<button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='icon-button column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' /></button>
|
||||
<button title={formatMessage(messages.moveLeft)} aria-label={formatMessage(messages.moveLeft)} className='icon-button column-header__setting-btn' onClick={this.handleMoveLeft}><Icon id='chevron-left' icon={ChevronLeftIcon} /></button>
|
||||
<button title={formatMessage(messages.moveRight)} aria-label={formatMessage(messages.moveRight)} className='icon-button column-header__setting-btn' onClick={this.handleMoveRight}><Icon id='chevron-right' icon={ChevronRightIcon} /></button>
|
||||
</div>
|
||||
);
|
||||
} else if (multiColumn && this.props.onPin) {
|
||||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
|
||||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={this.handlePin}><Icon id='plus' icon={AddIcon} /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>;
|
||||
}
|
||||
|
||||
if (!pinned && ((multiColumn && history.location?.state?.fromMastodon) || showBackButton)) {
|
||||
backButton = (
|
||||
<button onClick={this.handleBackClick} className='column-header__back-button'>
|
||||
<Icon id='chevron-left' className='column-back-button__icon' fixedWidth />
|
||||
<Icon id='chevron-left' icon={ArrowBackIcon} className='column-back-button__icon' />
|
||||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' />
|
||||
</button>
|
||||
);
|
||||
@@ -157,21 +165,21 @@ class ColumnHeader extends PureComponent {
|
||||
onClick={this.handleToggleClick}
|
||||
>
|
||||
<i className='icon-with-badge'>
|
||||
<Icon id='sliders' />
|
||||
<Icon id='sliders' icon={TuneIcon} />
|
||||
{collapseIssues && <i className='icon-with-badge__issue-badge' />}
|
||||
</i>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
const hasTitle = icon && title;
|
||||
const hasTitle = (icon || iconComponent) && title;
|
||||
|
||||
const component = (
|
||||
<div className={wrapperClassName}>
|
||||
<h1 className={buttonClassName}>
|
||||
{hasTitle && (
|
||||
<button onClick={this.handleTitleClick}>
|
||||
<Icon id={icon} fixedWidth className='column-header__icon' />
|
||||
<Icon id={icon} icon={iconComponent} className='column-header__icon' />
|
||||
{title}
|
||||
</button>
|
||||
)}
|
||||
|
||||
@@ -8,6 +8,8 @@ import { useCallback, useState, useEffect } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
|
||||
|
||||
import { changeSetting } from 'flavours/glitch/actions/settings';
|
||||
import { bannerSettings } from 'flavours/glitch/settings';
|
||||
import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
|
||||
@@ -55,6 +57,7 @@ export const DismissableBanner: React.FC<PropsWithChildren<Props>> = ({
|
||||
<div className='dismissable-banner__action'>
|
||||
<IconButton
|
||||
icon='times'
|
||||
iconComponent={CloseIcon}
|
||||
title={intl.formatMessage(messages.dismiss)}
|
||||
onClick={handleDismiss}
|
||||
/>
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useCallback } from 'react';
|
||||
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
|
||||
|
||||
import { IconButton } from './icon_button';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -34,6 +36,7 @@ export const Domain: React.FC<Props> = ({ domain, onUnblockDomain }) => {
|
||||
<IconButton
|
||||
active
|
||||
icon='unlock'
|
||||
iconComponent={LockOpenIcon}
|
||||
title={intl.formatMessage(messages.unblockDomain, { domain })}
|
||||
onClick={handleDomainUnblock}
|
||||
/>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { withRouter } from 'react-router-dom';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { ReactComponent as CloseIcon } from '@material-symbols/svg-600/outlined/close.svg';
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
|
||||
@@ -163,6 +164,7 @@ class Dropdown extends PureComponent {
|
||||
static propTypes = {
|
||||
children: PropTypes.node,
|
||||
icon: PropTypes.string,
|
||||
iconComponent: PropTypes.func,
|
||||
items: PropTypes.oneOfType([PropTypes.array, ImmutablePropTypes.list]).isRequired,
|
||||
loading: PropTypes.bool,
|
||||
size: PropTypes.number,
|
||||
@@ -255,7 +257,7 @@ class Dropdown extends PureComponent {
|
||||
};
|
||||
|
||||
findTarget = () => {
|
||||
return this.target;
|
||||
return this.target?.buttonRef?.current;
|
||||
};
|
||||
|
||||
componentWillUnmount = () => {
|
||||
@@ -271,6 +273,7 @@ class Dropdown extends PureComponent {
|
||||
render () {
|
||||
const {
|
||||
icon,
|
||||
iconComponent,
|
||||
items,
|
||||
size,
|
||||
title,
|
||||
@@ -291,9 +294,11 @@ class Dropdown extends PureComponent {
|
||||
onMouseDown: this.handleMouseDown,
|
||||
onKeyDown: this.handleButtonKeyDown,
|
||||
onKeyPress: this.handleKeyPress,
|
||||
ref: this.setTargetRef,
|
||||
}) : (
|
||||
<IconButton
|
||||
icon={icon}
|
||||
icon={!open ? icon : 'close'}
|
||||
iconComponent={!open ? iconComponent : CloseIcon}
|
||||
title={title}
|
||||
active={open}
|
||||
disabled={disabled}
|
||||
@@ -302,14 +307,14 @@ class Dropdown extends PureComponent {
|
||||
onMouseDown={this.handleMouseDown}
|
||||
onKeyDown={this.handleButtonKeyDown}
|
||||
onKeyPress={this.handleKeyPress}
|
||||
ref={this.setTargetRef}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<span ref={this.setTargetRef}>
|
||||
{button}
|
||||
</span>
|
||||
{button}
|
||||
|
||||
<Overlay show={open} offset={[5, 5]} placement={'bottom'} flip target={this.findTarget} popperConfig={{ strategy: 'fixed' }}>
|
||||
{({ props, arrowProps, placement }) => (
|
||||
<div {...props}>
|
||||
|
||||
@@ -5,6 +5,8 @@ import { FormattedMessage, injectIntl } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { ReactComponent as ArrowDropDownIcon } from '@material-symbols/svg-600/outlined/arrow_drop_down.svg';
|
||||
|
||||
import { openModal } from 'flavours/glitch/actions/modal';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import InlineAccount from 'flavours/glitch/components/inline_account';
|
||||
@@ -66,7 +68,7 @@ class EditedTimestamp extends PureComponent {
|
||||
return (
|
||||
<DropdownMenu statusId={statusId} renderItem={this.renderItem} scrollable renderHeader={this.renderHeader} onItemClick={this.handleItemClick}>
|
||||
<button className='dropdown-menu__text-button'>
|
||||
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' />
|
||||
<FormattedMessage id='status.edited' defaultMessage='Edited {date}' values={{ date: intl.formatDate(timestamp, { hour12: false, month: 'short', day: '2-digit', hour: '2-digit', minute: '2-digit' }) }} /> <Icon id='caret-down' icon={ArrowDropDownIcon} />
|
||||
</button>
|
||||
</DropdownMenu>
|
||||
);
|
||||
|
||||
@@ -1,20 +1,50 @@
|
||||
import classNames from 'classnames';
|
||||
|
||||
interface Props extends React.HTMLAttributes<HTMLImageElement> {
|
||||
id: string;
|
||||
className?: string;
|
||||
fixedWidth?: boolean;
|
||||
import { ReactComponent as CheckBoxOutlineBlankIcon } from '@material-symbols/svg-600/outlined/check_box_outline_blank.svg';
|
||||
|
||||
interface SVGPropsWithTitle extends React.SVGProps<SVGSVGElement> {
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export type IconProp = React.FC<SVGPropsWithTitle>;
|
||||
|
||||
interface Props extends React.SVGProps<SVGSVGElement> {
|
||||
children?: never;
|
||||
id: string;
|
||||
icon: IconProp;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const Icon: React.FC<Props> = ({
|
||||
id,
|
||||
icon: IconComponent,
|
||||
className,
|
||||
fixedWidth,
|
||||
title: titleProp,
|
||||
...other
|
||||
}) => (
|
||||
<i
|
||||
className={classNames('fa', `fa-${id}`, className, { 'fa-fw': fixedWidth })}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
}) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (!IconComponent) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
throw new Error(`<Icon id="${id}"> is missing an "icon" prop.`);
|
||||
}
|
||||
|
||||
IconComponent = CheckBoxOutlineBlankIcon;
|
||||
}
|
||||
|
||||
const ariaHidden = titleProp ? undefined : true;
|
||||
const role = !ariaHidden ? 'img' : undefined;
|
||||
|
||||
// Set the title to an empty string to remove the built-in SVG one if any
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
|
||||
const title = titleProp || '';
|
||||
|
||||
return (
|
||||
<IconComponent
|
||||
className={classNames('icon', `icon-${id}`, className)}
|
||||
title={title}
|
||||
aria-hidden={ariaHidden}
|
||||
role={role}
|
||||
{...other}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,19 +1,20 @@
|
||||
import { PureComponent } from 'react';
|
||||
import { PureComponent, createRef } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { AnimatedNumber } from './animated_number';
|
||||
import type { IconProp } from './icon';
|
||||
import { Icon } from './icon';
|
||||
|
||||
interface Props {
|
||||
className?: string;
|
||||
title: string;
|
||||
icon: string;
|
||||
iconComponent: IconProp;
|
||||
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
onMouseDown?: React.MouseEventHandler<HTMLButtonElement>;
|
||||
onKeyDown?: React.KeyboardEventHandler<HTMLButtonElement>;
|
||||
onKeyPress?: React.KeyboardEventHandler<HTMLButtonElement>;
|
||||
size: number;
|
||||
active: boolean;
|
||||
expanded?: boolean;
|
||||
style?: React.CSSProperties;
|
||||
@@ -34,8 +35,9 @@ interface States {
|
||||
deactivate: boolean;
|
||||
}
|
||||
export class IconButton extends PureComponent<Props, States> {
|
||||
buttonRef = createRef<HTMLButtonElement>();
|
||||
|
||||
static defaultProps = {
|
||||
size: 18,
|
||||
active: false,
|
||||
disabled: false,
|
||||
animate: false,
|
||||
@@ -86,24 +88,10 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
};
|
||||
|
||||
render() {
|
||||
// Hack required for some icons which have an overriden size
|
||||
let containerSize = '1.28571429em';
|
||||
if (this.props.style?.fontSize) {
|
||||
containerSize = `${this.props.size * 1.28571429}px`;
|
||||
}
|
||||
|
||||
const style = {
|
||||
fontSize: `${this.props.size}px`,
|
||||
height: containerSize,
|
||||
lineHeight: `${this.props.size}px`,
|
||||
...this.props.style,
|
||||
...(this.props.active ? this.props.activeStyle : {}),
|
||||
};
|
||||
if (!this.props.label) {
|
||||
style.width = containerSize;
|
||||
} else {
|
||||
style.textAlign = 'left';
|
||||
}
|
||||
|
||||
const {
|
||||
active,
|
||||
@@ -111,6 +99,7 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
disabled,
|
||||
expanded,
|
||||
icon,
|
||||
iconComponent,
|
||||
inverted,
|
||||
overlay,
|
||||
tabIndex,
|
||||
@@ -133,13 +122,9 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
'icon-button--with-counter': typeof counter !== 'undefined',
|
||||
});
|
||||
|
||||
if (typeof counter !== 'undefined') {
|
||||
style.width = 'auto';
|
||||
}
|
||||
|
||||
let contents = (
|
||||
<>
|
||||
<Icon id={icon} fixedWidth aria-hidden='true' />{' '}
|
||||
<Icon id={icon} icon={iconComponent} aria-hidden='true' />{' '}
|
||||
{typeof counter !== 'undefined' && (
|
||||
<span className='icon-button__counter'>
|
||||
<AnimatedNumber value={counter} obfuscate={obfuscateCount} />
|
||||
@@ -172,6 +157,7 @@ export class IconButton extends PureComponent<Props, States> {
|
||||
style={style}
|
||||
tabIndex={tabIndex}
|
||||
disabled={disabled}
|
||||
ref={this.buttonRef}
|
||||
>
|
||||
{contents}
|
||||
</button>
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
import type { IconProp } from './icon';
|
||||
import { Icon } from './icon';
|
||||
|
||||
const formatNumber = (num: number): number | string => (num > 40 ? '40+' : num);
|
||||
|
||||
interface Props {
|
||||
id: string;
|
||||
icon: IconProp;
|
||||
count: number;
|
||||
issueBadge: boolean;
|
||||
className: string;
|
||||
}
|
||||
export const IconWithBadge: React.FC<Props> = ({
|
||||
id,
|
||||
icon,
|
||||
count,
|
||||
issueBadge,
|
||||
className,
|
||||
}) => (
|
||||
<i className='icon-with-badge'>
|
||||
<Icon id={id} fixedWidth className={className} />
|
||||
<Icon id={id} icon={icon} className={className} />
|
||||
{count > 0 && (
|
||||
<i className='icon-with-badge__badge'>{formatNumber(count)}</i>
|
||||
)}
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useCallback } from 'react';
|
||||
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
|
||||
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -28,7 +30,7 @@ export const LoadGap: React.FC<Props> = ({ disabled, maxId, onClick }) => {
|
||||
onClick={handleClick}
|
||||
aria-label={intl.formatMessage(messages.load_more)}
|
||||
>
|
||||
<Icon id='ellipsis-h' />
|
||||
<Icon id='ellipsis-h' icon={MoreHorizIcon} />
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@ import classNames from 'classnames';
|
||||
import { is } from 'immutable';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { ReactComponent as VisibilityOffIcon } from '@material-symbols/svg-600/outlined/visibility_off.svg';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import { Blurhash } from 'flavours/glitch/components/blurhash';
|
||||
@@ -362,7 +363,7 @@ class MediaGallery extends PureComponent {
|
||||
</button>
|
||||
);
|
||||
} else if (visible) {
|
||||
spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' overlay onClick={this.handleOpen} ariaHidden />;
|
||||
spoilerButton = <IconButton title={intl.formatMessage(messages.toggle_visible, { number: size })} icon='eye-slash' iconComponent={VisibilityOffIcon} overlay onClick={this.handleOpen} ariaHidden />;
|
||||
} else {
|
||||
spoilerButton = (
|
||||
<button type='button' onClick={this.handleOpen} className='spoiler-button__overlay'>
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
* a Confirm and Abort buttons are shown in its place.
|
||||
*/
|
||||
|
||||
|
||||
// Package imports //
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
@@ -14,6 +12,8 @@ import classNames from 'classnames';
|
||||
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import { ReactComponent as DeleteIcon } from '@material-symbols/svg-600/outlined/delete.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
@@ -53,7 +53,7 @@ class NotificationPurgeButtons extends ImmutablePureComponent {
|
||||
</button>
|
||||
|
||||
<button onClick={this.props.onDeleteMarked} className='column-header__button'>
|
||||
<Icon id='trash' /><br />{intl.formatMessage(messages.btnApply)}
|
||||
<Icon id='trash' icon={DeleteIcon} /><br />{intl.formatMessage(messages.btnApply)}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -5,6 +5,8 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { connect } from 'react-redux';
|
||||
|
||||
import { ReactComponent as CancelPresentationIcon } from '@material-symbols/svg-600/outlined/cancel_presentation.svg';
|
||||
|
||||
import { removePictureInPicture } from 'flavours/glitch/actions/picture_in_picture';
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
|
||||
@@ -22,7 +24,7 @@ class PictureInPicturePlaceholder extends PureComponent {
|
||||
render () {
|
||||
return (
|
||||
<div className='picture-in-picture-placeholder' role='button' tabIndex={0} onClick={this.handleClick}>
|
||||
<Icon id='window-restore' />
|
||||
<Icon id='window-restore' icon={CancelPresentationIcon} />
|
||||
<FormattedMessage id='picture_in_picture.restore' defaultMessage='Put it back' />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import classNames from 'classnames';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
|
||||
import escapeTextContentForBrowser from 'escape-html';
|
||||
import spring from 'react-motion/lib/spring';
|
||||
|
||||
@@ -192,7 +193,7 @@ class Poll extends ImmutablePureComponent {
|
||||
/>
|
||||
|
||||
{!!voted && <span className='poll__voted'>
|
||||
<Icon id='check' className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
|
||||
<Icon id='check' icon={CheckIcon} className='poll__voted__mark' title={intl.formatMessage(messages.voted)} />
|
||||
</span>}
|
||||
</label>
|
||||
|
||||
|
||||
@@ -8,6 +8,16 @@ import { withRouter } from 'react-router-dom';
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import { ReactComponent as BookmarkIcon } from '@material-symbols/svg-600/outlined/bookmark-fill.svg';
|
||||
import { ReactComponent as BookmarkBorderIcon } from '@material-symbols/svg-600/outlined/bookmark.svg';
|
||||
import { ReactComponent as MoreHorizIcon } from '@material-symbols/svg-600/outlined/more_horiz.svg';
|
||||
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
|
||||
import { ReactComponent as ReplyIcon } from '@material-symbols/svg-600/outlined/reply.svg';
|
||||
import { ReactComponent as ReplyAllIcon } from '@material-symbols/svg-600/outlined/reply_all.svg';
|
||||
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
|
||||
import { ReactComponent as StarBorderIcon } from '@material-symbols/svg-600/outlined/star.svg';
|
||||
import { ReactComponent as VisibilityIcon } from '@material-symbols/svg-600/outlined/visibility.svg';
|
||||
|
||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
||||
import { accountAdminLink, statusAdminLink } from 'flavours/glitch/utils/backend_links';
|
||||
import { WithRouterPropTypes } from 'flavours/glitch/utils/react_router';
|
||||
@@ -208,6 +218,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
let menu = [];
|
||||
let reblogIcon = 'retweet';
|
||||
let replyIcon;
|
||||
let replyIconComponent;
|
||||
let replyTitle;
|
||||
|
||||
menu.push({ text: intl.formatMessage(messages.open), action: this.handleOpen });
|
||||
@@ -277,9 +288,11 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
|
||||
if (status.get('in_reply_to_id', null) === null) {
|
||||
replyIcon = 'reply';
|
||||
replyIconComponent = ReplyIcon;
|
||||
replyTitle = intl.formatMessage(messages.reply);
|
||||
} else {
|
||||
replyIcon = 'reply-all';
|
||||
replyIconComponent = ReplyAllIcon;
|
||||
replyTitle = intl.formatMessage(messages.replyAll);
|
||||
}
|
||||
|
||||
@@ -297,7 +310,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
}
|
||||
|
||||
const filterButton = this.props.onFilter && (
|
||||
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' onClick={this.handleHideClick} />
|
||||
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.hide)} icon='eye' iconComponent={VisibilityIcon} onClick={this.handleHideClick} />
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -306,27 +319,27 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||
className='status__action-bar-button'
|
||||
title={replyTitle}
|
||||
icon={replyIcon}
|
||||
iconComponent={replyIconComponent}
|
||||
onClick={this.handleReplyClick}
|
||||
counter={showReplyCount ? status.get('replies_count') : undefined}
|
||||
obfuscateCount
|
||||
/>
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
|
||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
||||
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
|
||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} iconComponent={RepeatIcon} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
|
||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
||||
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
||||
|
||||
{filterButton}
|
||||
|
||||
<div className='status__action-bar-dropdown'>
|
||||
<DropdownMenuContainer
|
||||
scrollKey={scrollKey}
|
||||
status={status}
|
||||
items={menu}
|
||||
icon='ellipsis-h'
|
||||
size={18}
|
||||
direction='right'
|
||||
ariaLabel={intl.formatMessage(messages.more)}
|
||||
/>
|
||||
</div>
|
||||
<DropdownMenuContainer
|
||||
scrollKey={scrollKey}
|
||||
status={status}
|
||||
items={menu}
|
||||
icon='ellipsis-h'
|
||||
size={18}
|
||||
iconComponent={MoreHorizIcon}
|
||||
direction='right'
|
||||
ariaLabel={intl.formatMessage(messages.more)}
|
||||
/>
|
||||
|
||||
<div className='status__action-bar-spacer' />
|
||||
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'>
|
||||
|
||||
@@ -6,15 +6,16 @@ import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { ReactComponent as ExpandLessIcon } from '@material-symbols/svg-600/outlined/expand_less.svg';
|
||||
import { ReactComponent as ForumIcon } from '@material-symbols/svg-600/outlined/forum.svg';
|
||||
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home.svg';
|
||||
|
||||
// Mastodon imports.
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { languages } from 'flavours/glitch/initial_state';
|
||||
|
||||
import { IconButton } from './icon_button';
|
||||
import VisibilityIcon from './status_visibility_icon';
|
||||
import { VisibilityIcon } from './visibility_icon';
|
||||
|
||||
// Messages for use with internationalization stuff.
|
||||
const messages = defineMessages({
|
||||
collapse: { id: 'status.collapse', defaultMessage: 'Collapse' },
|
||||
uncollapse: { id: 'status.uncollapse', defaultMessage: 'Uncollapse' },
|
||||
@@ -92,7 +93,6 @@ class StatusIcons extends PureComponent {
|
||||
);
|
||||
}
|
||||
|
||||
// Rendering.
|
||||
render () {
|
||||
const {
|
||||
status,
|
||||
@@ -109,16 +109,16 @@ class StatusIcons extends PureComponent {
|
||||
{settings.get('reply') && status.get('in_reply_to_id', null) !== null ? (
|
||||
<Icon
|
||||
className='status__reply-icon'
|
||||
fixedWidth
|
||||
id='comment'
|
||||
icon={ForumIcon}
|
||||
aria-hidden='true'
|
||||
title={intl.formatMessage(messages.inReplyTo)}
|
||||
/>
|
||||
) : null}
|
||||
{settings.get('local_only') && status.get('local_only') &&
|
||||
<Icon
|
||||
fixedWidth
|
||||
id='home'
|
||||
icon={HomeIcon}
|
||||
aria-hidden='true'
|
||||
title={intl.formatMessage(messages.localOnly)}
|
||||
/>}
|
||||
@@ -135,6 +135,7 @@ class StatusIcons extends PureComponent {
|
||||
intl.formatMessage(messages.collapse)
|
||||
}
|
||||
icon='angle-double-up'
|
||||
iconComponent={ExpandLessIcon}
|
||||
onClick={this.handleCollapsedClick}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -6,6 +6,13 @@ import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||
|
||||
import { ReactComponent as EditIcon } from '@material-symbols/svg-600/outlined/edit.svg';
|
||||
import { ReactComponent as HomeIcon } from '@material-symbols/svg-600/outlined/home-fill.svg';
|
||||
import { ReactComponent as InsertChartIcon } from '@material-symbols/svg-600/outlined/insert_chart.svg';
|
||||
import { ReactComponent as PushPinIcon } from '@material-symbols/svg-600/outlined/push_pin.svg';
|
||||
import { ReactComponent as RepeatIcon } from '@material-symbols/svg-600/outlined/repeat.svg';
|
||||
import { ReactComponent as StarIcon } from '@material-symbols/svg-600/outlined/star-fill.svg';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
import { me } from 'flavours/glitch/initial_state';
|
||||
|
||||
@@ -107,27 +114,33 @@ export default class StatusPrepend extends PureComponent {
|
||||
const { Message } = this;
|
||||
const { type } = this.props;
|
||||
|
||||
let iconId;
|
||||
let iconId, iconComponent;
|
||||
|
||||
switch(type) {
|
||||
case 'favourite':
|
||||
iconId = 'star';
|
||||
iconComponent = StarIcon;
|
||||
break;
|
||||
case 'featured':
|
||||
iconId = 'thumb-tack';
|
||||
iconComponent = PushPinIcon;
|
||||
break;
|
||||
case 'poll':
|
||||
iconId = 'tasks';
|
||||
iconComponent = InsertChartIcon;
|
||||
break;
|
||||
case 'reblog':
|
||||
case 'reblogged_by':
|
||||
iconId = 'retweet';
|
||||
iconComponent = RepeatIcon;
|
||||
break;
|
||||
case 'status':
|
||||
iconId = 'bell';
|
||||
iconComponent = HomeIcon;
|
||||
break;
|
||||
case 'update':
|
||||
iconId = 'pencil';
|
||||
iconComponent = EditIcon;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -137,6 +150,7 @@ export default class StatusPrepend extends PureComponent {
|
||||
<Icon
|
||||
className={`status__prepend-icon ${type === 'favourite' ? 'star-icon' : ''}`}
|
||||
id={iconId}
|
||||
icon={iconComponent}
|
||||
/>
|
||||
</div>
|
||||
<Message />
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
// Package imports //
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { defineMessages, injectIntl } from 'react-intl';
|
||||
|
||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||
|
||||
import { Icon } from 'flavours/glitch/components/icon';
|
||||
|
||||
const messages = defineMessages({
|
||||
public: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
unlisted: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
||||
private: { id: 'privacy.private.short', defaultMessage: 'Followers only' },
|
||||
direct: { id: 'privacy.direct.short', defaultMessage: 'Mentioned people only' },
|
||||
});
|
||||
|
||||
class VisibilityIcon extends ImmutablePureComponent {
|
||||
|
||||
static propTypes = {
|
||||
visibility: PropTypes.string,
|
||||
intl: PropTypes.object.isRequired,
|
||||
withLabel: PropTypes.bool,
|
||||
};
|
||||
|
||||
render() {
|
||||
const { withLabel, visibility, intl } = this.props;
|
||||
|
||||
const visibilityIcon = {
|
||||
public: 'globe',
|
||||
unlisted: 'unlock',
|
||||
private: 'lock',
|
||||
direct: 'envelope',
|
||||
}[visibility];
|
||||
|
||||
const label = intl.formatMessage(messages[visibility]);
|
||||
|
||||
const icon = (<Icon
|
||||
className='status__visibility-icon'
|
||||
fixedWidth
|
||||
id={visibilityIcon}
|
||||
title={label}
|
||||
aria-hidden='true'
|
||||
/>);
|
||||
|
||||
if (withLabel) {
|
||||
return (<span style={{ whiteSpace: 'nowrap' }}>{icon} {label}</span>);
|
||||
} else {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(VisibilityIcon);
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ReactComponent as CheckIcon } from '@material-symbols/svg-600/outlined/check.svg';
|
||||
|
||||
import { Icon } from './icon';
|
||||
|
||||
const domParser = new DOMParser();
|
||||
@@ -21,7 +23,7 @@ interface Props {
|
||||
}
|
||||
export const VerifiedBadge: React.FC<Props> = ({ link }) => (
|
||||
<span className='verified-badge'>
|
||||
<Icon id='check' className='verified-badge__mark' />
|
||||
<Icon id='check' icon={CheckIcon} className='verified-badge__mark' />
|
||||
<span dangerouslySetInnerHTML={stripRelMe(link)} />
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
|
||||
import { ReactComponent as LockIcon } from '@material-symbols/svg-600/outlined/lock.svg';
|
||||
import { ReactComponent as LockOpenIcon } from '@material-symbols/svg-600/outlined/lock_open.svg';
|
||||
import { ReactComponent as MailIcon } from '@material-symbols/svg-600/outlined/mail.svg';
|
||||
import { ReactComponent as PublicIcon } from '@material-symbols/svg-600/outlined/public.svg';
|
||||
|
||||
import { Icon } from './icon';
|
||||
|
||||
type Visibility = 'public' | 'unlisted' | 'private' | 'direct';
|
||||
|
||||
const messages = defineMessages({
|
||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
unlisted_short: { id: 'privacy.unlisted.short', defaultMessage: 'Unlisted' },
|
||||
private_short: {
|
||||
id: 'privacy.private.short',
|
||||
defaultMessage: 'Followers only',
|
||||
},
|
||||
direct_short: {
|
||||
id: 'privacy.direct.short',
|
||||
defaultMessage: 'Mentioned people only',
|
||||
},
|
||||
});
|
||||
|
||||
export const VisibilityIcon: React.FC<{ visibility: Visibility }> = ({
|
||||
visibility,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const visibilityIconInfo = {
|
||||
public: {
|
||||
icon: 'globe',
|
||||
iconComponent: PublicIcon,
|
||||
text: intl.formatMessage(messages.public_short),
|
||||
},
|
||||
unlisted: {
|
||||
icon: 'unlock',
|
||||
iconComponent: LockOpenIcon,
|
||||
text: intl.formatMessage(messages.unlisted_short),
|
||||
},
|
||||
private: {
|
||||
icon: 'lock',
|
||||
iconComponent: LockIcon,
|
||||
text: intl.formatMessage(messages.private_short),
|
||||
},
|
||||
direct: {
|
||||
icon: 'envelope',
|
||||
iconComponent: MailIcon,
|
||||
text: intl.formatMessage(messages.direct_short),
|
||||
},
|
||||
};
|
||||
|
||||
const visibilityIcon = visibilityIconInfo[visibility];
|
||||
|
||||
return (
|
||||
<Icon
|
||||
id={visibilityIcon.icon}
|
||||
icon={visibilityIcon.iconComponent}
|
||||
title={visibilityIcon.text}
|
||||
/>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user