Add ReactIcons (#149)

This commit is contained in:
Riccardo Graziosi
2022-08-22 10:38:03 +02:00
committed by GitHub
parent 4c73b398e8
commit 6198d814d8
32 changed files with 267 additions and 226 deletions

View File

@@ -1,6 +1,9 @@
import * as React from 'react';
import I18n from 'i18n-js';
import Button from '../common/Button';
import Switch from '../common/Switch';
import ActionLink from '../common/ActionLink';
import { CancelIcon } from '../common/Icons';
interface Props {
id: number;
@@ -61,34 +64,23 @@ class CommentEditForm extends React.Component<Props, State> {
<div>
<div>
{
isPowerUser ?
<>
<input
id={`isPostUpdateFlagComment${id}`}
type="checkbox"
onChange={e => this.handleCommentIsPostUpdateChange(e.target.checked)}
checked={isPostUpdate || false}
/>
&nbsp;
<label htmlFor={`isPostUpdateFlagComment${id}`}>
{I18n.t('post.new_comment.is_post_update')}
</label>
</>
:
null
isPowerUser &&
<Switch
htmlId={`isPostUpdateFlagComment${id}`}
onClick={e => this.handleCommentIsPostUpdateChange(!isPostUpdate)}
checked={isPostUpdate || false}
label={I18n.t('post.new_comment.is_post_update')}
/>
}
</div>
<div>
<a className="commentLink" onClick={toggleEditMode}>
{ I18n.t('common.buttons.cancel') }
</a>
<div className="editCommentFormActions">
<ActionLink onClick={toggleEditMode} icon={<CancelIcon />}>
{I18n.t('common.buttons.cancel')}
</ActionLink>
&nbsp;
<Button
onClick={() => handleUpdateComment(body, isPostUpdate)}
>
{ I18n.t('common.buttons.update') }
<Button onClick={() => handleUpdateComment(body, isPostUpdate)}>
{I18n.t('common.buttons.update')}
</Button>
</div>
</div>

View File

@@ -5,6 +5,8 @@ import Separator from '../common/Separator';
import { MutedText } from '../common/CustomTexts';
import friendlyDate from '../../helpers/datetime';
import { ReplyFormState } from '../../reducers/replyFormReducer';
import ActionLink from '../common/ActionLink';
import { CancelIcon, DeleteIcon, EditIcon, ReplyIcon } from '../common/Icons';
interface Props {
id: number;
@@ -34,43 +36,43 @@ const CommentFooter = ({
toggleEditMode,
}: Props) => (
<div className="commentFooter">
<a className="commentReplyButton commentLink" onClick={handleToggleCommentReply}>
<ActionLink
onClick={handleToggleCommentReply}
icon={replyForm.isOpen ? <CancelIcon /> : <ReplyIcon />}
>
{
replyForm.isOpen ?
I18n.t('common.buttons.cancel')
:
I18n.t('post.comments.reply_button')
}
</a>
</ActionLink>
{
isPowerUser || currentUserEmail === commentAuthorEmail ?
<>
<Separator />
<a onClick={toggleEditMode} className="commentLink">
<ActionLink onClick={toggleEditMode} icon={<EditIcon />}>
{I18n.t('common.buttons.edit')}
</a>
</ActionLink>
<Separator />
<a
<ActionLink
onClick={() => confirm(I18n.t('common.confirmation')) && handleDeleteComment(id)}
className="commentLink">
{I18n.t('common.buttons.delete')}
</a>
icon={<DeleteIcon />}
>
{I18n.t('common.buttons.delete')}
</ActionLink>
</>
:
null
}
<Separator />
<MutedText>{friendlyDate(createdAt)}</MutedText>
{
createdAt !== updatedAt ?
createdAt !== updatedAt &&
<>
<Separator />
<MutedText>{ I18n.t('common.edited').toLowerCase() }</MutedText>
</>
:
null
}
</div>
);

View File

@@ -2,6 +2,7 @@ import * as React from 'react';
import I18n from 'i18n-js';
import { MutedText } from '../common/CustomTexts';
import Switch from '../common/Switch';
interface Props {
postUpdateFlagValue: boolean;
@@ -13,21 +14,15 @@ const NewCommentUpdateSection = ({
handlePostUpdateFlag,
}: Props) => (
<div className="commentIsUpdateForm">
<div>
<input
id="isPostUpdateFlag"
type="checkbox"
onChange={handlePostUpdateFlag}
checked={postUpdateFlagValue || false}
/>
&nbsp;
<label htmlFor="isPostUpdateFlag">{I18n.t('post.new_comment.is_post_update')}</label>
</div>
<Switch
htmlId="isPostUpdateFlag"
onClick={handlePostUpdateFlag}
checked={postUpdateFlagValue || false}
label={I18n.t('post.new_comment.is_post_update')}
/>
{
postUpdateFlagValue ?
postUpdateFlagValue &&
<MutedText>{I18n.t('post.new_comment.user_notification')}</MutedText>
:
null
}
</div>
);

View File

@@ -8,6 +8,8 @@ import IPostStatus from '../../interfaces/IPostStatus';
import IBoard from '../../interfaces/IBoard';
import Button from '../common/Button';
import Spinner from '../common/Spinner';
import ActionLink from '../common/ActionLink';
import { CancelIcon } from '../common/Icons';
interface Props {
title: string;
@@ -93,9 +95,9 @@ const PostEditForm = ({
/>
<div className="postEditFormButtons">
<a onClick={toggleEditMode}>
{ I18n.t('common.buttons.cancel') }
</a>
<ActionLink onClick={toggleEditMode} icon={<CancelIcon />}>
{I18n.t('common.buttons.cancel')}
</ActionLink>
&nbsp;
<Button onClick={() => handleUpdatePost(title, description, boardId, postStatusId)}>
{ isUpdating ? <Spinner /> : I18n.t('common.buttons.update') }

View File

@@ -5,6 +5,8 @@ import I18n from 'i18n-js';
import { MutedText } from '../common/CustomTexts';
import friendlyDate from '../../helpers/datetime';
import Separator from '../common/Separator';
import ActionLink from '../common/ActionLink';
import { DeleteIcon, EditIcon } from '../common/Icons';
interface Props {
createdAt: string;
@@ -27,26 +29,29 @@ const PostFooter = ({
}: Props) => (
<div className="postFooter">
<div className="postAuthor">
<span>{ I18n.t('post.published_by').toLowerCase() } &nbsp;</span>
<span>{I18n.t('post.published_by').toLowerCase()} &nbsp;</span>
<Gravatar email={authorEmail} size={24} className="postAuthorAvatar" /> &nbsp;
{authorFullName}
<Separator />
{friendlyDate(createdAt)}
</div>
{
isPowerUser || authorEmail === currentUserEmail ?
<>
<a onClick={toggleEditMode}>
{ I18n.t('common.buttons.edit') }
</a>
<Separator />
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDeletePost()}>
{ I18n.t('common.buttons.delete') }
</a>
<Separator />
</>
<div className="postFooterActions">
<ActionLink onClick={toggleEditMode} icon={<EditIcon />}>
{I18n.t('common.buttons.edit')}
</ActionLink>
<ActionLink
onClick={() => confirm(I18n.t('common.confirmation')) && handleDeletePost()}
icon={<DeleteIcon />}
>
{I18n.t('common.buttons.delete')}
</ActionLink>
</div>
:
null
}
<MutedText>{friendlyDate(createdAt)}</MutedText>
</div>
);

View File

@@ -9,6 +9,8 @@ import { IOAuth } from '../../../interfaces/IOAuth';
import { AuthenticationPages } from './AuthenticationSiteSettingsP';
import { useState } from 'react';
import Separator from '../../common/Separator';
import ActionLink from '../../common/ActionLink';
import { BackIcon } from '../../common/Icons';
interface Props {
selectedOAuth: IOAuth;
@@ -88,16 +90,18 @@ const OAuthForm = ({
return (
<>
<a
<ActionLink
onClick={() => {
let confirmation = true;
if (isDirty)
confirmation = confirm(I18n.t('common.unsaved_changes') + ' ' + I18n.t('common.confirmation'));
if (confirmation) setPage('index');
}}
className="backButton link">
{ I18n.t('common.buttons.back') }
</a>
icon={<BackIcon />}
customClass="backButton"
>
{I18n.t('common.buttons.back')}
</ActionLink>
<h2>{ I18n.t(`site_settings.authentication.form.title_${page}`) }</h2>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="formRow">

View File

@@ -6,6 +6,8 @@ import Switch from '../../common/Switch';
import Separator from '../../common/Separator';
import { AuthenticationPages } from './AuthenticationSiteSettingsP';
import CopyToClipboardButton from '../../common/CopyToClipboardButton';
import ActionLink from '../../common/ActionLink';
import { DeleteIcon, EditIcon, TestIcon } from '../../common/Icons';
interface Props {
oAuth: IOAuth;
@@ -44,23 +46,32 @@ const OAuthProviderItem = ({
label={I18n.t('site_settings.authentication.copy_url')}
textToCopy={oAuth.callbackUrl}
/>
<Separator />
<a onClick={() =>
window.open(`/o_auths/${oAuth.id}/start?reason=test`, '', 'width=640, height=640')
}>
Test
</a>
<Separator />
<a onClick={() => {
setSelectedOAuth(oAuth.id);
setPage('edit');
}}>
{ I18n.t('common.buttons.edit') }
</a>
<Separator />
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDeleteOAuth(oAuth.id)}>
{ I18n.t('common.buttons.delete') }
</a>
<ActionLink
onClick={() =>
window.open(`/o_auths/${oAuth.id}/start?reason=test`, '', 'width=640, height=640')
}
icon={<TestIcon />}
>
{I18n.t('common.buttons.test')}
</ActionLink>
<ActionLink
onClick={() => {
setSelectedOAuth(oAuth.id);
setPage('edit');
}}
icon={<EditIcon />}
>
{I18n.t('common.buttons.edit')}
</ActionLink>
<ActionLink
onClick={() => confirm(I18n.t('common.confirmation')) && handleDeleteOAuth(oAuth.id)}
icon={<DeleteIcon />}
>
{I18n.t('common.buttons.delete')}
</ActionLink>
</div>
</li>
);

View File

@@ -8,6 +8,8 @@ import DragZone from '../../common/DragZone';
import PostBoardLabel from '../../common/PostBoardLabel';
import Separator from '../../common/Separator';
import BoardForm from './BoardForm';
import ActionLink from '../../common/ActionLink';
import { CancelIcon, DeleteIcon, EditIcon } from '../../common/Icons';
interface Props {
id: number;
@@ -83,13 +85,16 @@ class BoardsEditable extends React.Component<Props, State> {
</div>
<div className="boardEditableActions">
<a onClick={this.toggleEditMode}>{I18n.t('common.buttons.edit')}</a>
<ActionLink onClick={this.toggleEditMode} icon={<EditIcon />}>
{I18n.t('common.buttons.edit')}
</ActionLink>
<Separator />
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDelete(id)}>
<ActionLink
onClick={() => confirm(I18n.t('common.confirmation')) && handleDelete(id)}
icon={<DeleteIcon />}
>
{I18n.t('common.buttons.delete')}
</a>
</ActionLink>
</div>
</>
:
@@ -102,11 +107,12 @@ class BoardsEditable extends React.Component<Props, State> {
handleUpdate={this.handleUpdate}
/>
<a
className="boardFormCancelButton"
onClick={this.toggleEditMode}>
<ActionLink
onClick={this.toggleEditMode}
icon={<CancelIcon />}
>
{I18n.t('common.buttons.cancel')}
</a>
</ActionLink>
</>
}
</li>

View File

@@ -68,6 +68,7 @@ const BoardForm = ({
{...register('name', { required: true })}
placeholder={I18n.t('site_settings.boards.form.name')}
autoFocus={mode === 'update'}
autoComplete={'off'}
className="formControl"
/>

View File

@@ -6,6 +6,8 @@ import PostStatusLabel from "../../common/PostStatusLabel";
import DragZone from '../../common/DragZone';
import Separator from '../../common/Separator';
import PostStatusForm from './PostStatusForm';
import ActionLink from '../../common/ActionLink';
import { CancelIcon, DeleteIcon, EditIcon } from '../../common/Icons';
interface Props {
id: number;
@@ -74,13 +76,16 @@ class PostStatusEditable extends React.Component<Props, State> {
<PostStatusLabel name={name} color={color} />
<div className="postStatusEditableActions">
<a onClick={this.toggleEditMode}>{I18n.t('common.buttons.edit')}</a>
<ActionLink onClick={this.toggleEditMode} icon={<EditIcon />}>
{I18n.t('common.buttons.edit')}
</ActionLink>
<Separator />
<a onClick={() => confirm(I18n.t('common.confirmation')) && handleDelete(id)}>
<ActionLink
onClick={() => confirm(I18n.t('common.confirmation')) && handleDelete(id)}
icon={<DeleteIcon />}
>
{I18n.t('common.buttons.delete')}
</a>
</ActionLink>
</div>
</>
:
@@ -93,11 +98,12 @@ class PostStatusEditable extends React.Component<Props, State> {
handleUpdate={this.handleUpdate}
/>
<a
className="postStatusFormCancelButton"
onClick={this.toggleEditMode}>
<ActionLink
onClick={this.toggleEditMode}
icon={<CancelIcon />}
>
{I18n.t('common.buttons.cancel')}
</a>
</ActionLink>
</>
}
</li>

View File

@@ -72,6 +72,7 @@ const PostStatusForm = ({
{...register('name', { required: true })}
placeholder={I18n.t('site_settings.post_statuses.form.name')}
autoFocus={mode === 'update'}
autoComplete={'off'}
className="formControl"
/>

View File

@@ -6,6 +6,8 @@ import IUser, { UserRoles, USER_ROLE_ADMIN, USER_ROLE_USER, USER_STATUS_ACTIVE,
import Separator from "../../common/Separator";
import UserForm from "./UserForm";
import { MutedText } from "../../common/CustomTexts";
import { BlockIcon, CancelIcon, EditIcon, UnblockIcon } from "../../common/Icons";
import ActionLink from "../../common/ActionLink";
interface Props {
user: IUser;
@@ -119,18 +121,18 @@ class UserEditable extends React.Component<Props, State> {
</div>
<div className="userEditableActions">
<a
<ActionLink
onClick={() => editEnabled && this.toggleEditMode()}
className={editEnabled ? '' : 'actionDisabled'}
icon={<EditIcon />}
disabled={!editEnabled}
>
{ I18n.t('common.buttons.edit') }
</a>
</ActionLink>
<Separator />
<a
<ActionLink
onClick={() => blockEnabled && this._handleUpdateUserStatus()}
className={blockEnabled ? '' : 'actionDisabled'}
icon={user.status !== USER_STATUS_BLOCKED ? <BlockIcon /> : <UnblockIcon />}
disabled={!blockEnabled}
>
{
user.status !== USER_STATUS_BLOCKED ?
@@ -138,15 +140,15 @@ class UserEditable extends React.Component<Props, State> {
:
I18n.t('site_settings.users.unblock')
}
</a>
</ActionLink>
</div>
</>
:
<>
<UserForm user={user} updateUserRole={this._handleUpdateUserRole} />
<a onClick={this.toggleEditMode} className="userEditCancelButton">
{ I18n.t('common.buttons.cancel') }
</a>
<ActionLink onClick={this.toggleEditMode} icon={<CancelIcon />}>
{I18n.t('common.buttons.cancel')}
</ActionLink>
</>
}
</li>

View File

@@ -0,0 +1,26 @@
import * as React from 'react';
interface Props {
onClick: React.MouseEventHandler<HTMLAnchorElement>;
icon?: React.ReactElement;
disabled?: boolean;
customClass?: string;
children: React.ReactNode;
}
const ActionLink = ({
onClick,
icon,
disabled = false,
customClass,
children,
}: Props) => (
<a
onClick={onClick}
className={`actionLink${disabled ? ' actionLinkDisabled' : ''}${customClass ? ' ' + customClass : ''}`}
>
{icon}{children}
</a>
);
export default ActionLink;

View File

@@ -1,6 +1,8 @@
import * as React from 'react';
import I18n from 'i18n-js';
import { useState } from 'react';
import ActionLink from './ActionLink';
import { CopyIcon, DoneIcon } from './Icons';
interface Props {
label: string;
@@ -20,7 +22,7 @@ const CopyToClipboardButton = ({
return (
ready ?
<a
<ActionLink
onClick={() => {
if (navigator.clipboard) {
navigator.clipboard.writeText(textToCopy).then(() => {
@@ -32,11 +34,14 @@ const CopyToClipboardButton = ({
alertError();
}
}}
icon={<CopyIcon />}
>
{label}
</a>
</ActionLink>
:
<span>{copiedLabel}</span>
<span style={{display: 'flex', marginRight: 12}}>
{copiedLabel}
</span>
);
};

View File

@@ -1,11 +1,22 @@
import * as React from 'react';
import { MdDragIndicator } from 'react-icons/md';
const DragZone = ({dndProvided, isDragDisabled, color = 'black'}) => (
interface Props {
dndProvided: any;
isDragDisabled: boolean;
color?: 'black' | 'white';
}
const DragZone = ({
dndProvided,
isDragDisabled,
color = 'black',
}: Props) => (
<span
className={`drag-zone${isDragDisabled ? ' drag-zone-disabled' : ''}`}
{...dndProvided.dragHandleProps}
>
<span className={`drag-icon${color === 'white' ? ' drag-icon-white' : ''}`}></span>
<MdDragIndicator color={color} size={18} />
</span>
);

View File

@@ -0,0 +1,28 @@
import * as React from 'react';
import { BsReply } from 'react-icons/bs';
import { FiEdit, FiDelete } from 'react-icons/fi';
import { ImCancelCircle } from 'react-icons/im';
import { TbLock, TbLockOpen } from 'react-icons/tb';
import { MdContentCopy, MdDone, MdOutlineArrowBack } from 'react-icons/md';
import { GrTest } from 'react-icons/gr';
export const EditIcon = () => <FiEdit />;
export const DeleteIcon = () => <FiDelete />;
export const CancelIcon = () => <ImCancelCircle />;
export const BlockIcon = () => <TbLock />;
export const UnblockIcon = () => <TbLockOpen />;
export const CopyIcon = () => <MdContentCopy />;
export const TestIcon = () => <GrTest />;
export const DoneIcon = () => <MdDone />;
export const BackIcon = () => <MdOutlineArrowBack />;
export const ReplyIcon = () => <BsReply />;