Merge branch 'main' into more_accessibility

This commit is contained in:
Dessalines 2021-02-11 15:43:06 -05:00
commit 58bbb51f8f
33 changed files with 246 additions and 423 deletions

View file

@ -11,6 +11,10 @@
cursor: pointer;
}
.pointer-events {
pointer-events: auto !important;
}
.no-click {
pointer-events:none;
opacity: 0.65;

View file

@ -25,6 +25,7 @@ import autosize from 'autosize';
import { SiteForm } from './site-form';
import { UserListing } from './user-listing';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
@ -109,9 +110,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
/>
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">
@ -185,9 +184,7 @@ export class AdminSettings extends Component<any, AdminSettingsState> {
<div class="col-12">
<button type="submit" class="btn btn-secondary mr-2">
{this.state.siteConfigLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : (
capitalizeFirstLetter(i18n.t('save'))
)}

View file

@ -1,5 +1,6 @@
import { Component } from 'inferno';
import { i18n } from '../i18next';
import { Icon } from './icon';
interface CakeDayProps {
creatorName: string;
@ -12,9 +13,7 @@ export class CakeDay extends Component<CakeDayProps, any> {
className={`mx-2 d-inline-block unselectable pointer`}
data-tippy-content={this.cakeDayTippy()}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-cake"></use>
</svg>
<Icon icon="cake" classes="icon-inline" />
</div>
);
}

View file

@ -20,6 +20,7 @@ import { WebSocketService, UserService } from '../services';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
import { MarkdownTextArea } from './markdown-textarea';
import { Icon } from './icon';
interface CommentFormProps {
postId?: number;
@ -84,9 +85,7 @@ export class CommentForm extends Component<CommentFormProps, CommentFormState> {
/>
) : (
<div class="alert alert-light" role="alert">
<svg class="icon icon-inline mr-2">
<use xlinkHref="#icon-alert-triangle"></use>
</svg>
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
<T i18nKey="must_login" class="d-inline">
#
<Link className="alert-link" to="/login">

View file

@ -36,6 +36,7 @@ import { CommentForm } from './comment-form';
import { CommentNodes } from './comment-nodes';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { Icon, Spinner } from './icon';
import { i18n } from '../i18next';
interface CommentNodeState {
@ -260,13 +261,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.state.readLoading ? (
this.loadingIcon
) : (
<svg
class={`icon icon-inline ${
<Icon
icon="check"
classes={`icon-inline ${
this.commentOrMentionRead && 'text-success'
}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
/>
)}
</button>
)}
@ -280,9 +280,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
data-tippy-content={i18n.t('upvote')}
aria-label={i18n.t('upvote')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-arrow-up1"></use>
</svg>
<Icon icon="arrow-up1" classes="icon-inline" />
{this.state.upvotes !== this.state.score && (
<span class="ml-1">{this.state.upvotes}</span>
)}
@ -298,9 +296,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
data-tippy-content={i18n.t('downvote')}
aria-label={i18n.t('downvote')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-arrow-down1"></use>
</svg>
<Icon icon="arrow-down1" classes="icon-inline" />
{this.state.upvotes !== this.state.score && (
<span class="ml-1">{this.state.downvotes}</span>
)}
@ -312,9 +308,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
data-tippy-content={i18n.t('reply')}
aria-label={i18n.t('reply')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-reply1"></use>
</svg>
<Icon icon="reply1" classes="icon-inline" />
</button>
{!this.state.showAdvanced ? (
<button
@ -323,9 +317,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
data-tippy-content={i18n.t('more')}
aria-label={i18n.t('more')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-more-vertical"></use>
</svg>
<Icon icon="more-vertical" classes="icon-inline" />
</button>
) : (
<>
@ -336,9 +328,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
to={`/create_private_message/recipient/${cv.creator.id}`}
title={i18n.t('message').toLowerCase()}
>
<svg class="icon">
<use xlinkHref="#icon-mail"></use>
</svg>
<Icon icon="mail" />
</Link>
</button>
)}
@ -359,13 +349,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
{this.state.saveLoading ? (
this.loadingIcon
) : (
<svg
class={`icon icon-inline ${
<Icon
icon="star"
classes={`icon-inline ${
cv.saved && 'text-warning'
}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
/>
)}
</button>
<button
@ -374,13 +363,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
data-tippy-content={i18n.t('view_source')}
aria-label={i18n.t('view_source')}
>
<svg
class={`icon icon-inline ${
<Icon
icon="file-text"
classes={`icon-inline ${
this.state.viewSource && 'text-success'
}`}
>
<use xlinkHref="#icon-file-text"></use>
</svg>
/>
</button>
{this.myComment && (
<>
@ -390,9 +378,7 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
data-tippy-content={i18n.t('edit')}
aria-label={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
<Icon icon="edit" classes="icon-inline" />
</button>
<button
class="btn btn-link btn-animate text-muted"
@ -411,13 +397,12 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
: i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="trash"
classes={`icon-inline ${
cv.comment.deleted && 'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
/>
</button>
</>
)}
@ -817,19 +802,13 @@ export class CommentNode extends Component<CommentNodeProps, CommentNodeState> {
to={`/post/${cv.post.id}/comment/${cv.comment.id}`}
title={this.props.showContext ? i18n.t('show_context') : i18n.t('link')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-link"></use>
</svg>
<Icon icon="link" classes="icon-inline" />
</Link>
);
}
get loadingIcon() {
return (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
);
return <Spinner />;
}
get myComment(): boolean {

View file

@ -26,6 +26,7 @@ import {
setOptionalAuth,
} from '../utils';
import { CommunityLink } from './community-link';
import { Spinner } from './icon';
import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
@ -104,10 +105,8 @@ export class Communities extends Component<any, CommunitiesState> {
path={this.context.router.route.match.url}
/>
{this.state.loading ? (
<h5 class="">
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<h5>
<Spinner />
</h5>
) : (
<div>

View file

@ -24,6 +24,7 @@ import { i18n } from '../i18next';
import { MarkdownTextArea } from './markdown-textarea';
import { ImageUploadForm } from './image-upload-form';
import { Icon, Spinner } from './icon';
interface CommunityFormProps {
community_view?: CommunityView; // If a community is given, that means this is an edit
@ -132,9 +133,7 @@ export class CommunityForm extends Component<
class="pointer unselectable ml-2 text-muted"
data-tippy-content={i18n.t('name_explain')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-help-circle"></use>
</svg>
<Icon icon="help-circle" classes="icon-inline" />
</span>
</label>
<div class="col-12">
@ -160,9 +159,7 @@ export class CommunityForm extends Component<
class="pointer unselectable ml-2 text-muted"
data-tippy-content={i18n.t('display_name_explain')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-help-circle"></use>
</svg>
<Icon icon="help-circle" classes="icon-inline" />
</span>
</label>
<div class="col-12">
@ -252,9 +249,7 @@ export class CommunityForm extends Component<
disabled={this.state.loading}
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : this.props.community_view ? (
capitalizeFirstLetter(i18n.t('save'))
) : (

View file

@ -31,6 +31,7 @@ import { DataTypeSelect } from './data-type-select';
import { Sidebar } from './sidebar';
import { CommunityLink } from './community-link';
import { BannerIconHeader } from './banner-icon-header';
import { Icon, Spinner } from './icon';
import {
wsJsonToRes,
fetchLimit,
@ -244,9 +245,7 @@ export class Community extends Component<any, State> {
<div class="container">
{this.state.communityLoading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">
@ -283,9 +282,7 @@ export class Community extends Component<any, State> {
return this.state.dataType == DataType.Post ? (
this.state.postsLoading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<PostListings
@ -297,9 +294,7 @@ export class Community extends Component<any, State> {
)
) : this.state.commentsLoading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<CommentNodes
@ -350,9 +345,7 @@ export class Community extends Component<any, State> {
title="RSS"
rel="noopener"
>
<svg class="icon text-muted small">
<use xlinkHref="#icon-rss"></use>
</svg>
<Icon icon="rss" classes="text-muted small" />
</a>
</div>
);

View file

@ -2,6 +2,7 @@ import { Component } from 'inferno';
import { Subscription } from 'rxjs';
import { CommunityForm } from './community-form';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
import {
CommunityView,
UserOperation,
@ -77,9 +78,7 @@ export class CreateCommunity extends Component<any, CreateCommunityState> {
/>
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">

View file

@ -2,6 +2,7 @@ import { Component } from 'inferno';
import { Subscription } from 'rxjs';
import { PostForm } from './post-form';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
import {
authField,
isBrowser,
@ -95,9 +96,7 @@ export class CreatePost extends Component<any, CreatePostState> {
/>
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">

View file

@ -2,6 +2,7 @@ import { Component } from 'inferno';
import { Subscription } from 'rxjs';
import { PrivateMessageForm } from './private-message-form';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
import { UserService, WebSocketService } from '../services';
import {
SiteView,
@ -112,9 +113,7 @@ export class CreatePrivateMessage extends Component<
/>
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">

View file

@ -0,0 +1,31 @@
import { Component } from 'inferno';
interface IconProps {
icon: string;
classes?: string;
}
export class Icon extends Component<IconProps, any> {
constructor(props: any, context: any) {
super(props, context);
}
render() {
return (
<svg class={`icon ${this.props.classes}`}>
<title>{this.props.icon}</title>
<use xlinkHref={`#icon-${this.props.icon}`}></use>
</svg>
);
}
}
export class Spinner extends Component<any, any> {
constructor(props: any, context: any) {
super(props, context);
}
render() {
return <Icon icon="spinner" classes="icon-spinner spin" />;
}
}

View file

@ -2,6 +2,7 @@ import { Component, linkEvent } from 'inferno';
import { Post } from 'lemmy-js-client';
import { mdToHtml } from '../utils';
import { i18n } from '../i18next';
import { Icon } from './icon';
interface FramelyCardProps {
post: Post;
@ -52,9 +53,7 @@ export class IFramelyCard extends Component<
rel="noopener"
>
{new URL(post.url).hostname}
<svg class="ml-1 icon">
<use xlinkHref="#icon-external-link"></use>
</svg>
<Icon icon="external-link" classes="ml-1" />
</a>
</span>,
]}

View file

@ -3,6 +3,7 @@ import { pictrsUri } from '../env';
import { UserService } from '../services';
import { toast, randomStr } from '../utils';
import { i18n } from '../i18next';
import { Icon } from './icon';
interface ImageUploadFormProps {
uploadTitle: string;
@ -53,9 +54,7 @@ export class ImageUploadForm extends Component<
onClick={linkEvent(this, this.handleRemoveImage)}
aria-label={i18n.t('remove')}
>
<svg class="icon mini-overlay">
<use xlinkHref="#icon-x"></use>
</svg>
<Icon icon="x" classes="mini-overlay" />
</a>
</span>
)}

View file

@ -38,6 +38,7 @@ import { CommentNodes } from './comment-nodes';
import { PrivateMessage } from './private-message';
import { HtmlTags } from './html-tags';
import { SortSelect } from './sort-select';
import { Icon, Spinner } from './icon';
import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
@ -137,9 +138,7 @@ export class Inbox extends Component<any, InboxState> {
<div class="container">
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">
@ -157,9 +156,7 @@ export class Inbox extends Component<any, InboxState> {
title="RSS"
rel="noopener"
>
<svg class="icon ml-2 text-muted small">
<use xlinkHref="#icon-rss"></use>
</svg>
<Icon icon="rss" classes="ml-2 text-muted small" />
</a>
</small>
</h5>

View file

@ -24,6 +24,7 @@ import {
} from '../utils';
import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
import { Icon, Spinner } from './icon';
interface State {
loginForm: LoginForm;
@ -134,27 +135,21 @@ export class Login extends Component<any, State> {
class="form-control"
required
/>
{validEmail(this.state.loginForm.username_or_email) && (
<button
type="button"
onClick={linkEvent(this, this.handlePasswordReset)}
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold"
>
{i18n.t('forgot_password')}
</button>
)}
<button
type="button"
onClick={linkEvent(this, this.handlePasswordReset)}
className="btn p-0 btn-link d-inline-block float-right text-muted small font-weight-bold pointer-events"
disabled={!validEmail(this.state.loginForm.username_or_email)}
title={i18n.t('no_password_reset')}
>
{i18n.t('forgot_password')}
</button>
</div>
</div>
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">
{this.state.loginLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
) : (
i18n.t('login')
)}
{this.state.loginLoading ? <Spinner /> : i18n.t('login')}
</button>
</div>
</div>
@ -204,9 +199,7 @@ export class Login extends Component<any, State> {
/>
{!validEmail(this.state.registerForm.email) && (
<div class="mt-2 mb-0 alert alert-light" role="alert">
<svg class="icon icon-inline mr-2">
<use xlinkHref="#icon-alert-triangle"></use>
</svg>
<Icon icon="alert-triangle" classes="icon-inline mr-2" />
{i18n.t('no_password_reset')}
</div>
)}
@ -262,9 +255,7 @@ export class Login extends Component<any, State> {
onClick={linkEvent(this, this.handleRegenCaptcha)}
aria-label={i18n.t('captcha')}
>
<svg class="icon icon-refresh-cw">
<use xlinkHref="#icon-refresh-cw"></use>
</svg>
<Icon icon="refresh-cw" classes="icon-refresh-cw" />
</button>
</label>
{this.showCaptcha()}
@ -304,13 +295,7 @@ export class Login extends Component<any, State> {
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">
{this.state.registerLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
) : (
i18n.t('sign_up')
)}
{this.state.registerLoading ? <Spinner /> : i18n.t('sign_up')}
</button>
</div>
</div>
@ -338,9 +323,7 @@ export class Login extends Component<any, State> {
type="button"
disabled={this.state.captchaPlaying}
>
<svg class="icon icon-play">
<use xlinkHref="#icon-play"></use>
</svg>
<Icon icon="play" classes="icon-play" />
</button>
)}
</>

View file

@ -34,6 +34,7 @@ import { SiteForm } from './site-form';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { BannerIconHeader } from './banner-icon-header';
import { Icon, Spinner } from './icon';
import {
wsJsonToRes,
mdToHtml,
@ -513,9 +514,7 @@ export class Main extends Component<any, MainState> {
aria-label={i18n.t('edit')}
data-tippy-content={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
<Icon icon="edit" classes="icon-inline" />
</span>
</li>
</ul>
@ -539,9 +538,7 @@ export class Main extends Component<any, MainState> {
<div class="main-content-wrapper">
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div>
@ -601,9 +598,7 @@ export class Main extends Component<any, MainState> {
rel="noopener"
title="RSS"
>
<svg class="icon text-muted small">
<use xlinkHref="#icon-rss"></use>
</svg>
<Icon icon="rss" classes="text-muted small" />
</a>
)}
{this.state.listingType == ListingType.Local && (
@ -613,9 +608,7 @@ export class Main extends Component<any, MainState> {
rel="noopener"
title="RSS"
>
<svg class="icon text-muted small">
<use xlinkHref="#icon-rss">#</use>
</svg>
<Icon icon="rss" classes="text-muted small" />
</a>
)}
{UserService.Instance.user &&
@ -626,9 +619,7 @@ export class Main extends Component<any, MainState> {
title="RSS"
rel="noopener"
>
<svg class="icon text-muted small">
<use xlinkHref="#icon-rss">#</use>
</svg>
<Icon icon="rss" classes="text-muted small" />
</a>
)}
</div>

View file

@ -14,6 +14,7 @@ import { UserService } from '../services';
import autosize from 'autosize';
import { i18n } from '../i18next';
import { pictrsUri } from '../env';
import { Icon, Spinner } from './icon';
interface MarkdownTextAreaProps {
initialContent: string;
@ -151,9 +152,7 @@ export class MarkdownTextArea extends Component<
disabled={this.props.disabled || this.state.loading}
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : (
<span>{this.props.buttonTitle}</span>
)}
@ -186,9 +185,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('bold')}
onClick={linkEvent(this, this.handleInsertBold)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-bold"></use>
</svg>
<Icon icon="bold" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -196,9 +193,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('italic')}
onClick={linkEvent(this, this.handleInsertItalic)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-italic"></use>
</svg>
<Icon icon="italic" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -206,9 +201,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('link')}
onClick={linkEvent(this, this.handleInsertLink)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-link"></use>
</svg>
<Icon icon="link" classes="icon-inline" />
</button>
<form class="btn btn-sm text-muted font-weight-bold">
<label
@ -217,13 +210,9 @@ export class MarkdownTextArea extends Component<
data-tippy-content={i18n.t('upload_image')}
>
{this.state.imageLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : (
<svg class="icon icon-inline">
<use xlinkHref="#icon-image"></use>
</svg>
<Icon icon="image" classes="icon-inline" />
)}
</label>
<input
@ -242,9 +231,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('header')}
onClick={linkEvent(this, this.handleInsertHeader)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-header"></use>
</svg>
<Icon icon="header" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -252,9 +239,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('strikethrough')}
onClick={linkEvent(this, this.handleInsertStrikethrough)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-strikethrough"></use>
</svg>
<Icon icon="strikethrough" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -262,9 +247,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('quote')}
onClick={linkEvent(this, this.handleInsertQuote)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-format_quote"></use>
</svg>
<Icon icon="format_quote" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -272,9 +255,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('list')}
onClick={linkEvent(this, this.handleInsertList)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-list"></use>
</svg>
<Icon icon="list" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -282,9 +263,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('code')}
onClick={linkEvent(this, this.handleInsertCode)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-code"></use>
</svg>
<Icon icon="code" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -292,9 +271,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('subscript')}
onClick={linkEvent(this, this.handleInsertSubscript)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-subscript"></use>
</svg>
<Icon icon="subscript" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -302,9 +279,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('superscript')}
onClick={linkEvent(this, this.handleInsertSuperscript)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-superscript"></use>
</svg>
<Icon icon="superscript" classes="icon-inline" />
</button>
<button
class="btn btn-sm text-muted"
@ -312,9 +287,7 @@ export class MarkdownTextArea extends Component<
aria-label={i18n.t('spoiler')}
onClick={linkEvent(this, this.handleInsertSpoiler)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-alert-triangle"></use>
</svg>
<Icon icon="alert-triangle" classes="icon-inline" />
</button>
<a
href={markdownHelpUrl}
@ -323,9 +296,7 @@ export class MarkdownTextArea extends Component<
title={i18n.t('formatting_help')}
rel="noopener"
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-help-circle"></use>
</svg>
<Icon icon="help-circle" classes="icon-inline" />
</a>
</div>
</div>

View file

@ -34,6 +34,7 @@ import { i18n } from '../i18next';
import { InitialFetchRequest } from 'shared/interfaces';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { Spinner } from './icon';
enum ModlogEnum {
ModRemovePost,
@ -364,10 +365,8 @@ export class Modlog extends Component<any, ModlogState> {
path={this.context.router.route.match.url}
/>
{this.state.loading ? (
<h5 class="">
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<h5>
<Spinner />
</h5>
) : (
<div>

View file

@ -2,6 +2,7 @@ import { Component } from 'inferno';
import moment from 'moment';
import { getMomentLanguage, capitalizeFirstLetter } from '../utils';
import { i18n } from '../i18next';
import { Icon } from './icon';
interface MomentTimeProps {
data: {
@ -31,9 +32,7 @@ export class MomentTime extends Component<MomentTimeProps, any> {
)} ${this.format(this.props.data.updated)}`}
className="font-italics pointer unselectable"
>
<svg class="icon icon-inline mr-1">
<use xlinkHref="#icon-edit-2"></use>
</svg>
<Icon icon="edit-2" classes="icon-inline mr-1" />
{moment.utc(this.props.data.updated).fromNow(!this.props.showAgo)}
</span>
);

View file

@ -35,6 +35,7 @@ import {
} from '../utils';
import { i18n } from '../i18next';
import { PictrsImage } from './pictrs-image';
import { Icon } from './icon';
interface NavbarProps {
site_res: GetSiteResponse;
@ -198,9 +199,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to="/inbox"
title={i18n.t('inbox')}
>
<svg class="icon">
<use xlinkHref="#icon-bell"></use>
</svg>
<Icon icon="bell" />
{this.state.unreadCount > 0 && (
<span
class="mx-1 badge badge-light"
@ -220,9 +219,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
onClick={linkEvent(this, this.expandNavbar)}
data-tippy-content={i18n.t('expand_here')}
>
<svg class="icon">
<use xlinkHref="#icon-menu"></use>
</svg>
<Icon icon="menu" />
</button>
<div
className={`${!this.state.expanded && 'collapse'} navbar-collapse`}
@ -264,9 +261,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
title={i18n.t('support_lemmy')}
href={supportLemmyUrl}
>
<svg class="icon small">
<use xlinkHref="#icon-beer"></use>
</svg>
<Icon icon="beer" classes="small" />
</a>
</li>
</ul>
@ -278,9 +273,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to={`/admin`}
title={i18n.t('admin_settings')}
>
<svg class="icon">
<use xlinkHref="#icon-settings"></use>
</svg>
<Icon icon="settings" />
</Link>
</li>
)}
@ -314,9 +307,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
style="color: var(--gray)"
aria-label={i18n.t('search')}
>
<svg class="icon">
<use xlinkHref="#icon-search"></use>
</svg>
<Icon icon="search" />
</button>
</form>
)}
@ -329,9 +320,7 @@ export class Navbar extends Component<NavbarProps, NavbarState> {
to="/inbox"
title={i18n.t('inbox')}
>
<svg class="icon">
<use xlinkHref="#icon-bell"></use>
</svg>
<Icon icon="bell" />
{this.state.unreadCount > 0 && (
<span
class="ml-1 badge badge-light"

View file

@ -19,6 +19,7 @@ import {
} from '../utils';
import { i18n } from '../i18next';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
interface State {
passwordChangeForm: PasswordChangeForm;
@ -113,9 +114,7 @@ export class PasswordChange extends Component<any, State> {
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : (
capitalizeFirstLetter(i18n.t('save'))
)}

View file

@ -2,6 +2,7 @@ import { Component, linkEvent } from 'inferno';
import { Prompt } from 'inferno-router';
import { PostListings } from './post-listings';
import { MarkdownTextArea } from './markdown-textarea';
import { Icon, Spinner } from './icon';
import { Subscription } from 'rxjs';
import {
CreatePost,
@ -194,9 +195,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
} d-inline-block float-right text-muted font-weight-bold`}
data-tippy-content={i18n.t('upload_image')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-image"></use>
</svg>
<Icon icon="image" classes="icon-inline" />
</label>
<input
id="file-upload"
@ -220,11 +219,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
{i18n.t('archive_link')}
</a>
)}
{this.state.imageLoading && (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
)}
{this.state.imageLoading && <Spinner />}
{isImage(this.state.postForm.url) && (
<img src={this.state.postForm.url} class="img-fluid" alt="" />
)}
@ -343,9 +338,7 @@ export class PostForm extends Component<PostFormProps, PostFormState> {
class="btn btn-secondary mr-2"
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : this.props.post_view ? (
capitalizeFirstLetter(i18n.t('save'))
) : (

View file

@ -25,6 +25,7 @@ import { IFramelyCard } from './iframely-card';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { PictrsImage } from './pictrs-image';
import { Icon } from './icon';
import {
md,
mdToHtml,
@ -205,9 +206,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
aria-label={i18n.t('expand_here')}
>
{this.imgThumb(this.getImageSrc())}
<svg class="icon mini-overlay">
<use xlinkHref="#icon-image"></use>
</svg>
<Icon icon="image" classes="mini-overlay" />
</div>
);
} else if (post.thumbnail_url) {
@ -220,9 +219,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
title={post.url}
>
{this.imgThumb(this.getImageSrc())}
<svg class="icon mini-overlay">
<use xlinkHref="#icon-external-link"></use>
</svg>
<Icon icon="external-link" classes="mini-overlay" />
</a>
);
} else if (post.url) {
@ -250,9 +247,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
rel="noopener"
>
<div class="thumbnail rounded bg-light d-flex justify-content-center">
<svg class="icon d-flex align-items-center">
<use xlinkHref="#icon-external-link"></use>
</svg>
<Icon icon="external-link" classes="d-flex align-items-center" />
</div>
</a>
);
@ -265,9 +260,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
title={i18n.t('comments')}
>
<div class="thumbnail rounded bg-light d-flex justify-content-center">
<svg class="icon d-flex align-items-center">
<use xlinkHref="#icon-message-square"></use>
</svg>
<Icon icon="message-square" classes="d-flex align-items-center" />
</div>
</Link>
);
@ -334,9 +327,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
aria-label={i18n.t('upvote')}
to={`/post/${post_view.post.id}`}
>
<svg class="mr-1 icon icon-inline">
<use xlinkHref="#icon-book-open"></use>
</svg>
<Icon icon="book-open" classes="icon-inline mr-1" />
</Link>
</li>
</>
@ -356,9 +347,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={i18n.t('upvote')}
aria-label={i18n.t('upvote')}
>
<svg class="icon upvote">
<use xlinkHref="#icon-arrow-up1"></use>
</svg>
<Icon icon="arrow-up1" classes="upvote" />
</button>
<div
class={`unselectable pointer font-weight-bold text-muted px-1`}
@ -375,9 +364,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={i18n.t('downvote')}
aria-label={i18n.t('downvote')}
>
<svg class="icon downvote">
<use xlinkHref="#icon-arrow-down1"></use>
</svg>
<Icon icon="arrow-down1" classes="downvote" />
</button>
)}
</div>
@ -415,9 +402,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={i18n.t('expand_here')}
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use>
</svg>
<Icon icon="plus-square" classes="icon-inline" />
</span>
) : (
<span>
@ -425,9 +410,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="text-monospace unselectable pointer ml-2 text-muted small"
onClick={linkEvent(this, this.handleImageExpandClick)}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-minus-square"></use>
</svg>
<Icon icon="minus-square" classes="icon-inline" />
</span>
<div>
<span
@ -449,9 +432,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('deleted')}
>
<svg class={`icon icon-inline text-danger`}>
<use xlinkHref="#icon-trash"></use>
</svg>
<Icon icon="trash" classes="icon-inline text-danger" />
</small>
)}
{post.locked && (
@ -459,9 +440,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('locked')}
>
<svg class={`icon icon-inline text-danger`}>
<use xlinkHref="#icon-lock"></use>
</svg>
<Icon icon="lock" classes="icon-inline text-danger" />
</small>
)}
{post.stickied && (
@ -469,9 +448,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className="unselectable pointer ml-2 text-muted font-italic"
data-tippy-content={i18n.t('stickied')}
>
<svg class={`icon icon-inline text-primary`}>
<use xlinkHref="#icon-pin"></use>
</svg>
<Icon icon="pin" classes="icon-inline text-primary" />
</small>
)}
{post.nsfw && (
@ -496,9 +473,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
})}
to={`/post/${post_view.post.id}`}
>
<svg class="mr-1 icon icon-inline">
<use xlinkHref="#icon-message-square"></use>
</svg>
<Icon icon="message-square" classes="icon-inline mr-1" />
{i18n.t('number_of_comments', {
count: post_view.counts.comments,
})}
@ -513,9 +488,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
aria-label={i18n.t('downvote')}
>
<small>
<svg class="icon icon-inline mr-1">
<use xlinkHref="#icon-arrow-down1"></use>
</svg>
<Icon icon="arrow-down1" classes="icon-inline mr-1" />
<span>{this.state.downvotes}</span>
</small>
</button>
@ -530,13 +503,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
aria-label={post_view.saved ? i18n.t('unsave') : i18n.t('save')}
>
<small>
<svg
class={`icon icon-inline ${
post_view.saved && 'text-warning'
}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
<Icon
icon="star"
classes={`icon-inline ${post_view.saved && 'text-warning'}`}
/>
</small>
</button>
)}
@ -555,9 +525,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
onClick={linkEvent(this, this.handlePostLike)}
aria-label={i18n.t('upvote')}
>
<svg class="small icon icon-inline mr-2">
<use xlinkHref="#icon-arrow-up1"></use>
</svg>
<Icon icon="arrow-up1" classes="icon-inline small mr-2" />
{this.state.upvotes}
</button>
{this.props.enableDownvotes && (
@ -569,9 +537,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={this.pointsTippy}
aria-label={i18n.t('downvote')}
>
<svg class="small icon icon-inline mr-2">
<use xlinkHref="#icon-arrow-down1"></use>
</svg>
<Icon icon="arrow-down1" classes="icon-inline small mr-2" />
{this.state.downvotes !== 0 && (
<span>{this.state.downvotes}</span>
)}
@ -586,11 +552,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
post_view.saved ? i18n.t('unsave') : i18n.t('save')
}
>
<svg
class={`icon icon-inline ${post_view.saved && 'text-warning'}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
<Icon
icon="star"
classes={`icon-inline ${post_view.saved && 'text-warning'}`}
/>
</button>
{!this.state.showMoreMobile && this.props.showBody && (
@ -600,9 +565,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
aria-label={i18n.t('more')}
data-tippy-content={i18n.t('more')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-more-vertical"></use>
</svg>
<Icon icon="more-vertical" classes="icon-inline" />
</button>
)}
{this.state.showMoreMobile && this.postActions(mobile)}
@ -655,13 +618,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
post_view.saved ? i18n.t('unsave') : i18n.t('save')
}
>
<svg
class={`icon icon-inline ${
post_view.saved && 'text-warning'
}`}
>
<use xlinkHref="#icon-star"></use>
</svg>
<Icon
icon="star"
classes={`icon-inline ${post_view.saved && 'text-warning'}`}
/>
</button>
)}
<Link
@ -669,9 +629,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
to={`/create_post${this.crossPostParams}`}
title={i18n.t('cross_post')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-copy"></use>
</svg>
<Icon icon="copy" classes="icon-inline" />
</Link>
</>
)}
@ -683,9 +641,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={i18n.t('edit')}
aria-label={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
<Icon icon="edit" classes="icon-inline" />
</button>
<button
class="btn btn-link btn-animate text-muted py-0"
@ -697,13 +653,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
!post_view.post.deleted ? i18n.t('delete') : i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="trash"
classes={`icon-inline ${
post_view.post.deleted && 'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
/>
</button>
</>
)}
@ -715,9 +670,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={i18n.t('more')}
aria-label={i18n.t('more')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-more-vertical"></use>
</svg>
<Icon icon="more-vertical" classes="icon-inline" />
</button>
) : (
<>
@ -728,13 +681,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
data-tippy-content={i18n.t('view_source')}
aria-label={i18n.t('view_source')}
>
<svg
class={`icon icon-inline ${
<Icon
icon="file-text"
classes={`icon-inline ${
this.state.viewSource && 'text-success'
}`}
>
<use xlinkHref="#icon-file-text"></use>
</svg>
/>
</button>
)}
{this.canModOnSelf && (
@ -749,13 +701,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
post_view.post.locked ? i18n.t('unlock') : i18n.t('lock')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="lock"
classes={`icon-inline ${
post_view.post.locked && 'text-danger'
}`}
>
<use xlinkHref="#icon-lock"></use>
</svg>
/>
</button>
<button
class="btn btn-link btn-animate text-muted py-0"
@ -771,13 +722,12 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
: i18n.t('sticky')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="pin"
classes={`icon-inline ${
post_view.post.stickied && 'text-success'
}`}
>
<use xlinkHref="#icon-pin"></use>
</svg>
/>
</button>
</>
)}

View file

@ -1,5 +1,6 @@
import { Component, linkEvent } from 'inferno';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
import { Subscription } from 'rxjs';
import {
UserOperation,
@ -256,9 +257,7 @@ export class Post extends Component<any, PostState> {
<div class="container">
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">

View file

@ -23,6 +23,7 @@ import {
} from '../utils';
import { UserListing } from './user-listing';
import { MarkdownTextArea } from './markdown-textarea';
import { Icon, Spinner } from './icon';
import { i18n } from '../i18next';
import { T } from 'inferno-i18next';
@ -121,9 +122,7 @@ export class PrivateMessageForm extends Component<
data-tippy-content={i18n.t('disclaimer')}
aria-label={i18n.t('disclaimer')}
>
<svg class={`icon icon-inline`}>
<use xlinkHref="#icon-alert-triangle"></use>
</svg>
<Icon icon="alert-triangle" classes="icon-inline" />
</span>
</label>
<div class="col-sm-10">
@ -161,9 +160,7 @@ export class PrivateMessageForm extends Component<
disabled={this.state.loading}
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : this.props.privateMessage ? (
capitalizeFirstLetter(i18n.t('save'))
) : (

View file

@ -10,6 +10,7 @@ import { authField, mdToHtml, toast, wsClient } from '../utils';
import { MomentTime } from './moment-time';
import { PrivateMessageForm } from './private-message-form';
import { UserListing } from './user-listing';
import { Icon } from './icon';
import { i18n } from '../i18next';
interface PrivateMessageState {
@ -82,13 +83,9 @@ export class PrivateMessage extends Component<
onClick={linkEvent(this, this.handleMessageCollapse)}
>
{this.state.collapsed ? (
<svg class="icon icon-inline">
<use xlinkHref="#icon-plus-square"></use>
</svg>
<Icon icon="plus-square" classes="icon-inline" />
) : (
<svg class="icon icon-inline">
<use xlinkHref="#icon-minus-square"></use>
</svg>
<Icon icon="minus-square" classes="icon-inline" />
)}
</div>
</li>
@ -130,13 +127,12 @@ export class PrivateMessage extends Component<
: i18n.t('mark_as_read')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="check"
classes={`icon-inline ${
message_view.private_message.read && 'text-success'
}`}
>
<use xlinkHref="#icon-check"></use>
</svg>
/>
</button>
</li>
<li className="list-inline-item">
@ -146,9 +142,7 @@ export class PrivateMessage extends Component<
data-tippy-content={i18n.t('reply')}
aria-label={i18n.t('reply')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-reply1"></use>
</svg>
<Icon icon="reply1" classes="icon-inline" />
</button>
</li>
</>
@ -162,9 +156,7 @@ export class PrivateMessage extends Component<
data-tippy-content={i18n.t('edit')}
aria-label={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
<Icon icon="edit" classes="icon-inline" />
</button>
</li>
<li className="list-inline-item">
@ -182,14 +174,13 @@ export class PrivateMessage extends Component<
: i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="trash"
classes={`icon-inline ${
message_view.private_message.deleted &&
'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
/>
</button>
</li>
</>
@ -201,13 +192,12 @@ export class PrivateMessage extends Component<
data-tippy-content={i18n.t('view_source')}
aria-label={i18n.t('view_source')}
>
<svg
class={`icon icon-inline ${
<Icon
icon="file-text"
classes={`icon-inline ${
this.state.viewSource && 'text-success'
}`}
>
<use xlinkHref="#icon-file-text"></use>
</svg>
/>
</button>
</li>
</ul>

View file

@ -35,6 +35,7 @@ import {
} from '../utils';
import { PostListing } from './post-listing';
import { HtmlTags } from './html-tags';
import { Spinner } from './icon';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { SortSelect } from './sort-select';
@ -214,18 +215,8 @@ export class Search extends Component<any, SearchState> {
required
minLength={3}
/>
<button
type="submit"
class="btn btn-secondary mr-2 mb-2"
aria-label={i18n.t('search')}
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
) : (
<span>{i18n.t('search')}</span>
)}
<button type="submit" class="btn btn-secondary mr-2 mb-2">
{this.state.loading ? <Spinner /> : <span>{i18n.t('search')}</span>}
</button>
</form>
);

View file

@ -6,6 +6,7 @@ import { Register, LoginResponse, UserOperation } from 'lemmy-js-client';
import { WebSocketService, UserService } from '../services';
import { wsUserOp, wsJsonToRes, toast, wsClient } from '../utils';
import { SiteForm } from './site-form';
import { Spinner } from './icon';
import { i18n } from '../i18next';
interface State {
@ -143,13 +144,7 @@ export class Setup extends Component<any, State> {
<div class="form-group row">
<div class="col-sm-10">
<button type="submit" class="btn btn-secondary">
{this.state.userLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
) : (
i18n.t('sign_up')
)}
{this.state.userLoading ? <Spinner /> : i18n.t('sign_up')}
</button>
</div>
</div>

View file

@ -16,6 +16,7 @@ import { CommunityForm } from './community-form';
import { UserListing } from './user-listing';
import { CommunityLink } from './community-link';
import { BannerIconHeader } from './banner-icon-header';
import { Icon } from './icon';
import { i18n } from '../i18next';
interface SidebarProps {
@ -108,9 +109,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
href="#"
onClick={linkEvent(community.id, this.handleUnsubscribe)}
>
<svg class="text-success mr-1 icon icon-inline">
<use xlinkHref="#icon-check"></use>
</svg>
<Icon icon="check" classes="icon-inline text-success mr-1" />
{i18n.t('joined')}
</a>
)}
@ -305,9 +304,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
data-tippy-content={i18n.t('edit')}
aria-label={i18n.t('edit')}
>
<svg class="icon icon-inline">
<use xlinkHref="#icon-edit"></use>
</svg>
<Icon icon="edit" classes="icon-inline" />
</span>
</li>
{!this.amCreator &&
@ -368,13 +365,12 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
: i18n.t('restore')
}
>
<svg
class={`icon icon-inline ${
<Icon
icon="trash"
classes={`icon-inline ${
community_view.community.deleted && 'text-danger'
}`}
>
<use xlinkHref="#icon-trash"></use>
</svg>
/>
</span>
</li>
)}

View file

@ -1,6 +1,7 @@
import { Component, linkEvent } from 'inferno';
import { Prompt } from 'inferno-router';
import { MarkdownTextArea } from './markdown-textarea';
import { Spinner } from './icon';
import { ImageUploadForm } from './image-upload-form';
import { Site, EditSite } from 'lemmy-js-client';
import { WebSocketService } from '../services';
@ -220,9 +221,7 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
disabled={this.state.loading}
>
{this.state.loading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : this.props.site ? (
capitalizeFirstLetter(i18n.t('save'))
) : (

View file

@ -1,6 +1,7 @@
import { Component, linkEvent } from 'inferno';
import { SortType } from 'lemmy-js-client';
import { sortingHelpUrl, randomStr } from '../utils';
import { Icon } from './icon';
import { i18n } from '../i18next';
interface SortSelectProps {
@ -42,7 +43,9 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
class="custom-select w-auto mr-2 mb-2"
aria-label={i18n.t('sort_type')}
>
<option disabled aria-hidden="true">{i18n.t('sort_type')}</option>
<option disabled aria-hidden="true">
{i18n.t('sort_type')}
</option>
{!this.props.hideHot && [
<option value={SortType.Hot}>{i18n.t('hot')}</option>,
<option value={SortType.Active}>{i18n.t('active')}</option>,
@ -53,7 +56,9 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
{i18n.t('most_comments')}
</option>
)}
<option disabled aria-hidden="true"></option>
<option disabled aria-hidden="true">
</option>
<option value={SortType.TopDay}>{i18n.t('top_day')}</option>
<option value={SortType.TopWeek}>{i18n.t('top_week')}</option>
<option value={SortType.TopMonth}>{i18n.t('top_month')}</option>
@ -67,9 +72,7 @@ export class SortSelect extends Component<SortSelectProps, SortSelectState> {
rel="noopener"
title={i18n.t('sorting_help')}
>
<svg class={`icon icon-inline`}>
<use xlinkHref="#icon-help-circle"></use>
</svg>
<Icon icon="help-circle" classes="icon-inline" />
</a>
</>
);

View file

@ -57,6 +57,7 @@ import { i18n } from '../i18next';
import moment from 'moment';
import { UserDetails } from './user-details';
import { MarkdownTextArea } from './markdown-textarea';
import { Icon, Spinner } from './icon';
import { ImageUploadForm } from './image-upload-form';
import { BannerIconHeader } from './banner-icon-header';
import { CommunityLink } from './community-link';
@ -272,9 +273,7 @@ export class User extends Component<any, UserState> {
<div class="container">
{this.state.loading ? (
<h5>
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
</h5>
) : (
<div class="row">
@ -393,9 +392,7 @@ export class User extends Component<any, UserState> {
rel="noopener"
title="RSS"
>
<svg class="icon mx-2 text-muted small">
<use xlinkHref="#icon-rss"></use>
</svg>
<Icon icon="rss" classes="text-muted small mx-2" />
</a>
</div>
);
@ -485,9 +482,7 @@ export class User extends Component<any, UserState> {
<MomentTime data={uv.user} showAgo ignoreUpdated />
</div>
<div className="d-flex align-items-center text-muted mb-2">
<svg class="icon">
<use xlinkHref="#icon-cake"></use>
</svg>
<Icon icon="cake" />
<span className="ml-2">
{i18n.t('cake_day_title')}{' '}
{moment.utc(uv.user.published).local().format('MMM DD, YYYY')}
@ -787,9 +782,7 @@ export class User extends Component<any, UserState> {
<div class="form-group">
<button type="submit" class="btn btn-block btn-secondary mr-4">
{this.state.userSettingsLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : (
capitalizeFirstLetter(i18n.t('save'))
)}
@ -827,9 +820,7 @@ export class User extends Component<any, UserState> {
onClick={linkEvent(this, this.handleDeleteAccount)}
>
{this.state.deleteAccountLoading ? (
<svg class="icon icon-spinner spin">
<use xlinkHref="#icon-spinner"></use>
</svg>
<Spinner />
) : (
capitalizeFirstLetter(i18n.t('delete'))
)}