]> Untitled Git - lemmy-ui.git/commitdiff
Re-organized components folder. (#339)
authorDessalines <dessalines@users.noreply.github.com>
Sat, 17 Jul 2021 20:42:55 +0000 (16:42 -0400)
committerGitHub <noreply@github.com>
Sat, 17 Jul 2021 20:42:55 +0000 (16:42 -0400)
* Fixing too many large spinners

* Re-organized components folder.

- Cleaned up spans. Fixes #173
- Fixes #320

* Fixing miscolored edit

62 files changed:
package.json
src/client/index.tsx
src/server/index.tsx
src/shared/components/app/app.tsx [moved from src/shared/components/app.tsx with 93% similarity]
src/shared/components/app/footer.tsx [moved from src/shared/components/footer.tsx with 92% similarity]
src/shared/components/app/navbar.tsx [moved from src/shared/components/navbar.tsx with 98% similarity]
src/shared/components/app/no-match.tsx [moved from src/shared/components/no-match.tsx with 93% similarity]
src/shared/components/app/styles.scss [new file with mode: 0644]
src/shared/components/app/theme.tsx [moved from src/shared/components/theme.tsx with 100% similarity]
src/shared/components/comment/comment-form.tsx [moved from src/shared/components/comment-form.tsx with 93% similarity]
src/shared/components/comment/comment-node.tsx [moved from src/shared/components/comment-node.tsx with 99% similarity]
src/shared/components/comment/comment-nodes.tsx [moved from src/shared/components/comment-nodes.tsx with 95% similarity]
src/shared/components/common/banner-icon-header.tsx [moved from src/shared/components/banner-icon-header.tsx with 100% similarity]
src/shared/components/common/data-type-select.tsx [moved from src/shared/components/data-type-select.tsx with 95% similarity]
src/shared/components/common/html-tags.tsx [moved from src/shared/components/html-tags.tsx with 94% similarity]
src/shared/components/common/icon.tsx [moved from src/shared/components/icon.tsx with 100% similarity]
src/shared/components/common/image-upload-form.tsx [moved from src/shared/components/image-upload-form.tsx with 94% similarity]
src/shared/components/common/listing-type-select.tsx [moved from src/shared/components/listing-type-select.tsx with 95% similarity]
src/shared/components/common/markdown-textarea.tsx [moved from src/shared/components/markdown-textarea.tsx with 98% similarity]
src/shared/components/common/moment-time.tsx [moved from src/shared/components/moment-time.tsx with 92% similarity]
src/shared/components/common/paginator.tsx [moved from src/shared/components/paginator.tsx with 95% similarity]
src/shared/components/common/pictrs-image.tsx [moved from src/shared/components/pictrs-image.tsx with 100% similarity]
src/shared/components/common/sort-select.tsx [moved from src/shared/components/sort-select.tsx with 96% similarity]
src/shared/components/common/symbols.tsx [moved from src/shared/components/symbols.tsx with 100% similarity]
src/shared/components/community/communities.tsx [moved from src/shared/components/communities.tsx with 94% similarity]
src/shared/components/community/community-form.tsx [moved from src/shared/components/community-form.tsx with 96% similarity]
src/shared/components/community/community-link.tsx [moved from src/shared/components/community-link.tsx with 94% similarity]
src/shared/components/community/community.tsx [moved from src/shared/components/community.tsx with 95% similarity]
src/shared/components/community/create-community.tsx [moved from src/shared/components/create-community.tsx with 89% similarity]
src/shared/components/community/sidebar.tsx [moved from src/shared/components/sidebar.tsx with 92% similarity]
src/shared/components/home/admin-settings.tsx [moved from src/shared/components/admin-settings.tsx with 95% similarity]
src/shared/components/home/home.tsx [moved from src/shared/components/main.tsx with 95% similarity]
src/shared/components/home/instances.tsx [moved from src/shared/components/instances.tsx with 93% similarity]
src/shared/components/home/login.tsx [new file with mode: 0644]
src/shared/components/home/password_change.tsx [moved from src/shared/components/password_change.tsx with 95% similarity]
src/shared/components/home/setup.tsx [moved from src/shared/components/setup.tsx with 94% similarity]
src/shared/components/home/site-form.tsx [moved from src/shared/components/site-form.tsx with 96% similarity]
src/shared/components/login.tsx
src/shared/components/modlog.tsx
src/shared/components/person/cake-day.tsx [moved from src/shared/components/cake-day.tsx with 86% similarity]
src/shared/components/person/inbox.tsx [moved from src/shared/components/inbox.tsx with 96% similarity]
src/shared/components/person/person-details.tsx [moved from src/shared/components/person-details.tsx with 93% similarity]
src/shared/components/person/person-listing.tsx [moved from src/shared/components/person-listing.tsx with 94% similarity]
src/shared/components/person/person.tsx [moved from src/shared/components/person.tsx with 98% similarity]
src/shared/components/post/create-post.tsx [moved from src/shared/components/create-post.tsx with 96% similarity]
src/shared/components/post/iframely-card.tsx [moved from src/shared/components/iframely-card.tsx with 97% similarity]
src/shared/components/post/post-form.tsx [moved from src/shared/components/post-form.tsx with 98% similarity]
src/shared/components/post/post-listing.tsx [moved from src/shared/components/post-listing.tsx with 98% similarity]
src/shared/components/post/post-listings.tsx [moved from src/shared/components/post-listings.tsx with 98% similarity]
src/shared/components/post/post.tsx [moved from src/shared/components/post.tsx with 97% similarity]
src/shared/components/private_message/create-private-message.tsx [moved from src/shared/components/create-private-message.tsx with 93% similarity]
src/shared/components/private_message/private-message-form.tsx [moved from src/shared/components/private-message-form.tsx with 93% similarity]
src/shared/components/private_message/private-message.tsx [moved from src/shared/components/private-message.tsx with 95% similarity]
src/shared/components/search.tsx
src/shared/components/styles.scss [deleted file]
src/shared/i18next.ts
src/shared/initialize.ts [deleted file]
src/shared/routes.ts
src/shared/services/UserService.ts
src/shared/services/WebSocketService.ts
src/shared/utils.ts
yarn.lock

index 9e1e957b41cfd7d80356ea34a5fe24137dcb50e1..270dad9787a864b0979939ea748c5dcba05e30fa 100644 (file)
@@ -67,6 +67,7 @@
     "eslint": "^7.30.0",
     "eslint-plugin-prettier": "^3.4.0",
     "husky": "^7.0.1",
+    "import-sort-style-module": "^6.0.0",
     "iso-639-1": "^2.1.9",
     "lemmy-js-client": "0.11.0",
     "lint-staged": "^11.0.1",
@@ -74,6 +75,9 @@
     "node-fetch": "^2.6.1",
     "node-sass": "^6.0.1",
     "prettier": "^2.3.2",
+    "prettier-plugin-import-sort": "^0.0.7",
+    "prettier-plugin-organize-imports": "^2.2.0",
+    "prettier-plugin-packagejson": "^2.2.11",
     "rimraf": "^3.0.2",
     "run-node-webpack-plugin": "^1.3.0",
     "sass-loader": "^12.1.0",
     "package.json": [
       "sortpack"
     ]
+  },
+  "importSort": {
+    ".js, .jsx, .ts, .tsx": {
+      "style": "module",
+      "parser": "typescript"
+    }
   }
 }
index cb2e58f829fce400805afd4b247fe8dee08636b3..d5773b4455a29827a734eed34dc2063bb96ed8ca 100644 (file)
@@ -1,7 +1,7 @@
 import { hydrate } from "inferno-hydrate";
 import { BrowserRouter } from "inferno-router";
-import { initializeSite } from "../shared/initialize";
-import { App } from "../shared/components/app";
+import { App } from "../shared/components/app/app";
+import { initializeSite } from "../shared/utils";
 
 const site = window.isoData.site_res;
 initializeSite(site);
index 8273a57d2e0cce30f258038db44322b45cca6a48..163ab538ac299dae24bb080ed1d6b91deb559df0 100644 (file)
@@ -1,25 +1,23 @@
-import serialize from "serialize-javascript";
 import express from "express";
-import { StaticRouter } from "inferno-router";
+import { IncomingHttpHeaders } from "http";
+import { Helmet } from "inferno-helmet";
+import { matchPath, StaticRouter } from "inferno-router";
 import { renderToString } from "inferno-server";
-import { matchPath } from "inferno-router";
+import IsomorphicCookie from "isomorphic-cookie";
+import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
 import path from "path";
-import { App } from "../shared/components/app";
+import process from "process";
+import serialize from "serialize-javascript";
+import { App } from "../shared/components/app/app";
+import { SYMBOLS } from "../shared/components/common/symbols";
+import { httpBaseInternal } from "../shared/env";
 import {
   ILemmyConfig,
   InitialFetchRequest,
   IsoData,
 } from "../shared/interfaces";
 import { routes } from "../shared/routes";
-import IsomorphicCookie from "isomorphic-cookie";
-import { GetSite, GetSiteResponse, LemmyHttp } from "lemmy-js-client";
-import process from "process";
-import { Helmet } from "inferno-helmet";
-import { SYMBOLS } from "../shared/components/symbols";
-import { initializeSite } from "../shared/initialize";
-import { httpBaseInternal } from "../shared/env";
-import { IncomingHttpHeaders } from "http";
-import { setOptionalAuth } from "../shared/utils";
+import { initializeSite, setOptionalAuth } from "../shared/utils";
 
 const server = express();
 const [hostname, port] = process.env["LEMMY_UI_HOST"]
similarity index 93%
rename from src/shared/components/app.tsx
rename to src/shared/components/app/app.tsx
index 179db4db52f8382ef01a3186b07d2b3f15e96910..689f7985acabd2800b57bebf1c2e25e1a493f2c4 100644 (file)
@@ -1,16 +1,16 @@
 import { Component } from "inferno";
-import { Route, Switch } from "inferno-router";
-import { Provider } from "inferno-i18next";
 import { Helmet } from "inferno-helmet";
-import { i18n } from "../i18next";
-import { routes } from "../routes";
-import { Navbar } from "./navbar";
+import { Provider } from "inferno-i18next";
+import { Route, Switch } from "inferno-router";
+import { GetSiteResponse } from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { routes } from "../../routes";
+import { favIconPngUrl, favIconUrl } from "../../utils";
 import { Footer } from "./footer";
+import { Navbar } from "./navbar";
 import { NoMatch } from "./no-match";
-import { Theme } from "./theme";
-import { GetSiteResponse } from "lemmy-js-client";
 import "./styles.scss";
-import { favIconPngUrl, favIconUrl } from "../utils";
+import { Theme } from "./theme";
 
 export interface AppProps {
   siteRes: GetSiteResponse;
similarity index 92%
rename from src/shared/components/footer.tsx
rename to src/shared/components/app/footer.tsx
index 6547a18ffa3f443294f1f7157bd8b766394fe7cd..de70ac5c821f2ca8753957e0f38ef564df3c2cf7 100644 (file)
@@ -1,9 +1,9 @@
 import { Component } from "inferno";
 import { Link } from "inferno-router";
-import { i18n } from "../i18next";
-import { repoUrl, joinLemmyUrl, docsUrl } from "../utils";
 import { GetSiteResponse } from "lemmy-js-client";
-import { VERSION } from "../version";
+import { i18n } from "../../i18next";
+import { docsUrl, joinLemmyUrl, repoUrl } from "../../utils";
+import { VERSION } from "../../version";
 
 interface FooterProps {
   site: GetSiteResponse;
similarity index 98%
rename from src/shared/components/navbar.tsx
rename to src/shared/components/app/navbar.tsx
index 0af55ddcea9a1a7e265031866537218b2687a6a1..00381f63aad8b14903de42a5029a4b27db358c2b 100644 (file)
@@ -1,41 +1,41 @@
-import { Component, linkEvent, createRef, RefObject } from "inferno";
+import { Component, createRef, linkEvent, RefObject } from "inferno";
 import { Link } from "inferno-router";
-import { Subscription } from "rxjs";
-import { WebSocketService, UserService } from "../services";
 import {
-  UserOperation,
-  GetReplies,
-  GetRepliesResponse,
+  CommentResponse,
+  CommentView,
   GetPersonMentions,
   GetPersonMentionsResponse,
   GetPrivateMessages,
-  PrivateMessagesResponse,
-  SortType,
+  GetReplies,
+  GetRepliesResponse,
   GetSiteResponse,
-  CommentView,
-  CommentResponse,
   PrivateMessageResponse,
+  PrivateMessagesResponse,
   PrivateMessageView,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  showAvatars,
+  authField,
   fetchLimit,
-  toast,
-  setTheme,
   getLanguage,
+  isBrowser,
   notifyComment,
   notifyPrivateMessage,
-  isBrowser,
-  wsSubscribe,
+  setTheme,
+  showAvatars,
   supportLemmyUrl,
-  wsUserOp,
+  toast,
   wsClient,
-  authField,
-} from "../utils";
-import { i18n } from "../i18next";
-import { PictrsImage } from "./pictrs-image";
-import { Icon } from "./icon";
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
+} from "../../utils";
+import { Icon } from "../common/icon";
+import { PictrsImage } from "../common/pictrs-image";
 
 interface NavbarProps {
   site_res: GetSiteResponse;
similarity index 93%
rename from src/shared/components/no-match.tsx
rename to src/shared/components/app/no-match.tsx
index 175f4a9b2a7176cdabe0663adbd67ccede87b236..ca3fe64f0bcf889e828f2a3dc8625646136b97e5 100644 (file)
@@ -1,6 +1,6 @@
 import { I18nKeys } from "i18next";
 import { Component } from "inferno";
-import { i18n } from "../i18next";
+import { i18n } from "../../i18next";
 
 export class NoMatch extends Component<any, any> {
   private errCode = new URLSearchParams(this.props.location.search).get(
diff --git a/src/shared/components/app/styles.scss b/src/shared/components/app/styles.scss
new file mode 100644 (file)
index 0000000..7600681
--- /dev/null
@@ -0,0 +1,6 @@
+// Custom css
+@import "../../../../node_modules/tributejs/dist/tribute.css";
+@import "../../../../node_modules/toastify-js/src/toastify.css";
+@import "../../../../node_modules/choices.js/src/styles/choices.scss";
+@import "../../../../node_modules/tippy.js/dist/tippy.css";
+@import "../../../assets/css/main.css";
similarity index 100%
rename from src/shared/components/theme.tsx
rename to src/shared/components/app/theme.tsx
index 6ae1c4bf59a2dc9acc0dd88b471de0cda5e98010..624de61bef952b7f1a21e83f8572a89175ab5768 100644 (file)
@@ -1,6 +1,6 @@
-import { LocalUserSettingsView } from "lemmy-js-client";
-import { Helmet } from "inferno-helmet";
 import { Component } from "inferno";
+import { Helmet } from "inferno-helmet";
+import { LocalUserSettingsView } from "lemmy-js-client";
 
 interface Props {
   localUserView: LocalUserSettingsView | undefined;
similarity index 93%
rename from src/shared/components/comment-form.tsx
rename to src/shared/components/comment/comment-form.tsx
index 15a6838663388b79cfb7a2be323379790db88cbe..b7687c802eb221ba449960682d0d1292a8f04c3d 100644 (file)
@@ -1,13 +1,16 @@
 import { Component } from "inferno";
+import { T } from "inferno-i18next";
 import { Link } from "inferno-router";
-import { Subscription } from "rxjs";
 import {
+  CommentResponse,
   CreateComment,
   EditComment,
   UserOperation,
-  CommentResponse,
 } from "lemmy-js-client";
-import { CommentNode as CommentNodeI } from "../interfaces";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { CommentNode as CommentNodeI } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
   authField,
   capitalizeFirstLetter,
@@ -15,12 +18,9 @@ import {
   wsJsonToRes,
   wsSubscribe,
   wsUserOp,
-} from "../utils";
-import { WebSocketService, UserService } from "../services";
-import { i18n } from "../i18next";
-import { T } from "inferno-i18next";
-import { MarkdownTextArea } from "./markdown-textarea";
-import { Icon } from "./icon";
+} from "../../utils";
+import { Icon } from "../common/icon";
+import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface CommentFormProps {
   postId?: number;
similarity index 99%
rename from src/shared/components/comment-node.tsx
rename to src/shared/components/comment/comment-node.tsx
index 9423210c9e2654a6115822e70ca8908e63318a84..e13b93bea562319a57056b82d876a84661436a5c 100644 (file)
@@ -1,44 +1,44 @@
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
+  AddAdmin,
+  AddModToCommunity,
+  BanFromCommunity,
+  BanPerson,
+  CommentView,
+  CommunityModeratorView,
   CreateCommentLike,
   DeleteComment,
-  RemoveComment,
   MarkCommentAsRead,
   MarkPersonMentionAsRead,
-  SaveComment,
-  BanFromCommunity,
-  BanPerson,
-  CommunityModeratorView,
+  PersonMentionView,
   PersonViewSafe,
-  AddModToCommunity,
-  AddAdmin,
+  RemoveComment,
+  SaveComment,
   TransferCommunity,
   TransferSite,
-  CommentView,
-  PersonMentionView,
 } from "lemmy-js-client";
-import { CommentNode as CommentNodeI, BanType } from "../interfaces";
-import { WebSocketService, UserService } from "../services";
+import moment from "moment";
+import { i18n } from "../../i18next";
+import { BanType, CommentNode as CommentNodeI } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  mdToHtml,
-  getUnixTime,
+  authField,
   canMod,
+  colorList,
+  getUnixTime,
   isMod,
+  mdToHtml,
   setupTippy,
-  colorList,
-  wsClient,
-  authField,
   showScores,
-} from "../utils";
-import moment from "moment";
-import { MomentTime } from "./moment-time";
+  wsClient,
+} from "../../utils";
+import { Icon, Spinner } from "../common/icon";
+import { MomentTime } from "../common/moment-time";
+import { CommunityLink } from "../community/community-link";
+import { PersonListing } from "../person/person-listing";
 import { CommentForm } from "./comment-form";
 import { CommentNodes } from "./comment-nodes";
-import { PersonListing } from "./person-listing";
-import { CommunityLink } from "./community-link";
-import { Icon, Spinner } from "./icon";
-import { i18n } from "../i18next";
 
 interface CommentNodeState {
   showReply: boolean;
similarity index 95%
rename from src/shared/components/comment-nodes.tsx
rename to src/shared/components/comment/comment-nodes.tsx
index 0ce2bb9a81402f97ec01259954b452f1fadee17e..3605358fbeafd52a755f26c12822e1e613506465 100644 (file)
@@ -1,6 +1,6 @@
 import { Component } from "inferno";
-import { CommentNode as CommentNodeI } from "../interfaces";
 import { CommunityModeratorView, PersonViewSafe } from "lemmy-js-client";
+import { CommentNode as CommentNodeI } from "../../interfaces";
 import { CommentNode } from "./comment-node";
 
 interface CommentNodesProps {
similarity index 95%
rename from src/shared/components/data-type-select.tsx
rename to src/shared/components/common/data-type-select.tsx
index fb5cb5d883ed0a080339542cb2c9489dbd4735f0..b9b6a6f580c07a04cac295e7f93c9203c39e9162 100644 (file)
@@ -1,7 +1,6 @@
 import { Component, linkEvent } from "inferno";
-import { DataType } from "../interfaces";
-
-import { i18n } from "../i18next";
+import { i18n } from "../../i18next";
+import { DataType } from "../../interfaces";
 
 interface DataTypeSelectProps {
   type_: DataType;
similarity index 94%
rename from src/shared/components/html-tags.tsx
rename to src/shared/components/common/html-tags.tsx
index f96198619d42befaac5a8c319b344a58f27c1f4a..9efed1ff5106e6be838897cd78fb01613a5e7487 100644 (file)
@@ -1,7 +1,7 @@
 import { Component } from "inferno";
 import { Helmet } from "inferno-helmet";
-import { httpExternalPath } from "../env";
-import { md } from "../utils";
+import { httpExternalPath } from "../../env";
+import { md } from "../../utils";
 
 interface HtmlTagsProps {
   title: string;
similarity index 94%
rename from src/shared/components/image-upload-form.tsx
rename to src/shared/components/common/image-upload-form.tsx
index b8b94c22da53dca9d066296baac1002921e495ad..60823c02fdc1202a31176e75127f59bbe19865d9 100644 (file)
@@ -1,8 +1,8 @@
 import { Component, linkEvent } from "inferno";
-import { pictrsUri } from "../env";
-import { UserService } from "../services";
-import { toast, randomStr } from "../utils";
-import { i18n } from "../i18next";
+import { pictrsUri } from "../../env";
+import { i18n } from "../../i18next";
+import { UserService } from "../../services";
+import { randomStr, toast } from "../../utils";
 import { Icon } from "./icon";
 
 interface ImageUploadFormProps {
similarity index 95%
rename from src/shared/components/listing-type-select.tsx
rename to src/shared/components/common/listing-type-select.tsx
index 695211e497905c598e5256a86a90407002635860..23c5bbfd3651378c175f377a8be08dff7ec30244 100644 (file)
@@ -1,8 +1,8 @@
 import { Component, linkEvent } from "inferno";
 import { ListingType } from "lemmy-js-client";
-import { UserService } from "../services";
-import { randomStr } from "../utils";
-import { i18n } from "../i18next";
+import { i18n } from "../../i18next";
+import { UserService } from "../../services";
+import { randomStr } from "../../utils";
 
 interface ListingTypeSelectProps {
   type_: ListingType;
similarity index 98%
rename from src/shared/components/markdown-textarea.tsx
rename to src/shared/components/common/markdown-textarea.tsx
index 8d3a2b743d05944d07621b8991f3f0dbc2726a13..d8f033e520941cab4936900827a5f7e53f639bcf 100644 (file)
@@ -1,19 +1,19 @@
+import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
+import { pictrsUri } from "../../env";
+import { i18n } from "../../i18next";
+import { UserService } from "../../services";
 import {
-  mdToHtml,
-  randomStr,
+  isBrowser,
   markdownHelpUrl,
-  toast,
-  setupTribute,
+  mdToHtml,
   pictrsDeleteToast,
+  randomStr,
   setupTippy,
-  isBrowser,
-} from "../utils";
-import { UserService } from "../services";
-import autosize from "autosize";
-import { i18n } from "../i18next";
-import { pictrsUri } from "../env";
+  setupTribute,
+  toast,
+} from "../../utils";
 import { Icon, Spinner } from "./icon";
 
 interface MarkdownTextAreaProps {
@@ -475,10 +475,10 @@ export class MarkdownTextArea extends Component<
 
   handleInsertCode(i: MarkdownTextArea, event: any) {
     event.preventDefault();
-    if (i.getSelectedText().split(/\r*\n/).length > 1){
+    if (i.getSelectedText().split(/\r*\n/).length > 1) {
       i.simpleSurroundBeforeAfter("```\n", "\n```");
     } else {
-      i.simpleSurround('`');
+      i.simpleSurround("`");
     }
   }
 
@@ -561,6 +561,6 @@ export class MarkdownTextArea extends Component<
     let textarea: any = document.getElementById(this.id);
     let start: number = textarea.selectionStart;
     let end: number = textarea.selectionEnd;
-    return start !== end ? this.state.content.substring(start, end) : '';
+    return start !== end ? this.state.content.substring(start, end) : "";
   }
 }
similarity index 92%
rename from src/shared/components/moment-time.tsx
rename to src/shared/components/common/moment-time.tsx
index 434e8533aa8cb521f2088579a73f36b624fdeeb4..20623932f68d77900404e2961cb28ca5d39f12d3 100644 (file)
@@ -1,7 +1,7 @@
 import { Component } from "inferno";
 import moment from "moment";
-import { getMomentLanguage, capitalizeFirstLetter } from "../utils";
-import { i18n } from "../i18next";
+import { i18n } from "../../i18next";
+import { capitalizeFirstLetter, getMomentLanguage } from "../../utils";
 import { Icon } from "./icon";
 
 interface MomentTimeProps {
similarity index 95%
rename from src/shared/components/paginator.tsx
rename to src/shared/components/common/paginator.tsx
index 055ff9fc0bd519eeb5f945e963112716f2ded59a..50094de48b839293667686106ad9f4ac32731fbd 100644 (file)
@@ -1,5 +1,5 @@
 import { Component, linkEvent } from "inferno";
-import { i18n } from "../i18next";
+import { i18n } from "../../i18next";
 
 interface PaginatorProps {
   page: number;
similarity index 96%
rename from src/shared/components/sort-select.tsx
rename to src/shared/components/common/sort-select.tsx
index 56ada8aca50c2303a7c7ce6fba6f8a5db360d36f..9504756e9bdb34268ea11de86ad921e2c377f8e3 100644 (file)
@@ -1,8 +1,8 @@
 import { Component, linkEvent } from "inferno";
 import { SortType } from "lemmy-js-client";
-import { sortingHelpUrl, randomStr } from "../utils";
+import { i18n } from "../../i18next";
+import { randomStr, sortingHelpUrl } from "../../utils";
 import { Icon } from "./icon";
-import { i18n } from "../i18next";
 
 interface SortSelectProps {
   sort: SortType;
similarity index 94%
rename from src/shared/components/communities.tsx
rename to src/shared/components/community/communities.tsx
index 875ceeac8046c4b14860ecba7bd3b5e3c0e9f983..d57f1a455fb512beb6450e6d839032a34bd6e4ac 100644 (file)
@@ -1,35 +1,35 @@
 import { Component, linkEvent } from "inferno";
-import { HtmlTags } from "./html-tags";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
-  CommunityView,
-  ListCommunitiesResponse,
   CommunityResponse,
+  CommunityView,
   FollowCommunity,
   ListCommunities,
-  SortType,
+  ListCommunitiesResponse,
   ListingType,
   SiteView,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService } from "../services";
+import { Subscription } from "rxjs";
+import { InitialFetchRequest } from "shared/interfaces";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  toast,
+  authField,
   getPageFromProps,
   isBrowser,
   setIsoData,
+  setOptionalAuth,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
   wsUserOp,
-  wsClient,
-  authField,
-  setOptionalAuth,
-} from "../utils";
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { Paginator } from "../common/paginator";
 import { CommunityLink } from "./community-link";
-import { Paginator } from "./paginator";
-import { Spinner } from "./icon";
-import { i18n } from "../i18next";
-import { InitialFetchRequest } from "shared/interfaces";
 
 const communityLimit = 100;
 
@@ -152,27 +152,25 @@ export class Communities extends Component<any, CommunitiesState> {
                       </td>
                       <td class="text-right">
                         {cv.subscribed ? (
-                          <span
-                            class="pointer btn-link"
-                            role="button"
+                          <button
+                            class="btn btn-link d-inline-block"
                             onClick={linkEvent(
                               cv.community.id,
                               this.handleUnsubscribe
                             )}
                           >
                             {i18n.t("unsubscribe")}
-                          </span>
+                          </button>
                         ) : (
-                          <span
-                            class="pointer btn-link"
-                            role="button"
+                          <button
+                            class="btn btn-link d-inline-block"
                             onClick={linkEvent(
                               cv.community.id,
                               this.handleSubscribe
                             )}
                           >
                             {i18n.t("subscribe")}
-                          </span>
+                          </button>
                         )}
                       </td>
                     </tr>
similarity index 96%
rename from src/shared/components/community-form.tsx
rename to src/shared/components/community/community-form.tsx
index 396c0f3fff30b71fc34ec9b6d85f6bbe89bc3498..ecc2b8900fdd40bd72b66c502a739e0283ad6fd2 100644 (file)
@@ -1,29 +1,28 @@
 import { Component, linkEvent } from "inferno";
 import { Prompt } from "inferno-router";
-import { Subscription } from "rxjs";
 import {
-  EditCommunity,
-  CreateCommunity,
-  UserOperation,
   CommunityResponse,
   CommunityView,
+  CreateCommunity,
+  EditCommunity,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService } from "../services";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
+  authField,
   capitalizeFirstLetter,
-  toast,
   randomStr,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
   wsUserOp,
-  wsClient,
-  authField,
-} from "../utils";
-import { i18n } from "../i18next";
-
-import { MarkdownTextArea } from "./markdown-textarea";
-import { ImageUploadForm } from "./image-upload-form";
-import { Icon, Spinner } from "./icon";
+} from "../../utils";
+import { Icon, Spinner } from "../common/icon";
+import { ImageUploadForm } from "../common/image-upload-form";
+import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface CommunityFormProps {
   community_view?: CommunityView; // If a community is given, that means this is an edit
@@ -62,9 +61,8 @@ export class CommunityForm extends Component<
 
     this.state = this.emptyState;
 
-    this.handleCommunityDescriptionChange = this.handleCommunityDescriptionChange.bind(
-      this
-    );
+    this.handleCommunityDescriptionChange =
+      this.handleCommunityDescriptionChange.bind(this);
 
     this.handleIconUpload = this.handleIconUpload.bind(this);
     this.handleIconRemove = this.handleIconRemove.bind(this);
similarity index 94%
rename from src/shared/components/community-link.tsx
rename to src/shared/components/community/community-link.tsx
index c12f570b7ec187cbcb1c938436e0b189ebbebe4c..fe68a27e9e790c5bc0bb78f87386fc4d72bee728 100644 (file)
@@ -1,8 +1,8 @@
 import { Component } from "inferno";
 import { Link } from "inferno-router";
 import { CommunitySafe } from "lemmy-js-client";
-import { hostname, showAvatars } from "../utils";
-import { PictrsImage } from "./pictrs-image";
+import { hostname, showAvatars } from "../../utils";
+import { PictrsImage } from "../common/pictrs-image";
 
 interface CommunityLinkProps {
   // TODO figure this out better
similarity index 95%
rename from src/shared/components/community.tsx
rename to src/shared/components/community/community.tsx
index 4a82da61afc6bd6854fa47c0d0ace89f96a44bd3..954c1977ddd6f4a73a90d006d2dab3412c395026 100644 (file)
@@ -1,62 +1,62 @@
 import { Component } from "inferno";
-import { Subscription } from "rxjs";
-import { DataType, InitialFetchRequest } from "../interfaces";
 import {
-  UserOperation,
-  GetCommunityResponse,
-  CommunityResponse,
-  SortType,
-  PostView,
-  GetPosts,
-  GetCommunity,
-  ListingType,
-  GetPostsResponse,
-  PostResponse,
   AddModToCommunityResponse,
   BanFromCommunityResponse,
+  CommentResponse,
   CommentView,
+  CommunityResponse,
   GetComments,
   GetCommentsResponse,
-  CommentResponse,
+  GetCommunity,
+  GetCommunityResponse,
+  GetPosts,
+  GetPostsResponse,
   GetSiteResponse,
+  ListingType,
+  PostResponse,
+  PostView,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
-import { UserService, WebSocketService } from "../services";
-import { PostListings } from "./post-listings";
-import { CommentNodes } from "./comment-nodes";
-import { HtmlTags } from "./html-tags";
-import { SortSelect } from "./sort-select";
-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 { Paginator } from "./paginator";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { DataType, InitialFetchRequest } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  fetchLimit,
-  toast,
-  getPageFromProps,
-  getSortTypeFromProps,
-  getDataTypeFromProps,
-  editCommentRes,
-  saveCommentRes,
+  authField,
+  commentsToFlatNodes,
+  communityRSSUrl,
   createCommentLikeRes,
   createPostLikeFindRes,
+  editCommentRes,
   editPostFindRes,
-  commentsToFlatNodes,
-  setupTippy,
+  fetchLimit,
+  getDataTypeFromProps,
+  getPageFromProps,
+  getSortTypeFromProps,
   notifyPost,
+  restoreScrollPosition,
+  saveCommentRes,
+  saveScrollPosition,
   setIsoData,
+  setOptionalAuth,
+  setupTippy,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
-  communityRSSUrl,
   wsUserOp,
-  wsClient,
-  authField,
-  setOptionalAuth,
-  saveScrollPosition,
-  restoreScrollPosition,
-} from "../utils";
-import { i18n } from "../i18next";
+} from "../../utils";
+import { CommentNodes } from "../comment/comment-nodes";
+import { BannerIconHeader } from "../common/banner-icon-header";
+import { DataTypeSelect } from "../common/data-type-select";
+import { HtmlTags } from "../common/html-tags";
+import { Icon, Spinner } from "../common/icon";
+import { Paginator } from "../common/paginator";
+import { SortSelect } from "../common/sort-select";
+import { Sidebar } from "../community/sidebar";
+import { PostListings } from "../post/post-listings";
+import { CommunityLink } from "./community-link";
 
 interface State {
   communityRes: GetCommunityResponse;
similarity index 89%
rename from src/shared/components/create-community.tsx
rename to src/shared/components/community/create-community.tsx
index c8e3111e2f57ff2f674401203d8f4cc19bfe2cd8..b96ddba91cb60eb8a3616a88955149bc537cdf4a 100644 (file)
@@ -1,12 +1,12 @@
 import { Component } from "inferno";
+import { CommunityView, SiteView } from "lemmy-js-client";
 import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { UserService } from "../../services";
+import { isBrowser, setIsoData, toast, wsSubscribe } from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
 import { CommunityForm } from "./community-form";
-import { HtmlTags } from "./html-tags";
-import { Spinner } from "./icon";
-import { CommunityView, SiteView } from "lemmy-js-client";
-import { setIsoData, toast, wsSubscribe, isBrowser } from "../utils";
-import { UserService } from "../services";
-import { i18n } from "../i18next";
 
 interface CreateCommunityState {
   site_view: SiteView;
similarity index 92%
rename from src/shared/components/sidebar.tsx
rename to src/shared/components/community/sidebar.tsx
index 29b1523f5a43e1b3cee8c17a0d19440d076c46dd..a699ab982998cb8cfd0cfebbe47431660671229a 100644 (file)
@@ -1,22 +1,22 @@
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
 import {
-  CommunityView,
+  AddModToCommunity,
   CommunityModeratorView,
-  FollowCommunity,
+  CommunityView,
   DeleteCommunity,
-  RemoveCommunity,
+  FollowCommunity,
   PersonViewSafe,
-  AddModToCommunity,
+  RemoveCommunity,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
-import { mdToHtml, getUnixTime, wsClient, authField } from "../utils";
-import { CommunityForm } from "./community-form";
-import { PersonListing } from "./person-listing";
-import { CommunityLink } from "./community-link";
-import { BannerIconHeader } from "./banner-icon-header";
-import { Icon } from "./icon";
-import { i18n } from "../i18next";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
+import { authField, getUnixTime, mdToHtml, wsClient } from "../../utils";
+import { BannerIconHeader } from "../common/banner-icon-header";
+import { Icon } from "../common/icon";
+import { CommunityForm } from "../community/community-form";
+import { CommunityLink } from "../community/community-link";
+import { PersonListing } from "../person/person-listing";
 
 interface SidebarProps {
   community_view: CommunityView;
@@ -289,29 +289,27 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
           {this.canMod && (
             <>
               <li className="list-inline-item-action">
-                <span
-                  role="button"
-                  class="pointer"
+                <button
+                  class="btn btn-link text-muted d-inline-block"
                   onClick={linkEvent(this, this.handleEditClick)}
                   data-tippy-content={i18n.t("edit")}
                   aria-label={i18n.t("edit")}
                 >
                   <Icon icon="edit" classes="icon-inline" />
-                </span>
+                </button>
               </li>
               {!this.amTopMod &&
                 (!this.state.showConfirmLeaveModTeam ? (
                   <li className="list-inline-item-action">
-                    <span
-                      class="pointer"
-                      role="button"
+                    <button
+                      class="btn btn-link text-muted d-inline-block"
                       onClick={linkEvent(
                         this,
                         this.handleShowConfirmLeaveModTeamClick
                       )}
                     >
                       {i18n.t("leave_mod_team")}
-                    </span>
+                    </button>
                   </li>
                 ) : (
                   <>
@@ -319,32 +317,30 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
                       {i18n.t("are_you_sure")}
                     </li>
                     <li className="list-inline-item-action">
-                      <span
-                        class="pointer"
-                        role="button"
+                      <button
+                        class="btn btn-link text-muted d-inline-block"
                         onClick={linkEvent(this, this.handleLeaveModTeamClick)}
                       >
                         {i18n.t("yes")}
-                      </span>
+                      </button>
                     </li>
                     <li className="list-inline-item-action">
-                      <span
-                        class="pointer"
-                        role="button"
+                      <button
+                        class="btn btn-link text-muted d-inline-block"
                         onClick={linkEvent(
                           this,
                           this.handleCancelLeaveModTeamClick
                         )}
                       >
                         {i18n.t("no")}
-                      </span>
+                      </button>
                     </li>
                   </>
                 ))}
               {this.amTopMod && (
                 <li className="list-inline-item-action">
-                  <span
-                    class="pointer"
+                  <button
+                    class="btn btn-link text-muted d-inline-block"
                     onClick={linkEvent(this, this.handleDeleteClick)}
                     data-tippy-content={
                       !community_view.community.deleted
@@ -363,7 +359,7 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
                         community_view.community.deleted && "text-danger"
                       }`}
                     />
-                  </span>
+                  </button>
                 </li>
               )}
             </>
@@ -371,21 +367,19 @@ export class Sidebar extends Component<SidebarProps, SidebarState> {
           {this.canAdmin && (
             <li className="list-inline-item">
               {!this.props.community_view.community.removed ? (
-                <span
-                  class="pointer"
-                  role="button"
+                <button
+                  class="btn btn-link text-muted d-inline-block"
                   onClick={linkEvent(this, this.handleModRemoveShow)}
                 >
                   {i18n.t("remove")}
-                </span>
+                </button>
               ) : (
-                <span
-                  class="pointer"
-                  role="button"
+                <button
+                  class="btn btn-link text-muted d-inline-block"
                   onClick={linkEvent(this, this.handleModRemoveSubmit)}
                 >
                   {i18n.t("restore")}
-                </span>
+                </button>
               )}
             </li>
           )}
similarity index 95%
rename from src/shared/components/admin-settings.tsx
rename to src/shared/components/home/admin-settings.tsx
index d9aa74b176e5a2ac03cd3bd745567612843d4fd1..cc8be245367a25e8682a9acc77ea3479c7712217 100644 (file)
@@ -1,33 +1,33 @@
+import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
-  SiteResponse,
+  GetSiteConfig,
+  GetSiteConfigResponse,
   GetSiteResponse,
   SaveSiteConfig,
-  GetSiteConfigResponse,
-  GetSiteConfig,
+  SiteResponse,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService } from "../services";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { InitialFetchRequest } from "../../interfaces";
+import { WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
+  authField,
   capitalizeFirstLetter,
-  toast,
+  isBrowser,
   randomStr,
   setIsoData,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
-  isBrowser,
   wsUserOp,
-  wsClient,
-  authField,
-} from "../utils";
-import autosize from "autosize";
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { PersonListing } from "../person/person-listing";
 import { SiteForm } from "./site-form";
-import { PersonListing } from "./person-listing";
-import { HtmlTags } from "./html-tags";
-import { Spinner } from "./icon";
-import { i18n } from "../i18next";
-import { InitialFetchRequest } from "shared/interfaces";
 
 interface AdminSettingsState {
   siteRes: GetSiteResponse;
similarity index 95%
rename from src/shared/components/main.tsx
rename to src/shared/components/home/home.tsx
index 0e781ef80b563765e9033c89cdc151d881bcd19b..9d6b6898af11132e0663b7c431fba7d3c632dbec 100644 (file)
@@ -1,73 +1,73 @@
 import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next";
 import { Link } from "inferno-router";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
+  AddAdminResponse,
+  BanPersonResponse,
+  CommentResponse,
+  CommentView,
   CommunityFollowerView,
+  CommunityView,
+  GetComments,
+  GetCommentsResponse,
   GetFollowedCommunitiesResponse,
+  GetPosts,
+  GetPostsResponse,
+  GetSiteResponse,
   ListCommunities,
   ListCommunitiesResponse,
-  CommunityView,
-  SortType,
-  GetSiteResponse,
   ListingType,
-  SiteResponse,
-  GetPostsResponse,
   PostResponse,
   PostView,
-  GetPosts,
-  CommentView,
-  GetComments,
-  GetCommentsResponse,
-  CommentResponse,
-  AddAdminResponse,
-  BanPersonResponse,
+  SiteResponse,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
-import { DataType, InitialFetchRequest } from "../interfaces";
-import { WebSocketService, UserService } from "../services";
-import { PostListings } from "./post-listings";
-import { CommentNodes } from "./comment-nodes";
-import { SortSelect } from "./sort-select";
-import { ListingTypeSelect } from "./listing-type-select";
-import { DataTypeSelect } from "./data-type-select";
-import { SiteForm } from "./site-form";
-import { PersonListing } from "./person-listing";
-import { CommunityLink } from "./community-link";
-import { BannerIconHeader } from "./banner-icon-header";
-import { Icon, Spinner } from "./icon";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { DataType, InitialFetchRequest } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  mdToHtml,
+  authField,
+  commentsToFlatNodes,
+  createCommentLikeRes,
+  createPostLikeFindRes,
+  editCommentRes,
+  editPostFindRes,
   fetchLimit,
-  toast,
+  getDataTypeFromProps,
   getListingTypeFromProps,
   getPageFromProps,
   getSortTypeFromProps,
-  getDataTypeFromProps,
-  editCommentRes,
-  saveCommentRes,
-  createCommentLikeRes,
-  createPostLikeFindRes,
-  editPostFindRes,
-  commentsToFlatNodes,
-  setupTippy,
+  mdToHtml,
   notifyPost,
+  restoreScrollPosition,
+  saveCommentRes,
+  saveScrollPosition,
   setIsoData,
-  wsSubscribe,
-  wsUserOp,
   setOptionalAuth,
-  wsClient,
-  authField,
-  saveScrollPosition,
-  restoreScrollPosition,
+  setupTippy,
   showLocal,
-} from "../utils";
-import { i18n } from "../i18next";
-import { T } from "inferno-i18next";
-import { HtmlTags } from "./html-tags";
-import { Paginator } from "./paginator";
+  toast,
+  wsClient,
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
+} from "../../utils";
+import { CommentNodes } from "../comment/comment-nodes";
+import { BannerIconHeader } from "../common/banner-icon-header";
+import { DataTypeSelect } from "../common/data-type-select";
+import { HtmlTags } from "../common/html-tags";
+import { Icon, Spinner } from "../common/icon";
+import { ListingTypeSelect } from "../common/listing-type-select";
+import { Paginator } from "../common/paginator";
+import { SortSelect } from "../common/sort-select";
+import { CommunityLink } from "../community/community-link";
+import { PersonListing } from "../person/person-listing";
+import { PostListings } from "../post/post-listings";
+import { SiteForm } from "./site-form";
 
-interface MainState {
+interface HomeState {
   subscribedCommunities: CommunityFollowerView[];
   trendingCommunities: CommunityView[];
   siteRes: GetSiteResponse;
@@ -81,7 +81,7 @@ interface MainState {
   page: number;
 }
 
-interface MainProps {
+interface HomeProps {
   listingType: ListingType;
   dataType: DataType;
   sort: SortType;
@@ -95,10 +95,10 @@ interface UrlParams {
   page?: number;
 }
 
-export class Main extends Component<any, MainState> {
+export class Home extends Component<any, HomeState> {
   private isoData = setIsoData(this.context);
   private subscription: Subscription;
-  private emptyState: MainState = {
+  private emptyState: HomeState = {
     subscribedCommunities: [],
     trendingCommunities: [],
     siteRes: this.isoData.site_res,
@@ -180,7 +180,7 @@ export class Main extends Component<any, MainState> {
     window.isoData.path = undefined;
   }
 
-  static getDerivedStateFromProps(props: any): MainProps {
+  static getDerivedStateFromProps(props: any): HomeProps {
     return {
       listingType: getListingTypeFromProps(props),
       dataType: getDataTypeFromProps(props),
@@ -251,7 +251,7 @@ export class Main extends Component<any, MainState> {
     return promises;
   }
 
-  componentDidUpdate(_: any, lastState: MainState) {
+  componentDidUpdate(_: any, lastState: HomeState) {
     if (
       lastState.listingType !== this.state.listingType ||
       lastState.dataType !== this.state.dataType ||
@@ -519,15 +519,14 @@ export class Main extends Component<any, MainState> {
       this.canAdmin && (
         <ul class="list-inline mb-1 text-muted font-weight-bold">
           <li className="list-inline-item-action">
-            <span
-              class="pointer"
-              role="button"
+            <button
+              class="btn btn-link d-inline-block text-muted"
               onClick={linkEvent(this, this.handleEditClick)}
               aria-label={i18n.t("edit")}
               data-tippy-content={i18n.t("edit")}
             >
               <Icon icon="edit" classes="icon-inline" />
-            </span>
+            </button>
           </li>
         </ul>
       )
@@ -647,7 +646,7 @@ export class Main extends Component<any, MainState> {
     );
   }
 
-  handleEditClick(i: Main) {
+  handleEditClick(i: Home) {
     i.state.showEditSite = true;
     i.setState(i.state);
   }
similarity index 93%
rename from src/shared/components/instances.tsx
rename to src/shared/components/home/instances.tsx
index fb6372469155844e22494c581ccc062106a6a3ef..c9a7b1ff943f8df1af29b62d84b794f2bfd591dd 100644 (file)
@@ -1,8 +1,8 @@
 import { Component } from "inferno";
 import { GetSiteResponse } from "lemmy-js-client";
-import { setIsoData } from "../utils";
-import { i18n } from "../i18next";
-import { HtmlTags } from "./html-tags";
+import { i18n } from "../../i18next";
+import { setIsoData } from "../../utils";
+import { HtmlTags } from "../common/html-tags";
 
 interface InstancesState {
   siteRes: GetSiteResponse;
diff --git a/src/shared/components/home/login.tsx b/src/shared/components/home/login.tsx
new file mode 100644 (file)
index 0000000..8568316
--- /dev/null
@@ -0,0 +1,490 @@
+import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next";
+import {
+  GetCaptchaResponse,
+  GetSiteResponse,
+  Login as LoginForm,
+  LoginResponse,
+  PasswordReset,
+  Register,
+  SiteView,
+  UserOperation,
+} from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
+import {
+  authField,
+  isBrowser,
+  joinLemmyUrl,
+  setIsoData,
+  toast,
+  validEmail,
+  wsClient,
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Icon, Spinner } from "../common/icon";
+
+interface State {
+  loginForm: LoginForm;
+  registerForm: Register;
+  loginLoading: boolean;
+  registerLoading: boolean;
+  captcha: GetCaptchaResponse;
+  captchaPlaying: boolean;
+  site_view: SiteView;
+}
+
+export class Login extends Component<any, State> {
+  private isoData = setIsoData(this.context);
+  private subscription: Subscription;
+
+  emptyState: State = {
+    loginForm: {
+      username_or_email: undefined,
+      password: undefined,
+    },
+    registerForm: {
+      username: undefined,
+      password: undefined,
+      password_verify: undefined,
+      show_nsfw: false,
+      captcha_uuid: undefined,
+      captcha_answer: undefined,
+    },
+    loginLoading: false,
+    registerLoading: false,
+    captcha: undefined,
+    captchaPlaying: false,
+    site_view: this.isoData.site_res.site_view,
+  };
+
+  constructor(props: any, context: any) {
+    super(props, context);
+
+    this.state = this.emptyState;
+
+    this.parseMessage = this.parseMessage.bind(this);
+    this.subscription = wsSubscribe(this.parseMessage);
+
+    if (isBrowser()) {
+      WebSocketService.Instance.send(wsClient.getCaptcha());
+    }
+  }
+
+  componentWillUnmount() {
+    if (isBrowser()) {
+      this.subscription.unsubscribe();
+    }
+  }
+
+  get documentTitle(): string {
+    return `${i18n.t("login")} - ${this.state.site_view.site.name}`;
+  }
+
+  get isLemmyMl(): boolean {
+    return isBrowser() && window.location.hostname == "lemmy.ml";
+  }
+
+  render() {
+    return (
+      <div class="container">
+        <HtmlTags
+          title={this.documentTitle}
+          path={this.context.router.route.match.url}
+        />
+        <div class="row">
+          <div class="col-12 col-lg-6 mb-4">{this.loginForm()}</div>
+          <div class="col-12 col-lg-6">{this.registerForm()}</div>
+        </div>
+      </div>
+    );
+  }
+
+  loginForm() {
+    return (
+      <div>
+        <form onSubmit={linkEvent(this, this.handleLoginSubmit)}>
+          <h5>{i18n.t("login")}</h5>
+          <div class="form-group row">
+            <label
+              class="col-sm-2 col-form-label"
+              htmlFor="login-email-or-username"
+            >
+              {i18n.t("email_or_username")}
+            </label>
+            <div class="col-sm-10">
+              <input
+                type="text"
+                class="form-control"
+                id="login-email-or-username"
+                value={this.state.loginForm.username_or_email}
+                onInput={linkEvent(this, this.handleLoginUsernameChange)}
+                autoComplete="email"
+                required
+                minLength={3}
+              />
+            </div>
+          </div>
+          <div class="form-group row">
+            <label class="col-sm-2 col-form-label" htmlFor="login-password">
+              {i18n.t("password")}
+            </label>
+            <div class="col-sm-10">
+              <input
+                type="password"
+                id="login-password"
+                value={this.state.loginForm.password}
+                onInput={linkEvent(this, this.handleLoginPasswordChange)}
+                class="form-control"
+                autoComplete="current-password"
+                required
+                maxLength={60}
+              />
+              <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 not-allowed"
+                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 ? <Spinner /> : i18n.t("login")}
+              </button>
+            </div>
+          </div>
+        </form>
+      </div>
+    );
+  }
+
+  registerForm() {
+    return (
+      <form onSubmit={linkEvent(this, this.handleRegisterSubmit)}>
+        <h5>{i18n.t("sign_up")}</h5>
+
+        <div class="form-group row">
+          <label class="col-sm-2 col-form-label" htmlFor="register-username">
+            {i18n.t("username")}
+          </label>
+
+          <div class="col-sm-10">
+            <input
+              type="text"
+              id="register-username"
+              class="form-control"
+              value={this.state.registerForm.username}
+              onInput={linkEvent(this, this.handleRegisterUsernameChange)}
+              required
+              minLength={3}
+              maxLength={20}
+              pattern="[a-zA-Z0-9_]+"
+            />
+          </div>
+        </div>
+
+        <div class="form-group row">
+          <label class="col-sm-2 col-form-label" htmlFor="register-email">
+            {i18n.t("email")}
+          </label>
+          <div class="col-sm-10">
+            <input
+              type="email"
+              id="register-email"
+              class="form-control"
+              placeholder={i18n.t("optional")}
+              value={this.state.registerForm.email}
+              autoComplete="email"
+              onInput={linkEvent(this, this.handleRegisterEmailChange)}
+              minLength={3}
+            />
+            {!validEmail(this.state.registerForm.email) && (
+              <div class="mt-2 mb-0 alert alert-light" role="alert">
+                <Icon icon="alert-triangle" classes="icon-inline mr-2" />
+                {i18n.t("no_password_reset")}
+              </div>
+            )}
+          </div>
+        </div>
+
+        <div class="form-group row">
+          <label class="col-sm-2 col-form-label" htmlFor="register-password">
+            {i18n.t("password")}
+          </label>
+          <div class="col-sm-10">
+            <input
+              type="password"
+              id="register-password"
+              value={this.state.registerForm.password}
+              autoComplete="new-password"
+              onInput={linkEvent(this, this.handleRegisterPasswordChange)}
+              maxLength={60}
+              class="form-control"
+              required
+            />
+          </div>
+        </div>
+
+        <div class="form-group row">
+          <label
+            class="col-sm-2 col-form-label"
+            htmlFor="register-verify-password"
+          >
+            {i18n.t("verify_password")}
+          </label>
+          <div class="col-sm-10">
+            <input
+              type="password"
+              id="register-verify-password"
+              value={this.state.registerForm.password_verify}
+              autoComplete="new-password"
+              onInput={linkEvent(this, this.handleRegisterPasswordVerifyChange)}
+              maxLength={60}
+              class="form-control"
+              required
+            />
+          </div>
+        </div>
+
+        {this.state.captcha && (
+          <div class="form-group row">
+            <label class="col-sm-2" htmlFor="register-captcha">
+              <span class="mr-2">{i18n.t("enter_code")}</span>
+              <button
+                type="button"
+                class="btn btn-secondary"
+                onClick={linkEvent(this, this.handleRegenCaptcha)}
+                aria-label={i18n.t("captcha")}
+              >
+                <Icon icon="refresh-cw" classes="icon-refresh-cw" />
+              </button>
+            </label>
+            {this.showCaptcha()}
+            <div class="col-sm-6">
+              <input
+                type="text"
+                class="form-control"
+                id="register-captcha"
+                value={this.state.registerForm.captcha_answer}
+                onInput={linkEvent(
+                  this,
+                  this.handleRegisterCaptchaAnswerChange
+                )}
+                required
+              />
+            </div>
+          </div>
+        )}
+        {this.state.site_view.site.enable_nsfw && (
+          <div class="form-group row">
+            <div class="col-sm-10">
+              <div class="form-check">
+                <input
+                  class="form-check-input"
+                  id="register-show-nsfw"
+                  type="checkbox"
+                  checked={this.state.registerForm.show_nsfw}
+                  onChange={linkEvent(this, this.handleRegisterShowNsfwChange)}
+                />
+                <label class="form-check-label" htmlFor="register-show-nsfw">
+                  {i18n.t("show_nsfw")}
+                </label>
+              </div>
+            </div>
+          </div>
+        )}
+        {this.isLemmyMl && (
+          <div class="mt-2 mb-0 alert alert-light" role="alert">
+            <T i18nKey="lemmy_ml_registration_message">
+              #<a href={joinLemmyUrl}>#</a>
+            </T>
+          </div>
+        )}
+        <div class="form-group row">
+          <div class="col-sm-10">
+            <button type="submit" class="btn btn-secondary">
+              {this.state.registerLoading ? <Spinner /> : i18n.t("sign_up")}
+            </button>
+          </div>
+        </div>
+      </form>
+    );
+  }
+
+  showCaptcha() {
+    return (
+      <div class="col-sm-4">
+        {this.state.captcha.ok && (
+          <>
+            <img
+              class="rounded-top img-fluid"
+              src={this.captchaPngSrc()}
+              style="border-bottom-right-radius: 0; border-bottom-left-radius: 0;"
+              alt={i18n.t("captcha")}
+            />
+            {this.state.captcha.ok.wav && (
+              <button
+                class="rounded-bottom btn btn-sm btn-secondary btn-block"
+                style="border-top-right-radius: 0; border-top-left-radius: 0;"
+                title={i18n.t("play_captcha_audio")}
+                onClick={linkEvent(this, this.handleCaptchaPlay)}
+                type="button"
+                disabled={this.state.captchaPlaying}
+              >
+                <Icon icon="play" classes="icon-play" />
+              </button>
+            )}
+          </>
+        )}
+      </div>
+    );
+  }
+
+  handleLoginSubmit(i: Login, event: any) {
+    event.preventDefault();
+    i.state.loginLoading = true;
+    i.setState(i.state);
+    WebSocketService.Instance.send(wsClient.login(i.state.loginForm));
+  }
+
+  handleLoginUsernameChange(i: Login, event: any) {
+    i.state.loginForm.username_or_email = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleLoginPasswordChange(i: Login, event: any) {
+    i.state.loginForm.password = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterSubmit(i: Login, event: any) {
+    event.preventDefault();
+    i.state.registerLoading = true;
+    i.setState(i.state);
+    WebSocketService.Instance.send(wsClient.register(i.state.registerForm));
+  }
+
+  handleRegisterUsernameChange(i: Login, event: any) {
+    i.state.registerForm.username = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterEmailChange(i: Login, event: any) {
+    i.state.registerForm.email = event.target.value;
+    if (i.state.registerForm.email == "") {
+      i.state.registerForm.email = undefined;
+    }
+    i.setState(i.state);
+  }
+
+  handleRegisterPasswordChange(i: Login, event: any) {
+    i.state.registerForm.password = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterPasswordVerifyChange(i: Login, event: any) {
+    i.state.registerForm.password_verify = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegisterShowNsfwChange(i: Login, event: any) {
+    i.state.registerForm.show_nsfw = event.target.checked;
+    i.setState(i.state);
+  }
+
+  handleRegisterCaptchaAnswerChange(i: Login, event: any) {
+    i.state.registerForm.captcha_answer = event.target.value;
+    i.setState(i.state);
+  }
+
+  handleRegenCaptcha(_i: Login, event: any) {
+    event.preventDefault();
+    WebSocketService.Instance.send(wsClient.getCaptcha());
+  }
+
+  handlePasswordReset(i: Login, event: any) {
+    event.preventDefault();
+    let resetForm: PasswordReset = {
+      email: i.state.loginForm.username_or_email,
+    };
+    WebSocketService.Instance.send(wsClient.passwordReset(resetForm));
+  }
+
+  handleCaptchaPlay(i: Login, event: any) {
+    event.preventDefault();
+    let snd = new Audio("data:audio/wav;base64," + i.state.captcha.ok.wav);
+    snd.play();
+    i.state.captchaPlaying = true;
+    i.setState(i.state);
+    snd.addEventListener("ended", () => {
+      snd.currentTime = 0;
+      i.state.captchaPlaying = false;
+      i.setState(this.state);
+    });
+  }
+
+  captchaPngSrc() {
+    return `data:image/png;base64,${this.state.captcha.ok.png}`;
+  }
+
+  parseMessage(msg: any) {
+    let op = wsUserOp(msg);
+    console.log(msg);
+    if (msg.error) {
+      toast(i18n.t(msg.error), "danger");
+      this.state = this.emptyState;
+      this.state.registerForm.captcha_answer = undefined;
+      // Refetch another captcha
+      WebSocketService.Instance.send(wsClient.getCaptcha());
+      this.setState(this.state);
+      return;
+    } else {
+      if (op == UserOperation.Login) {
+        let data = wsJsonToRes<LoginResponse>(msg).data;
+        this.state = this.emptyState;
+        this.setState(this.state);
+        UserService.Instance.login(data);
+        WebSocketService.Instance.send(
+          wsClient.userJoin({
+            auth: authField(),
+          })
+        );
+        toast(i18n.t("logged_in"));
+        this.props.history.push("/");
+      } else if (op == UserOperation.Register) {
+        let data = wsJsonToRes<LoginResponse>(msg).data;
+        this.state = this.emptyState;
+        this.setState(this.state);
+        UserService.Instance.login(data);
+        WebSocketService.Instance.send(
+          wsClient.userJoin({
+            auth: authField(),
+          })
+        );
+        this.props.history.push("/communities");
+      } else if (op == UserOperation.GetCaptcha) {
+        let data = wsJsonToRes<GetCaptchaResponse>(msg).data;
+        if (data.ok) {
+          this.state.captcha = data;
+          this.state.registerForm.captcha_uuid = data.ok.uuid;
+          this.setState(this.state);
+        }
+      } else if (op == UserOperation.PasswordReset) {
+        toast(i18n.t("reset_password_mail_sent"));
+      } else if (op == UserOperation.GetSite) {
+        let data = wsJsonToRes<GetSiteResponse>(msg).data;
+        this.state.site_view = data.site_view;
+        this.setState(this.state);
+      }
+    }
+  }
+}
similarity index 95%
rename from src/shared/components/password_change.tsx
rename to src/shared/components/home/password_change.tsx
index 0c30c7144804af5af7737519a2d79d45b0324ff4..2b23ddcb9282550d266869cf533cbc6798c00eae 100644 (file)
@@ -1,25 +1,25 @@
 import { Component, linkEvent } from "inferno";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
   LoginResponse,
   PasswordChange as PasswordChangeForm,
   SiteView,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
   capitalizeFirstLetter,
-  toast,
-  setIsoData,
   isBrowser,
+  setIsoData,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
   wsUserOp,
-  wsClient,
-} from "../utils";
-import { i18n } from "../i18next";
-import { HtmlTags } from "./html-tags";
-import { Spinner } from "./icon";
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
 
 interface State {
   passwordChangeForm: PasswordChangeForm;
similarity index 94%
rename from src/shared/components/setup.tsx
rename to src/shared/components/home/setup.tsx
index 53d502149860140e18fc3b487ae7c8a71cec5e6e..e104cea4e213c00c4fac42a085786fd9a819815b 100644 (file)
@@ -1,13 +1,13 @@
 import { Component, linkEvent } from "inferno";
 import { Helmet } from "inferno-helmet";
+import { LoginResponse, Register, UserOperation } from "lemmy-js-client";
 import { Subscription } from "rxjs";
-import { retryWhen, delay, take } from "rxjs/operators";
-import { Register, LoginResponse, UserOperation } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
-import { wsUserOp, wsJsonToRes, toast, wsClient } from "../utils";
+import { delay, retryWhen, take } from "rxjs/operators";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
+import { toast, wsClient, wsJsonToRes, wsUserOp } from "../../utils";
+import { Spinner } from "../common/icon";
 import { SiteForm } from "./site-form";
-import { Spinner } from "./icon";
-import { i18n } from "../i18next";
 
 interface State {
   userForm: Register;
similarity index 96%
rename from src/shared/components/site-form.tsx
rename to src/shared/components/home/site-form.tsx
index c5a0fb98015bf371c03947d8a7684adbc304c5dc..6bfed4279009852c57938a0433bc2c26a8973398 100644 (file)
@@ -1,17 +1,17 @@
 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, CreateSite } from "lemmy-js-client";
-import { WebSocketService } from "../services";
+import { CreateSite, EditSite, Site } from "lemmy-js-client";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
 import {
   authField,
   capitalizeFirstLetter,
   randomStr,
   wsClient,
-} from "../utils";
-import { i18n } from "../i18next";
+} from "../../utils";
+import { Spinner } from "../common/icon";
+import { ImageUploadForm } from "../common/image-upload-form";
+import { MarkdownTextArea } from "../common/markdown-textarea";
 
 interface SiteFormProps {
   site?: Site; // If a site is given, that means this is an edit
@@ -58,8 +58,8 @@ export class SiteForm extends Component<SiteFormProps, SiteFormState> {
         enable_downvotes: this.props.site.enable_downvotes,
         open_registration: this.props.site.open_registration,
         enable_nsfw: this.props.site.enable_nsfw,
-        community_creation_admin_only: this.props.site
-          .community_creation_admin_only,
+        community_creation_admin_only:
+          this.props.site.community_creation_admin_only,
         icon: this.props.site.icon,
         banner: this.props.site.banner,
         auth: authField(),
index c8ce80fad295ae738280ae3c24f4ea23f2e07d04..7d0163e07f958f06481fcaf18eb25a30743eb4e9 100644 (file)
@@ -1,32 +1,32 @@
 import { Component, linkEvent } from "inferno";
-import { Subscription } from "rxjs";
+import { T } from "inferno-i18next";
 import {
+  GetCaptchaResponse,
+  GetSiteResponse,
   Login as LoginForm,
-  Register,
   LoginResponse,
-  UserOperation,
   PasswordReset,
-  GetSiteResponse,
-  GetCaptchaResponse,
+  Register,
   SiteView,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
+import { Subscription } from "rxjs";
+import { i18n } from "../i18next";
+import { UserService, WebSocketService } from "../services";
 import {
-  wsJsonToRes,
-  validEmail,
-  toast,
-  wsSubscribe,
+  authField,
   isBrowser,
+  joinLemmyUrl,
   setIsoData,
-  wsUserOp,
+  toast,
+  validEmail,
   wsClient,
-  authField,
-  joinLemmyUrl,
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
 } from "../utils";
-import { i18n } from "../i18next";
-import { HtmlTags } from "./html-tags";
-import { Icon, Spinner } from "./icon";
-import { T } from "inferno-i18next";
+import { HtmlTags } from "./common/html-tags";
+import { Icon, Spinner } from "./common/icon";
 
 interface State {
   loginForm: LoginForm;
index 47fda24847440f208d7dcdb286c158adb306ca43..f41a3658c22d6c5fe9da90bed7c58dc041a3b174 100644 (file)
@@ -1,44 +1,44 @@
 import { Component } from "inferno";
 import { Link } from "inferno-router";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
+  CommunityModeratorView,
+  GetCommunity,
+  GetCommunityResponse,
   GetModlog,
   GetModlogResponse,
-  SiteView,
-  ModRemovePostView,
+  ModAddCommunityView,
+  ModAddView,
+  ModBanFromCommunityView,
+  ModBanView,
   ModLockPostView,
-  ModStickyPostView,
   ModRemoveCommentView,
   ModRemoveCommunityView,
-  ModBanFromCommunityView,
-  ModBanView,
-  ModAddCommunityView,
-  ModAddView,
-  GetCommunity,
-  GetCommunityResponse,
-  CommunityModeratorView,
+  ModRemovePostView,
+  ModStickyPostView,
+  SiteView,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
+import moment from "moment";
+import { Subscription } from "rxjs";
+import { i18n } from "../i18next";
+import { InitialFetchRequest } from "../interfaces";
+import { UserService, WebSocketService } from "../services";
 import {
-  wsJsonToRes,
   fetchLimit,
-  toast,
+  isBrowser,
   setIsoData,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
-  isBrowser,
   wsUserOp,
-  wsClient,
 } from "../utils";
-import { MomentTime } from "./moment-time";
-import { HtmlTags } from "./html-tags";
-import moment from "moment";
-import { i18n } from "../i18next";
-import { InitialFetchRequest } from "shared/interfaces";
-import { PersonListing } from "./person-listing";
-import { CommunityLink } from "./community-link";
-import { Spinner } from "./icon";
-import { Paginator } from "./paginator";
+import { HtmlTags } from "./common/html-tags";
+import { Spinner } from "./common/icon";
+import { MomentTime } from "./common/moment-time";
+import { Paginator } from "./common/paginator";
+import { CommunityLink } from "./community/community-link";
+import { PersonListing } from "./person/person-listing";
 
 enum ModlogEnum {
   ModRemovePost,
similarity index 86%
rename from src/shared/components/cake-day.tsx
rename to src/shared/components/person/cake-day.tsx
index 1eb32d9a70c23716ba67436bf950c672ef0a9ab4..91ee7c0c776261b460ffc7ca7189a8fb7e407989 100644 (file)
@@ -1,6 +1,6 @@
 import { Component } from "inferno";
-import { i18n } from "../i18next";
-import { Icon } from "./icon";
+import { i18n } from "../../i18next";
+import { Icon } from "../common/icon";
 
 interface CakeDayProps {
   creatorName: string;
similarity index 96%
rename from src/shared/components/inbox.tsx
rename to src/shared/components/person/inbox.tsx
index 674c6642f1dbff6c680337872b7afa3f3c55a1c7..10375874a4c6531359b665d44f7874b853d810f7 100644 (file)
@@ -1,47 +1,47 @@
 import { Component, linkEvent } from "inferno";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
+  CommentResponse,
   CommentView,
-  SortType,
-  GetReplies,
-  GetRepliesResponse,
   GetPersonMentions,
   GetPersonMentionsResponse,
-  PersonMentionResponse,
-  CommentResponse,
-  PrivateMessageView,
   GetPrivateMessages,
-  PrivateMessagesResponse,
+  GetReplies,
+  GetRepliesResponse,
+  PersonMentionResponse,
+  PersonMentionView,
   PrivateMessageResponse,
+  PrivateMessagesResponse,
+  PrivateMessageView,
   SiteView,
-  PersonMentionView,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { InitialFetchRequest } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  fetchLimit,
-  toast,
+  authField,
+  commentsToFlatNodes,
+  createCommentLikeRes,
   editCommentRes,
+  fetchLimit,
+  isBrowser,
   saveCommentRes,
-  createCommentLikeRes,
-  commentsToFlatNodes,
-  setupTippy,
   setIsoData,
+  setupTippy,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
-  isBrowser,
   wsUserOp,
-  wsClient,
-  authField,
-} from "../utils";
-import { CommentNodes } from "./comment-nodes";
-import { PrivateMessage } from "./private-message";
-import { HtmlTags } from "./html-tags";
-import { Paginator } from "./paginator";
-import { SortSelect } from "./sort-select";
-import { Icon, Spinner } from "./icon";
-import { i18n } from "../i18next";
-import { InitialFetchRequest } from "shared/interfaces";
+} from "../../utils";
+import { CommentNodes } from "../comment/comment-nodes";
+import { HtmlTags } from "../common/html-tags";
+import { Icon, Spinner } from "../common/icon";
+import { Paginator } from "../common/paginator";
+import { SortSelect } from "../common/sort-select";
+import { PrivateMessage } from "../private_message/private-message";
 
 enum UnreadOrAll {
   Unread,
@@ -149,7 +149,7 @@ export class Inbox extends Component<any, InboxState> {
                 title={this.documentTitle}
                 path={this.context.router.route.match.url}
               />
-              <h5 class="mb-1">
+              <h5 class="mb-2">
                 {i18n.t("inbox")}
                 <small>
                   <a
@@ -166,17 +166,12 @@ export class Inbox extends Component<any, InboxState> {
                 this.state.messages.length >
                 0 &&
                 this.state.unreadOrAll == UnreadOrAll.Unread && (
-                  <ul class="list-inline mb-1 text-muted small font-weight-bold">
-                    <li className="list-inline-item">
-                      <span
-                        class="pointer"
-                        role="button"
-                        onClick={linkEvent(this, this.markAllAsRead)}
-                      >
-                        {i18n.t("mark_all_as_read")}
-                      </span>
-                    </li>
-                  </ul>
+                  <button
+                    class="btn btn-secondary mb-2"
+                    onClick={linkEvent(this, this.markAllAsRead)}
+                  >
+                    {i18n.t("mark_all_as_read")}
+                  </button>
                 )}
               {this.selects()}
               {this.state.messageType == MessageType.All && this.all()}
similarity index 93%
rename from src/shared/components/person-details.tsx
rename to src/shared/components/person/person-details.tsx
index b729fb122af1f041f28ad351b52af226765b48d2..ccc055b947888b50c81d0940eca8164ee2fef6f1 100644 (file)
@@ -1,16 +1,16 @@
 import { Component } from "inferno";
 import {
-  PostView,
   CommentView,
-  SortType,
   GetPersonDetailsResponse,
   PersonViewSafe,
+  PostView,
+  SortType,
 } from "lemmy-js-client";
-import { PersonDetailsView } from "../interfaces";
-import { commentsToFlatNodes, setupTippy } from "../utils";
-import { PostListing } from "./post-listing";
-import { CommentNodes } from "./comment-nodes";
-import { Paginator } from "./paginator";
+import { PersonDetailsView } from "../../interfaces";
+import { commentsToFlatNodes, setupTippy } from "../../utils";
+import { CommentNodes } from "../comment/comment-nodes";
+import { Paginator } from "../common/paginator";
+import { PostListing } from "../post/post-listing";
 
 interface PersonDetailsProps {
   personRes: GetPersonDetailsResponse;
similarity index 94%
rename from src/shared/components/person-listing.tsx
rename to src/shared/components/person/person-listing.tsx
index 17265760d5880710a383f4aa8204e8b8f112647d..cfd416118a5a53854954677dd5a7de87bf7ec35b 100644 (file)
@@ -1,9 +1,9 @@
 import { Component } from "inferno";
 import { Link } from "inferno-router";
 import { PersonSafe } from "lemmy-js-client";
-import { showAvatars, hostname, isCakeDay } from "../utils";
+import { hostname, isCakeDay, showAvatars } from "../../utils";
+import { PictrsImage } from "../common/pictrs-image";
 import { CakeDay } from "./cake-day";
-import { PictrsImage } from "./pictrs-image";
 
 interface PersonListingProps {
   person: PersonSafe;
similarity index 98%
rename from src/shared/components/person.tsx
rename to src/shared/components/person/person.tsx
index 8c046320a7bd52acc466a2f8749d5a63c8efd0d5..a314a30714a47b1b080d5fa4a8243ea303a4ad01 100644 (file)
@@ -1,69 +1,69 @@
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
-import { Subscription } from "rxjs";
 import ISO6391 from "iso-639-1";
 import {
-  UserOperation,
-  SortType,
-  ListingType,
-  SaveUserSettings,
-  LoginResponse,
-  DeleteAccount,
-  GetSiteResponse,
-  GetPersonDetailsResponse,
   AddAdminResponse,
-  GetPersonDetails,
-  CommentResponse,
-  PostResponse,
   BanPersonResponse,
   ChangePassword,
+  CommentResponse,
+  DeleteAccount,
+  GetPersonDetails,
+  GetPersonDetailsResponse,
+  GetSiteResponse,
+  ListingType,
+  LoginResponse,
+  PostResponse,
+  SaveUserSettings,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
-import { InitialFetchRequest, PersonDetailsView } from "../interfaces";
-import { WebSocketService, UserService } from "../services";
+import moment from "moment";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { InitialFetchRequest, PersonDetailsView } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  fetchLimit,
-  routeSortTypeToEnum,
+  authField,
   capitalizeFirstLetter,
-  themes,
-  setTheme,
-  languages,
-  toast,
-  setupTippy,
-  getLanguage,
-  mdToHtml,
+  createCommentLikeRes,
+  createPostLikeFindRes,
+  editCommentRes,
+  editPostFindRes,
   elementUrl,
-  setIsoData,
+  fetchLimit,
   getIdFromProps,
+  getLanguage,
   getUsernameFromProps,
-  wsSubscribe,
-  createCommentLikeRes,
-  editCommentRes,
-  saveCommentRes,
-  createPostLikeFindRes,
+  languages,
+  mdToHtml,
   previewLines,
-  editPostFindRes,
-  wsUserOp,
-  wsClient,
-  authField,
-  setOptionalAuth,
-  saveScrollPosition,
   restoreScrollPosition,
+  routeSortTypeToEnum,
+  saveCommentRes,
+  saveScrollPosition,
+  setIsoData,
+  setOptionalAuth,
+  setTheme,
+  setupTippy,
   showLocal,
-} from "../utils";
-import { PersonListing } from "./person-listing";
-import { HtmlTags } from "./html-tags";
-import { SortSelect } from "./sort-select";
-import { ListingTypeSelect } from "./listing-type-select";
-import { MomentTime } from "./moment-time";
-import { i18n } from "../i18next";
-import moment from "moment";
+  themes,
+  toast,
+  wsClient,
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
+} from "../../utils";
+import { BannerIconHeader } from "../common/banner-icon-header";
+import { HtmlTags } from "../common/html-tags";
+import { Icon, Spinner } from "../common/icon";
+import { ImageUploadForm } from "../common/image-upload-form";
+import { ListingTypeSelect } from "../common/listing-type-select";
+import { MarkdownTextArea } from "../common/markdown-textarea";
+import { MomentTime } from "../common/moment-time";
+import { SortSelect } from "../common/sort-select";
+import { CommunityLink } from "../community/community-link";
 import { PersonDetails } from "./person-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";
+import { PersonListing } from "./person-listing";
 
 interface PersonState {
   personRes: GetPersonDetailsResponse;
similarity index 96%
rename from src/shared/components/create-post.tsx
rename to src/shared/components/post/create-post.tsx
index 756dd9b4a31e75d8e2be88567e6f95a7ee0cced6..edd768dee2761773624ff7e4daf8723ce9887ee2 100644 (file)
@@ -1,8 +1,20 @@
 import { Component } from "inferno";
+import {
+  CommunityView,
+  GetCommunity,
+  GetCommunityResponse,
+  ListCommunities,
+  ListCommunitiesResponse,
+  ListingType,
+  PostView,
+  SiteView,
+  SortType,
+  UserOperation,
+} from "lemmy-js-client";
 import { Subscription } from "rxjs";
-import { PostForm } from "./post-form";
-import { HtmlTags } from "./html-tags";
-import { Spinner } from "./icon";
+import { InitialFetchRequest, PostFormParams } from "shared/interfaces";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
 import {
   authField,
   fetchLimit,
@@ -14,22 +26,10 @@ import {
   wsJsonToRes,
   wsSubscribe,
   wsUserOp,
-} from "../utils";
-import { UserService, WebSocketService } from "../services";
-import {
-  UserOperation,
-  ListCommunitiesResponse,
-  CommunityView,
-  SiteView,
-  ListCommunities,
-  SortType,
-  ListingType,
-  PostView,
-  GetCommunity,
-  GetCommunityResponse,
-} from "lemmy-js-client";
-import { i18n } from "../i18next";
-import { InitialFetchRequest, PostFormParams } from "shared/interfaces";
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { PostForm } from "./post-form";
 
 interface CreatePostState {
   site_view: SiteView;
similarity index 97%
rename from src/shared/components/iframely-card.tsx
rename to src/shared/components/post/iframely-card.tsx
index 4b1e4ebe6cd67663e4e0ccc3b9a86a726f1c5652..bf31694d0ea25615bd638616c99e1c891045b107 100644 (file)
@@ -1,7 +1,7 @@
 import { Component, linkEvent } from "inferno";
 import { Post } from "lemmy-js-client";
-import { i18n } from "../i18next";
-import { Icon } from "./icon";
+import { i18n } from "../../i18next";
+import { Icon } from "../common/icon";
 
 interface FramelyCardProps {
   post: Post;
similarity index 98%
rename from src/shared/components/post-form.tsx
rename to src/shared/components/post/post-form.tsx
index b267b4508f682807af389094fc804b38885ee100..cf39887686e225e244a4afc84e0919c977860a54 100644 (file)
@@ -1,56 +1,55 @@
+import autosize from "autosize";
 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 {
+  CommunityView,
   CreatePost,
   EditPost,
-  PostView,
+  ListingType,
   PostResponse,
-  UserOperation,
-  CommunityView,
-  SortType,
+  PostView,
   Search,
-  SearchType,
   SearchResponse,
-  ListingType,
+  SearchType,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
-import { PostFormParams } from "../interfaces";
+import { Subscription } from "rxjs";
+import { pictrsUri } from "../../env";
+import { i18n } from "../../i18next";
+import { PostFormParams } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  getPageTitle,
-  validURL,
-  capitalizeFirstLetter,
   archiveUrl,
+  authField,
+  capitalizeFirstLetter,
+  choicesConfig,
+  communitySelectName,
+  communityToChoice,
   debounce,
+  fetchCommunities,
+  getPageTitle,
+  isBrowser,
   isImage,
-  toast,
-  setupTippy,
   pictrsDeleteToast,
+  setupTippy,
+  toast,
   validTitle,
+  validURL,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
-  isBrowser,
   wsUserOp,
-  wsClient,
-  authField,
-  communityToChoice,
-  fetchCommunities,
-  choicesConfig,
-  communitySelectName,
-} from "../utils";
-import autosize from "autosize";
+} from "../../utils";
+import { Icon, Spinner } from "../common/icon";
+import { MarkdownTextArea } from "../common/markdown-textarea";
+import { PostListings } from "./post-listings";
 
-var Choices;
+var Choices: any;
 if (isBrowser()) {
   Choices = require("choices.js");
 }
 
-import { i18n } from "../i18next";
-import { pictrsUri } from "../env";
-
 const MAX_POST_TITLE_LENGTH = 200;
 
 interface PostFormProps {
similarity index 98%
rename from src/shared/components/post-listing.tsx
rename to src/shared/components/post/post-listing.tsx
index e62144b1143b28b33ff338863a78bf88c6d01935..2350f9bebefb997b61a25581dd5790be2406e0bc 100644 (file)
@@ -1,48 +1,48 @@
 import { Component, linkEvent } from "inferno";
 import { Link } from "inferno-router";
-import { WebSocketService, UserService } from "../services";
 import {
-  PostView,
+  AddAdmin,
+  AddModToCommunity,
+  BanFromCommunity,
+  BanPerson,
+  CommunityModeratorView,
   CreatePostLike,
   DeletePost,
-  RemovePost,
   LockPost,
-  StickyPost,
-  SavePost,
   PersonViewSafe,
-  BanFromCommunity,
-  BanPerson,
-  AddModToCommunity,
-  AddAdmin,
-  TransferSite,
+  PostView,
+  RemovePost,
+  SavePost,
+  StickyPost,
   TransferCommunity,
-  CommunityModeratorView,
+  TransferSite,
 } from "lemmy-js-client";
-import { BanType } from "../interfaces";
-import { MomentTime } from "./moment-time";
-import { PostForm } from "./post-form";
-import { IFramelyCard } from "./iframely-card";
-import { PersonListing } from "./person-listing";
-import { CommunityLink } from "./community-link";
-import { PictrsImage } from "./pictrs-image";
-import { Icon } from "./icon";
+import { externalHost } from "../../env";
+import { i18n } from "../../i18next";
+import { BanType } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  md,
-  mdToHtml,
+  authField,
   canMod,
-  isMod,
-  isImage,
-  isVideo,
   getUnixTime,
-  setupTippy,
   hostname,
+  isImage,
+  isMod,
+  isVideo,
+  md,
+  mdToHtml,
   previewLines,
-  wsClient,
-  authField,
+  setupTippy,
   showScores,
-} from "../utils";
-import { i18n } from "../i18next";
-import { externalHost } from "../env";
+  wsClient,
+} from "../../utils";
+import { Icon } from "../common/icon";
+import { MomentTime } from "../common/moment-time";
+import { PictrsImage } from "../common/pictrs-image";
+import { CommunityLink } from "../community/community-link";
+import { PersonListing } from "../person/person-listing";
+import { IFramelyCard } from "./iframely-card";
+import { PostForm } from "./post-form";
 
 interface PostListingState {
   showEdit: boolean;
@@ -398,28 +398,28 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
           )}
           {(isImage(post.url) || post.thumbnail_url) &&
             (!this.state.imageExpanded ? (
-              <span
-                class="text-monospace unselectable pointer ml-2 text-muted small"
+              <button
+                class="btn btn-link text-monospace text-muted small d-inline-block ml-2"
                 data-tippy-content={i18n.t("expand_here")}
                 onClick={linkEvent(this, this.handleImageExpandClick)}
               >
                 <Icon icon="plus-square" classes="icon-inline" />
-              </span>
+              </button>
             ) : (
               <span>
-                <span
-                  class="text-monospace unselectable pointer ml-2 text-muted small"
+                <button
+                  class="btn btn-link text-monospace text-muted small d-inline-block ml-2"
                   onClick={linkEvent(this, this.handleImageExpandClick)}
                 >
                   <Icon icon="minus-square" classes="icon-inline" />
-                </span>
+                </button>
                 <div>
-                  <span
-                    class="pointer"
+                  <button
+                    class="btn btn-link d-inline-block"
                     onClick={linkEvent(this, this.handleImageExpandClick)}
                   >
                     <PictrsImage src={this.getImageSrc()} />
-                  </span>
+                  </button>
                 </div>
               </span>
             ))}
similarity index 98%
rename from src/shared/components/post-listings.tsx
rename to src/shared/components/post/post-listings.tsx
index 2adc9f0516cdc00275a7e58c0da237c9eaa169fe..3dc8260ed871c5c220930e01bc672bb8ac7f7d1b 100644 (file)
@@ -1,9 +1,9 @@
 import { Component } from "inferno";
+import { T } from "inferno-i18next";
 import { Link } from "inferno-router";
 import { PostView } from "lemmy-js-client";
+import { i18n } from "../../i18next";
 import { PostListing } from "./post-listing";
-import { i18n } from "../i18next";
-import { T } from "inferno-i18next";
 
 interface PostListingsProps {
   posts: PostView[];
similarity index 97%
rename from src/shared/components/post.tsx
rename to src/shared/components/post/post.tsx
index b8aa0c30771730ab56740c631a6222d7c67c830c..6bd6419889e4f5bd206a7226ba38f4e9b833053b 100644 (file)
@@ -1,66 +1,66 @@
+import autosize from "autosize";
 import { Component, linkEvent } from "inferno";
-import { HtmlTags } from "./html-tags";
-import { Spinner } from "./icon";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
-  PostView,
-  GetPostResponse,
-  PostResponse,
-  MarkCommentAsRead,
-  CommentResponse,
-  CommunityResponse,
+  AddAdminResponse,
+  AddModToCommunityResponse,
   BanFromCommunityResponse,
   BanPersonResponse,
-  AddModToCommunityResponse,
-  AddAdminResponse,
-  SearchType,
-  SortType,
-  Search,
+  CommentResponse,
+  CommunityResponse,
+  GetCommunityResponse,
   GetPost,
-  SearchResponse,
+  GetPostResponse,
   GetSiteResponse,
-  GetCommunityResponse,
   ListingType,
+  MarkCommentAsRead,
+  PostResponse,
+  PostView,
+  Search,
+  SearchResponse,
+  SearchType,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
 import {
+  CommentNode as CommentNodeI,
   CommentSortType,
   CommentViewType,
   InitialFetchRequest,
-  CommentNode as CommentNodeI,
-} from "../interfaces";
-import { WebSocketService, UserService } from "../services";
+} from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
-  wsJsonToRes,
-  toast,
-  editCommentRes,
-  saveCommentRes,
+  authField,
+  buildCommentsTree,
+  commentsToFlatNodes,
   createCommentLikeRes,
   createPostLikeRes,
-  commentsToFlatNodes,
-  setupTippy,
-  setIsoData,
-  getIdFromProps,
+  editCommentRes,
   getCommentIdFromProps,
-  wsSubscribe,
+  getIdFromProps,
+  insertCommentIntoTree,
   isBrowser,
-  previewLines,
   isImage,
-  wsUserOp,
-  wsClient,
-  authField,
-  setOptionalAuth,
-  saveScrollPosition,
+  previewLines,
   restoreScrollPosition,
-  buildCommentsTree,
-  insertCommentIntoTree,
-} from "../utils";
+  saveCommentRes,
+  saveScrollPosition,
+  setIsoData,
+  setOptionalAuth,
+  setupTippy,
+  toast,
+  wsClient,
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
+} from "../../utils";
+import { CommentForm } from "../comment/comment-form";
+import { CommentNodes } from "../comment/comment-nodes";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { Sidebar } from "../community/sidebar";
 import { PostListing } from "./post-listing";
-import { Sidebar } from "./sidebar";
-import { CommentForm } from "./comment-form";
-import { CommentNodes } from "./comment-nodes";
-import autosize from "autosize";
-import { i18n } from "../i18next";
 
 interface PostState {
   postRes: GetPostResponse;
similarity index 93%
rename from src/shared/components/create-private-message.tsx
rename to src/shared/components/private_message/create-private-message.tsx
index 0796d3e7d2d23c7b42b30622345f8c3c544f33e7..5bd6a486d006588ee5f35310c5d434471feb90fd 100644 (file)
@@ -1,17 +1,16 @@
 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,
-  UserOperation,
+  GetPersonDetails,
   GetPersonDetailsResponse,
   PersonViewSafe,
+  SiteView,
   SortType,
-  GetPersonDetails,
+  UserOperation,
 } from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { InitialFetchRequest } from "../../interfaces";
+import { UserService, WebSocketService } from "../../services";
 import {
   authField,
   getRecipientIdFromProps,
@@ -22,9 +21,10 @@ import {
   wsJsonToRes,
   wsSubscribe,
   wsUserOp,
-} from "../utils";
-import { i18n } from "../i18next";
-import { InitialFetchRequest } from "shared/interfaces";
+} from "../../utils";
+import { HtmlTags } from "../common/html-tags";
+import { Spinner } from "../common/icon";
+import { PrivateMessageForm } from "./private-message-form";
 
 interface CreatePrivateMessageState {
   site_view: SiteView;
similarity index 93%
rename from src/shared/components/private-message-form.tsx
rename to src/shared/components/private_message/private-message-form.tsx
index a19095d761338747a1c8bc2dbb68704c8053f838..542c48b7dbee2f0cef61b959a09689f2c5efe33f 100644 (file)
@@ -1,31 +1,31 @@
 import { Component, linkEvent } from "inferno";
+import { T } from "inferno-i18next";
 import { Prompt } from "inferno-router";
-import { Subscription } from "rxjs";
 import {
   CreatePrivateMessage,
   EditPrivateMessage,
-  PrivateMessageView,
-  PrivateMessageResponse,
   PersonSafe,
+  PrivateMessageResponse,
+  PrivateMessageView,
   UserOperation,
 } from "lemmy-js-client";
-import { WebSocketService } from "../services";
+import { Subscription } from "rxjs";
+import { i18n } from "../../i18next";
+import { WebSocketService } from "../../services";
 import {
+  authField,
   capitalizeFirstLetter,
-  wsJsonToRes,
-  toast,
+  isBrowser,
   setupTippy,
+  toast,
+  wsClient,
+  wsJsonToRes,
   wsSubscribe,
-  isBrowser,
   wsUserOp,
-  wsClient,
-  authField,
-} from "../utils";
-import { PersonListing } from "./person-listing";
-import { MarkdownTextArea } from "./markdown-textarea";
-import { Icon, Spinner } from "./icon";
-import { i18n } from "../i18next";
-import { T } from "inferno-i18next";
+} from "../../utils";
+import { Icon, Spinner } from "../common/icon";
+import { MarkdownTextArea } from "../common/markdown-textarea";
+import { PersonListing } from "../person/person-listing";
 
 interface PrivateMessageFormProps {
   recipient: PersonSafe;
@@ -70,7 +70,8 @@ export class PrivateMessageForm extends Component<
 
     // Its an edit
     if (this.props.privateMessage) {
-      this.state.privateMessageForm.content = this.props.privateMessage.private_message.content;
+      this.state.privateMessageForm.content =
+        this.props.privateMessage.private_message.content;
     }
   }
 
@@ -115,15 +116,14 @@ export class PrivateMessageForm extends Component<
           <div class="form-group row">
             <label class="col-sm-2 col-form-label">
               {i18n.t("message")}
-              <span
+              <button
+                class="btn btn-link text-warning d-inline-block"
                 onClick={linkEvent(this, this.handleShowDisclaimer)}
-                role="button"
-                class="ml-2 pointer text-danger"
                 data-tippy-content={i18n.t("private_message_disclaimer")}
                 aria-label={i18n.t("private_message_disclaimer")}
               >
                 <Icon icon="alert-triangle" classes="icon-inline" />
-              </span>
+              </button>
             </label>
             <div class="col-sm-10">
               <MarkdownTextArea
similarity index 95%
rename from src/shared/components/private-message.tsx
rename to src/shared/components/private_message/private-message.tsx
index 664fe89fa5fe7885198c93cc6d2e9e108ca017a2..533a694a95672097001ad83d90cebeafbd95ec85 100644 (file)
@@ -1,17 +1,17 @@
 import { Component, linkEvent } from "inferno";
 import {
-  PrivateMessageView,
   DeletePrivateMessage,
   MarkPrivateMessageAsRead,
   PersonSafe,
+  PrivateMessageView,
 } from "lemmy-js-client";
-import { WebSocketService, UserService } from "../services";
-import { authField, mdToHtml, toast, wsClient } from "../utils";
-import { MomentTime } from "./moment-time";
+import { i18n } from "../../i18next";
+import { UserService, WebSocketService } from "../../services";
+import { authField, mdToHtml, toast, wsClient } from "../../utils";
+import { Icon } from "../common/icon";
+import { MomentTime } from "../common/moment-time";
+import { PersonListing } from "../person/person-listing";
 import { PrivateMessageForm } from "./private-message-form";
-import { PersonListing } from "./person-listing";
-import { Icon } from "./icon";
-import { i18n } from "../i18next";
 
 interface PrivateMessageState {
   showReply: boolean;
@@ -40,9 +40,8 @@ export class PrivateMessage extends Component<
 
     this.state = this.emptyState;
     this.handleReplyCancel = this.handleReplyCancel.bind(this);
-    this.handlePrivateMessageCreate = this.handlePrivateMessageCreate.bind(
-      this
-    );
+    this.handlePrivateMessageCreate =
+      this.handlePrivateMessageCreate.bind(this);
     this.handlePrivateMessageEdit = this.handlePrivateMessageEdit.bind(this);
   }
 
index 78d80722a05066f76803bb2d37a95d91f87fd2dd..61c3000edd249552b1681944d6996b05eb77457b 100644 (file)
@@ -1,68 +1,68 @@
 import { Component, linkEvent } from "inferno";
-import { Subscription } from "rxjs";
 import {
-  UserOperation,
-  PostView,
+  CommentResponse,
   CommentView,
   CommunityView,
+  GetCommunity,
+  GetPersonDetails,
+  ListCommunities,
+  ListCommunitiesResponse,
+  ListingType,
   PersonViewSafe,
-  SortType,
+  PostResponse,
+  PostView,
   Search as SearchForm,
   SearchResponse,
   SearchType,
-  PostResponse,
-  CommentResponse,
   Site,
-  ListingType,
-  ListCommunities,
-  ListCommunitiesResponse,
-  GetCommunity,
-  GetPersonDetails,
+  SortType,
+  UserOperation,
 } from "lemmy-js-client";
+import { Subscription } from "rxjs";
+import { InitialFetchRequest } from "shared/interfaces";
+import { i18n } from "../i18next";
 import { WebSocketService } from "../services";
 import {
-  wsJsonToRes,
-  fetchLimit,
-  routeSearchTypeToEnum,
-  routeSortTypeToEnum,
-  toast,
-  createCommentLikeRes,
-  createPostLikeFindRes,
-  commentsToFlatNodes,
-  setIsoData,
-  wsSubscribe,
-  wsUserOp,
-  wsClient,
   authField,
-  setOptionalAuth,
-  saveScrollPosition,
-  restoreScrollPosition,
-  routeListingTypeToEnum,
-  showLocal,
-  isBrowser,
+  capitalizeFirstLetter,
   choicesConfig,
+  commentsToFlatNodes,
+  communitySelectName,
+  communityToChoice,
+  createCommentLikeRes,
+  createPostLikeFindRes,
   debounce,
   fetchCommunities,
-  communityToChoice,
+  fetchLimit,
   fetchUsers,
-  personToChoice,
-  capitalizeFirstLetter,
-  communitySelectName,
+  isBrowser,
   personSelectName,
+  personToChoice,
+  restoreScrollPosition,
+  routeListingTypeToEnum,
+  routeSearchTypeToEnum,
+  routeSortTypeToEnum,
+  saveScrollPosition,
+  setIsoData,
+  setOptionalAuth,
+  showLocal,
+  toast,
+  wsClient,
+  wsJsonToRes,
+  wsSubscribe,
+  wsUserOp,
 } from "../utils";
-import { PostListing } from "./post-listing";
-import { HtmlTags } from "./html-tags";
-import { Spinner } from "./icon";
-import { PersonListing } from "./person-listing";
-import { CommunityLink } from "./community-link";
-import { SortSelect } from "./sort-select";
-import { ListingTypeSelect } from "./listing-type-select";
-import { CommentNodes } from "./comment-nodes";
-import { Paginator } from "./paginator";
-import { i18n } from "../i18next";
-import { InitialFetchRequest } from "shared/interfaces";
-
-var Choices;
+import { CommentNodes } from "./comment/comment-nodes";
+import { HtmlTags } from "./common/html-tags";
+import { Spinner } from "./common/icon";
+import { ListingTypeSelect } from "./common/listing-type-select";
+import { Paginator } from "./common/paginator";
+import { SortSelect } from "./common/sort-select";
+import { CommunityLink } from "./community/community-link";
+import { PersonListing } from "./person/person-listing";
+import { PostListing } from "./post/post-listing";
+
+var Choices: any;
 if (isBrowser()) {
   Choices = require("choices.js");
 }
diff --git a/src/shared/components/styles.scss b/src/shared/components/styles.scss
deleted file mode 100644 (file)
index 010fb6d..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-// Custom css
-@import "../../../node_modules/tributejs/dist/tribute.css";
-@import "../../../node_modules/toastify-js/src/toastify.css";
-@import "../../../node_modules/choices.js/src/styles/choices.scss";
-@import "../../../node_modules/tippy.js/dist/tippy.css";
-@import "../../assets/css/main.css";
index 6db9dd1f6f4496c167fe2f317c5eff86ce459eb9..565bf033de68c430c4e850c7b88e7457ee6b1be4 100644 (file)
@@ -1,43 +1,43 @@
 import i18next, { i18nTyped } from "i18next";
-import { getLanguage } from "./utils";
-import { en } from "./translations/en";
+import { ar } from "./translations/ar";
+import { bg } from "./translations/bg";
+import { ca } from "./translations/ca";
+import { da } from "./translations/da";
+import { de } from "./translations/de";
 import { el } from "./translations/el";
-import { eu } from "./translations/eu";
+import { en } from "./translations/en";
 import { eo } from "./translations/eo";
 import { es } from "./translations/es";
-import { de } from "./translations/de";
-import { fr } from "./translations/fr";
-import { sv } from "./translations/sv";
-import { ru } from "./translations/ru";
-import { zh } from "./translations/zh";
-import { nl } from "./translations/nl";
-import { it } from "./translations/it";
-import { fi } from "./translations/fi";
-import { ca } from "./translations/ca";
+import { eu } from "./translations/eu";
 import { fa } from "./translations/fa";
+import { fi } from "./translations/fi";
+import { fr } from "./translations/fr";
+import { ga } from "./translations/ga";
+import { gl } from "./translations/gl";
 import { hi } from "./translations/hi";
-import { pl } from "./translations/pl";
-import { pt_BR } from "./translations/pt_BR";
+import { hr } from "./translations/hr";
+import { hu } from "./translations/hu";
+import { id } from "./translations/id";
+import { it } from "./translations/it";
 import { ja } from "./translations/ja";
 import { ka } from "./translations/ka";
-import { gl } from "./translations/gl";
-import { tr } from "./translations/tr";
-import { hu } from "./translations/hu";
-import { uk } from "./translations/uk";
-import { sq } from "./translations/sq";
 import { km } from "./translations/km";
-import { ga } from "./translations/ga";
-import { sr_Latn } from "./translations/sr_Latn";
-import { da } from "./translations/da";
-import { oc } from "./translations/oc";
-import { hr } from "./translations/hr";
-import { th } from "./translations/th";
-import { bg } from "./translations/bg";
-import { ar } from "./translations/ar";
 import { ko } from "./translations/ko";
-import { id } from "./translations/id";
 import { nb_NO } from "./translations/nb_NO";
+import { nl } from "./translations/nl";
+import { oc } from "./translations/oc";
+import { pl } from "./translations/pl";
+import { pt_BR } from "./translations/pt_BR";
+import { ru } from "./translations/ru";
+import { sq } from "./translations/sq";
+import { sr_Latn } from "./translations/sr_Latn";
+import { sv } from "./translations/sv";
+import { th } from "./translations/th";
+import { tr } from "./translations/tr";
+import { uk } from "./translations/uk";
+import { zh } from "./translations/zh";
 import { zh_Hant } from "./translations/zh_Hant";
+import { getLanguage } from "./utils";
 
 // https://github.com/nimbusec-oss/inferno-i18next/blob/master/tests/T.test.js#L66
 const resources = {
diff --git a/src/shared/initialize.ts b/src/shared/initialize.ts
deleted file mode 100644 (file)
index 3b8bab9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-import { GetSiteResponse } from "lemmy-js-client";
-import { UserService } from "./services";
-import { i18n } from "./i18next";
-import { getLanguage } from "./utils";
-
-export function initializeSite(site: GetSiteResponse) {
-  UserService.Instance.localUserView = site.my_user;
-  i18n.changeLanguage(getLanguage());
-}
index cae8c5090b1db8e038cd3d64bc4b62872320ecf2..ff5d6a192e7f2a8474f93445b863028cea65f53b 100644 (file)
@@ -1,20 +1,20 @@
 import { IRouteProps } from "inferno-router/dist/Route";
-import { Main } from "./components/main";
-import { Login } from "./components/login";
-import { CreatePost } from "./components/create-post";
-import { CreateCommunity } from "./components/create-community";
-import { CreatePrivateMessage } from "./components/create-private-message";
-import { PasswordChange } from "./components/password_change";
-import { Post } from "./components/post";
-import { Community } from "./components/community";
-import { Communities } from "./components/communities";
-import { Person } from "./components/person";
+import { Communities } from "./components/community/communities";
+import { Community } from "./components/community/community";
+import { CreateCommunity } from "./components/community/create-community";
+import { AdminSettings } from "./components/home/admin-settings";
+import { Home } from "./components/home/home";
+import { Instances } from "./components/home/instances";
+import { Login } from "./components/home/login";
+import { PasswordChange } from "./components/home/password_change";
+import { Setup } from "./components/home/setup";
 import { Modlog } from "./components/modlog";
-import { Setup } from "./components/setup";
-import { AdminSettings } from "./components/admin-settings";
-import { Inbox } from "./components/inbox";
+import { Inbox } from "./components/person/inbox";
+import { Person } from "./components/person/person";
+import { CreatePost } from "./components/post/create-post";
+import { Post } from "./components/post/post";
+import { CreatePrivateMessage } from "./components/private_message/create-private-message";
 import { Search } from "./components/search";
-import { Instances } from "./components/instances";
 import { InitialFetchRequest } from "./interfaces";
 
 interface IRoutePropsWithFetch extends IRouteProps {
@@ -25,13 +25,13 @@ export const routes: IRoutePropsWithFetch[] = [
   {
     path: `/`,
     exact: true,
-    component: Main,
-    fetchInitialData: req => Main.fetchInitialData(req),
+    component: Home,
+    fetchInitialData: req => Home.fetchInitialData(req),
   },
   {
     path: `/home/data_type/:data_type/listing_type/:listing_type/sort/:sort/page/:page`,
-    component: Main,
-    fetchInitialData: req => Main.fetchInitialData(req),
+    component: Home,
+    fetchInitialData: req => Home.fetchInitialData(req),
   },
   {
     path: `/login`,
index e89657a8a73b5bf9db245e77a04a2aff57d1ec60..355e802844f3d758dc0fe3082ea2f3c34db35ff7 100644 (file)
@@ -1,8 +1,8 @@
 // import Cookies from 'js-cookie';
 import IsomorphicCookie from "isomorphic-cookie";
-import { LocalUserSettingsView, LoginResponse } from "lemmy-js-client";
 import jwt_decode from "jwt-decode";
-import { Subject, BehaviorSubject } from "rxjs";
+import { LocalUserSettingsView, LoginResponse } from "lemmy-js-client";
+import { BehaviorSubject, Subject } from "rxjs";
 
 interface Claims {
   sub: number;
index 3cb3748687f10498bf97f100729eb7acd266fd10..813503960aec6dc5d445958a600af8a3d6e04e91 100644 (file)
@@ -1,12 +1,12 @@
-import { wsUri } from "../env";
 import { PersonViewSafe, WebSocketJsonResponse } from "lemmy-js-client";
-import { isBrowser } from "../utils";
-import { Observable } from "rxjs";
-import { share } from "rxjs/operators";
 import {
-  Options as WSOptions,
   default as ReconnectingWebSocket,
+  Options as WSOptions,
 } from "reconnecting-websocket";
+import { Observable } from "rxjs";
+import { share } from "rxjs/operators";
+import { wsUri } from "../env";
+import { isBrowser } from "../utils";
 
 export class WebSocketService {
   private static _instance: WebSocketService;
index aad9745c8c8da9fd5de12b741383b7f2e79268b9..931f2f1fb5bab60bb00d89e34a3ec2ac5801f718 100644 (file)
@@ -1,79 +1,79 @@
-import "moment/locale/es";
+import emojiShortName from "emoji-short-name";
+import {
+  CommentView,
+  CommunityView,
+  GetSiteResponse,
+  LemmyHttp,
+  LemmyWebsocket,
+  ListingType,
+  LocalUserSettingsView,
+  PersonViewSafe,
+  PostView,
+  PrivateMessageView,
+  Search,
+  SearchResponse,
+  SearchType,
+  SortType,
+  UserOperation,
+  WebSocketJsonResponse,
+  WebSocketResponse,
+} from "lemmy-js-client";
+import markdown_it from "markdown-it";
+import markdown_it_container from "markdown-it-container";
+import markdown_it_sub from "markdown-it-sub";
+import markdown_it_sup from "markdown-it-sup";
+import moment from "moment";
+import "moment/locale/bg";
+import "moment/locale/ca";
+import "moment/locale/da";
+import "moment/locale/de";
 import "moment/locale/el";
-import "moment/locale/eu";
 import "moment/locale/eo";
-import "moment/locale/de";
-import "moment/locale/zh-cn";
+import "moment/locale/es";
+import "moment/locale/eu";
+import "moment/locale/fa";
+import "moment/locale/fi";
 import "moment/locale/fr";
-import "moment/locale/sv";
-import "moment/locale/ru";
-import "moment/locale/nl";
+import "moment/locale/ga";
+import "moment/locale/gl";
+import "moment/locale/hi";
+import "moment/locale/hr";
+import "moment/locale/hu";
+import "moment/locale/id";
 import "moment/locale/it";
-import "moment/locale/fi";
-import "moment/locale/ca";
-import "moment/locale/fa";
-import "moment/locale/pl";
-import "moment/locale/pt-br";
 import "moment/locale/ja";
 import "moment/locale/ka";
-import "moment/locale/hi";
-import "moment/locale/gl";
-import "moment/locale/tr";
-import "moment/locale/hu";
-import "moment/locale/uk";
-import "moment/locale/sq";
 import "moment/locale/km";
-import "moment/locale/ga";
-import "moment/locale/sr";
 import "moment/locale/ko";
-import "moment/locale/da";
-import "moment/locale/hr";
-import "moment/locale/bg";
-import "moment/locale/id";
 import "moment/locale/nb";
-
-import {
-  UserOperation,
-  CommentView,
-  LocalUserSettingsView,
-  SortType,
-  ListingType,
-  SearchType,
-  WebSocketResponse,
-  WebSocketJsonResponse,
-  Search,
-  SearchResponse,
-  PostView,
-  PrivateMessageView,
-  LemmyWebsocket,
-  PersonViewSafe,
-  CommunityView,
-  LemmyHttp,
-} from "lemmy-js-client";
-
+import "moment/locale/nl";
+import "moment/locale/pl";
+import "moment/locale/pt-br";
+import "moment/locale/ru";
+import "moment/locale/sq";
+import "moment/locale/sr";
+import "moment/locale/sv";
+import "moment/locale/tr";
+import "moment/locale/uk";
+import "moment/locale/zh-cn";
+import { Subscription } from "rxjs";
+import { delay, retryWhen, take } from "rxjs/operators";
+import tippy from "tippy.js";
+import Toastify from "toastify-js";
+import { httpBase } from "./env";
+import { i18n } from "./i18next";
 import {
+  CommentNode as CommentNodeI,
   CommentSortType,
   DataType,
   IsoData,
-  CommentNode as CommentNodeI,
 } from "./interfaces";
 import { UserService, WebSocketService } from "./services";
+
 var Tribute: any;
 if (isBrowser()) {
   Tribute = require("tributejs");
 }
-import markdown_it from "markdown-it";
-import markdown_it_sub from "markdown-it-sub";
-import markdown_it_sup from "markdown-it-sup";
-import markdown_it_container from "markdown-it-container";
-import emojiShortName from "emoji-short-name";
-import Toastify from "toastify-js";
-import tippy from "tippy.js";
-import moment from "moment";
-import { Subscription } from "rxjs";
-import { retryWhen, delay, take } from "rxjs/operators";
-import { i18n } from "./i18next";
-import { httpBase } from "./env";
 
 export const wsClient = new LemmyWebsocket();
 
@@ -1343,3 +1343,8 @@ export function personSelectName(pvs: PersonViewSafe): string {
     ? pvs.person.name
     : `${hostname(pvs.person.actor_id)}/${pvs.person.name}`;
 }
+
+export function initializeSite(site: GetSiteResponse) {
+  UserService.Instance.localUserView = site.my_user;
+  i18n.changeLanguage(getLanguage());
+}
index a47bd02bd521837f7b51d4f6b4a77b5d8ce949ef..9ed1bffa179fd4a3ed516b9e3ef32215107d2cc7 100644 (file)
--- a/yarn.lock
+++ b/yarn.lock
@@ -45,7 +45,7 @@
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.14.7.tgz#7b047d7a3a89a67d2258dc61f604f098f1bc7e08"
   integrity sha512-nS6dZaISCXJ3+518CWiBfEr//gHyMO02uDxBkXTKZDN5POruCnOZ1N4YBRZDCabwF8nZMWBpRxIicmXtBs+fvw==
 
-"@babel/core@^7.14.6":
+"@babel/core@^7.14.6", "@babel/core@^7.2.2":
   version "7.14.6"
   resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.14.6.tgz#e0814ec1a950032ff16c13a2721de39a8416fcab"
   integrity sha512-gJnOEWSqTk96qG5BoIrl5bVtc23DCycmIePPYnamY9RboYdI4nFy5vAQMSl81O5K/W0sLDWfGysnOECC+KUUCA==
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/parser@^7.0.0-beta.54", "@babel/parser@^7.14.5", "@babel/parser@^7.14.6", "@babel/parser@^7.14.7":
+  version "7.14.7"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.7.tgz#6099720c8839ca865a2637e6c85852ead0bdb595"
+  integrity sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==
+
 "@babel/parser@^7.12.13":
   version "7.12.15"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.12.15.tgz#2b20de7f0b4b332d9b119dd9c33409c538b8aacf"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df"
   integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw==
 
-"@babel/parser@^7.14.5", "@babel/parser@^7.14.6", "@babel/parser@^7.14.7":
-  version "7.14.7"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.14.7.tgz#6099720c8839ca865a2637e6c85852ead0bdb595"
-  integrity sha512-X67Z5y+VBJuHB/RjwECp8kSl5uYi0BvRbNeWqkaJCVh+LiTPl19WBUfG627psSgp9rSf6ojuXghQM3ha6qHHdA==
-
 "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.14.5":
   version "7.14.5"
   resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.14.5.tgz#4b467302e1548ed3b1be43beae2cc9cf45e0bb7e"
     "@babel/parser" "^7.14.5"
     "@babel/types" "^7.14.5"
 
-"@babel/traverse@^7.13.0":
-  version "7.13.13"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.13.tgz#39aa9c21aab69f74d948a486dd28a2dbdbf5114d"
-  integrity sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==
-  dependencies:
-    "@babel/code-frame" "^7.12.13"
-    "@babel/generator" "^7.13.9"
-    "@babel/helper-function-name" "^7.12.13"
-    "@babel/helper-split-export-declaration" "^7.12.13"
-    "@babel/parser" "^7.13.13"
-    "@babel/types" "^7.13.13"
-    debug "^4.1.0"
-    globals "^11.1.0"
-
-"@babel/traverse@^7.14.5":
+"@babel/traverse@^7.0.0-beta.54", "@babel/traverse@^7.14.5":
   version "7.14.7"
   resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.14.7.tgz#64007c9774cfdc3abd23b0780bc18a3ce3631753"
   integrity sha512-9vDr5NzHu27wgwejuKL7kIOm4bwEtaPQ4Z6cpCmjSuaRqpH/7xc4qcGEscwMqlkwgcXl6MvqoAjZkQ24uSdIZQ==
     debug "^4.1.0"
     globals "^11.1.0"
 
+"@babel/traverse@^7.13.0":
+  version "7.13.13"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.13.tgz#39aa9c21aab69f74d948a486dd28a2dbdbf5114d"
+  integrity sha512-CblEcwmXKR6eP43oQGG++0QMTtCjAsa3frUuzHoiIJWpaIIi8dwMyEFUJoXRLxagGqCK+jALRwIO+o3R9p/uUg==
+  dependencies:
+    "@babel/code-frame" "^7.12.13"
+    "@babel/generator" "^7.13.9"
+    "@babel/helper-function-name" "^7.12.13"
+    "@babel/helper-split-export-declaration" "^7.12.13"
+    "@babel/parser" "^7.13.13"
+    "@babel/types" "^7.13.13"
+    debug "^4.1.0"
+    globals "^11.1.0"
+
 "@babel/types@^7", "@babel/types@^7.4.4":
   version "7.11.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.5.tgz#d9de577d01252d77c6800cee039ee64faf75662d"
     lodash "^4.17.19"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.0.0-beta.54", "@babel/types@^7.14.5":
+  version "7.14.5"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
+  integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.14.5"
+    to-fast-properties "^2.0.0"
+
 "@babel/types@^7.10.4":
   version "7.11.0"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.11.0.tgz#2ae6bf1ba9ae8c3c43824e5861269871b206e90d"
     lodash "^4.17.19"
     to-fast-properties "^2.0.0"
 
-"@babel/types@^7.14.5":
-  version "7.14.5"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.14.5.tgz#3bb997ba829a2104cedb20689c4a5b8121d383ff"
-  integrity sha512-M/NzBpEL95I5Hh4dwhin5JlE7EzO5PHMAuzjxss3tiOBD46KfQvVedN/3jEPZvdRvtsK2222XfdHogNIttFgcg==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.14.5"
-    to-fast-properties "^2.0.0"
-
 "@discoveryjs/json-ext@^0.5.0":
   version "0.5.2"
   resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
@@ -2208,6 +2208,11 @@ builtin-modules@^1.0.0:
   resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
   integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=
 
+builtin-modules@^3.0.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.2.0.tgz#45d5db99e7ee5e6bc4f362e008bf917ab5049887"
+  integrity sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==
+
 builtins@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88"
@@ -2292,6 +2297,25 @@ call-limit@~1.1.0:
   resolved "https://registry.yarnpkg.com/call-limit/-/call-limit-1.1.1.tgz#ef15f2670db3f1992557e2d965abc459e6e358d4"
   integrity sha512-5twvci5b9eRBw2wCfPtN0GmlR2/gadZqyFpPhOK6CvMFoFgA+USnZ6Jpu1lhG9h85pQ3Ouil3PfXWRD4EUaRiQ==
 
+caller-callsite@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
+  integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=
+  dependencies:
+    callsites "^2.0.0"
+
+caller-path@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4"
+  integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=
+  dependencies:
+    caller-callsite "^2.0.0"
+
+callsites@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50"
+  integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=
+
 callsites@^3.0.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@@ -2784,6 +2808,16 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
   resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
   integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
 
+cosmiconfig@^5.0.5:
+  version "5.2.1"
+  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a"
+  integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==
+  dependencies:
+    import-fresh "^2.0.0"
+    is-directory "^0.3.1"
+    js-yaml "^3.13.1"
+    parse-json "^4.0.0"
+
 cosmiconfig@^7.0.0:
   version "7.0.0"
   resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.0.tgz#ef9b44d773959cae63ddecd122de23853b60f8d3"
@@ -3041,11 +3075,21 @@ destroy@~1.0.4:
   resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
   integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
 
+detect-indent@^6.0.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6"
+  integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==
+
 detect-indent@~5.0.0:
   version "5.0.0"
   resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d"
   integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50=
 
+detect-newline@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651"
+  integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==
+
 detect-newline@^2.1.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2"
@@ -3612,6 +3656,17 @@ fast-diff@^1.1.2:
   resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03"
   integrity sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==
 
+fast-glob@^3.0.3:
+  version "3.2.7"
+  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.7.tgz#fd6cb7a2d7e9aa7a7846111e85a196d6b2f766a1"
+  integrity sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==
+  dependencies:
+    "@nodelib/fs.stat" "^2.0.2"
+    "@nodelib/fs.walk" "^1.2.3"
+    glob-parent "^5.1.2"
+    merge2 "^1.3.0"
+    micromatch "^4.0.4"
+
 fast-glob@^3.1.1:
   version "3.2.4"
   resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3"
@@ -3728,11 +3783,21 @@ find-cache-dir@^3.3.1:
     make-dir "^3.0.2"
     pkg-dir "^4.1.0"
 
+find-line-column@^0.5.2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/find-line-column/-/find-line-column-0.5.2.tgz#db00238ff868551a182e74a103416d295a98c8ca"
+  integrity sha1-2wAjj/hoVRoYLnShA0FtKVqYyMo=
+
 find-npm-prefix@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/find-npm-prefix/-/find-npm-prefix-1.0.2.tgz#8d8ce2c78b3b4b9e66c8acc6a37c231eb841cfdf"
   integrity sha512-KEftzJ+H90x6pcKtdXZEPsQse8/y/UnvzRKrOSQFprnrGaFuJ62fVkP34Iu2IYuMvyauCyoLTNkJZgrrGA2wkA==
 
+find-root@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
+  integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
+
 find-up@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
@@ -4010,6 +4075,11 @@ getpass@^0.1.1:
   dependencies:
     assert-plus "^1.0.0"
 
+git-hooks-list@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/git-hooks-list/-/git-hooks-list-1.0.3.tgz#be5baaf78203ce342f2f844a9d2b03dba1b45156"
+  integrity sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ==
+
 glob-parent@^3.1.0:
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
@@ -4082,6 +4152,20 @@ globals@^13.9.0:
   dependencies:
     type-fest "^0.20.2"
 
+globby@10.0.0:
+  version "10.0.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.0.tgz#abfcd0630037ae174a88590132c2f6804e291072"
+  integrity sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw==
+  dependencies:
+    "@types/glob" "^7.1.1"
+    array-union "^2.1.0"
+    dir-glob "^3.0.1"
+    fast-glob "^3.0.3"
+    glob "^7.1.3"
+    ignore "^5.1.1"
+    merge2 "^1.2.3"
+    slash "^3.0.0"
+
 globby@^11.0.3:
   version "11.0.3"
   resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
@@ -4436,11 +4520,19 @@ ignore@^4.0.6:
   resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
   integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
 
-ignore@^5.1.4:
+ignore@^5.1.1, ignore@^5.1.4:
   version "5.1.8"
   resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57"
   integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==
 
+import-fresh@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546"
+  integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY=
+  dependencies:
+    caller-path "^2.0.0"
+    resolve-from "^3.0.0"
+
 import-fresh@^3.0.0, import-fresh@^3.2.1:
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.2.1.tgz#633ff618506e793af5ac91bf48b72677e15cbe66"
@@ -4470,6 +4562,60 @@ import-local@^3.0.2:
     pkg-dir "^4.2.0"
     resolve-cwd "^3.0.0"
 
+import-sort-config@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort-config/-/import-sort-config-6.0.0.tgz#7313775b761eb479ab2d383945ecb15c008763b8"
+  integrity sha512-FJpF2F3+30JXqH1rJKeajxoSCHCueai3/0ntDN4y3GJL5pjnLDt/VjCy5FzjH7u0NHnllL/zVEf1wfmsVxJlPQ==
+  dependencies:
+    cosmiconfig "^5.0.5"
+    find-root "^1.0.0"
+    minimatch "^3.0.4"
+    resolve-from "^4.0.0"
+
+import-sort-parser-babylon@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort-parser-babylon/-/import-sort-parser-babylon-6.0.0.tgz#e1a4c28e0794ad7d9ff36cd045559d8ca8c38be7"
+  integrity sha512-NyShTiNhTh4Vy7kJUVe6CuvOaQAzzfSIT72wtp3CzGjz8bHjNj59DCAjncuviicmDOgVAgmLuSh1WMcLYAMWGg==
+  dependencies:
+    "@babel/core" "^7.2.2"
+    "@babel/parser" "^7.0.0-beta.54"
+    "@babel/traverse" "^7.0.0-beta.54"
+    "@babel/types" "^7.0.0-beta.54"
+    find-line-column "^0.5.2"
+
+import-sort-parser-typescript@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort-parser-typescript/-/import-sort-parser-typescript-6.0.0.tgz#98e73cef9e077d073e798722ed59e215b51c17e2"
+  integrity sha512-pgxnr3I156DonupQriNsgDb2zJN9TxrqCCIN1rwT/6SDO1rkJb+a0fjqshCjlgacTSA92oPAp1eAwmQUeZi3dw==
+  dependencies:
+    typescript "^3.2.4"
+
+import-sort-parser@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort-parser/-/import-sort-parser-6.0.0.tgz#0d901f264d98ed7caaae71f66128a686f828f2f4"
+  integrity sha512-H5L+d6HnqHvThB0GmAA3/43Sv74oCwL0iMk3/ixOv0LRJ69rCyHXeG/+UadMHrD2FefEmgPIWboEPAG7gsQrkA==
+
+import-sort-style-module@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort-style-module/-/import-sort-style-module-6.0.0.tgz#3149df4785bae804ed32630634ed49e405fa7cad"
+  integrity sha512-Oxd256EVt6TAgawhIDuKnNHWumzHMHFWhVncBBvlHVnx69B4GP/Gu4Xo+gjxtqSEKEvam5ajUkNvnsXLDMDjKg==
+
+import-sort-style@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort-style/-/import-sort-style-6.0.0.tgz#088523f056e5064c34a6426f4733674d81b42e6a"
+  integrity sha512-z0H5PKs7YoDeKxNYXv2AA1mjjZFY07fjeNCXUdTM3ymJtWeeEoTm8CQkFm2l+KPZoMczIvdwzJpWkkOamBnsPw==
+
+import-sort@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/import-sort/-/import-sort-6.0.0.tgz#48ba2a7b53f2566ca1dd004327ea271321ad64ff"
+  integrity sha512-XUwSQMGAGmcW/wfshFE0gXgb1NPF6ibbQD6wDr3KRDykZf/lZj0jf58Bwa02xNb8EE59oz7etFe9OHnJocUW5Q==
+  dependencies:
+    detect-newline "^2.1.0"
+    import-sort-parser "^6.0.0"
+    import-sort-style "^6.0.0"
+    is-builtin-module "^3.0.0"
+    resolve "^1.8.1"
+
 imurmurhash@^0.1.4:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
@@ -4720,6 +4866,13 @@ is-builtin-module@^1.0.0:
   dependencies:
     builtin-modules "^1.0.0"
 
+is-builtin-module@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.1.0.tgz#6fdb24313b1c03b75f8b9711c0feb8c30b903b00"
+  integrity sha512-OV7JjAgOTfAFJmHZLvpSTb4qi0nIILDV1gWPYDnDJUTNFM5aGlRAhk4QcT8i7TuAleeEV5Fdkqn3t4mS+Q11fg==
+  dependencies:
+    builtin-modules "^3.0.0"
+
 is-callable@^1.1.4, is-callable@^1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb"
@@ -4790,6 +4943,11 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
     is-data-descriptor "^1.0.0"
     kind-of "^6.0.2"
 
+is-directory@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
+  integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=
+
 is-extendable@^0.1.0, is-extendable@^0.1.1:
   version "0.1.1"
   resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
@@ -4894,6 +5052,11 @@ is-path-inside@^2.1.0:
   dependencies:
     path-is-inside "^1.0.2"
 
+is-plain-obj@2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287"
+  integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==
+
 is-plain-obj@^1.1.0:
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@@ -5052,7 +5215,7 @@ jsesc@~0.5.0:
   resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
   integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
 
-json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.2:
+json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
   integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
@@ -5632,7 +5795,7 @@ merge-stream@^2.0.0:
   resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
   integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
 
-merge2@^1.3.0:
+merge2@^1.2.3, merge2@^1.3.0:
   version "1.4.1"
   resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
   integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
@@ -6713,6 +6876,14 @@ parse-json@^2.2.0:
   dependencies:
     error-ex "^1.2.0"
 
+parse-json@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0"
+  integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=
+  dependencies:
+    error-ex "^1.3.1"
+    json-parse-better-errors "^1.0.1"
+
 parse-json@^5.0.0:
   version "5.1.0"
   resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
@@ -6959,6 +7130,28 @@ prettier-linter-helpers@^1.0.0:
   dependencies:
     fast-diff "^1.1.2"
 
+prettier-plugin-import-sort@^0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/prettier-plugin-import-sort/-/prettier-plugin-import-sort-0.0.7.tgz#b13dcc4de98940b99066a9e34606a955d109b546"
+  integrity sha512-O0KlUSq+lwvh+UiN3wZDT6wWkf7TNxTVv2/XXE5KqpRNbFJq3nRg2ftzBYFFO8QGpdWIrOB0uCTCtFjIxmVKQw==
+  dependencies:
+    import-sort "^6.0.0"
+    import-sort-config "^6.0.0"
+    import-sort-parser-babylon "^6.0.0"
+    import-sort-parser-typescript "^6.0.0"
+
+prettier-plugin-organize-imports@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-2.2.0.tgz#dcdd5222416a90bd819734f131fea4a22b1c613a"
+  integrity sha512-2WM3moc/cAPCCsSneYhaL4+mMws0Bypbxz+98wuRyaA7GMokhOECVkQCG7l2hcH+9/4d5NsgZs9yktfwDy4r7A==
+
+prettier-plugin-packagejson@^2.2.11:
+  version "2.2.11"
+  resolved "https://registry.yarnpkg.com/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.2.11.tgz#640b6301da3a58c489889b3d315255e18153daf0"
+  integrity sha512-oJCBCEkHIKScEv6qNQC47S39NXlevbzwvoJE3gflmBB8/3BEsC6ZRi+hwFVajw32b4tDI9hFXPIzmVd/T8Rm9w==
+  dependencies:
+    sort-package-json "1.50.0"
+
 prettier@^2.3.2:
   version "2.3.2"
   resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.2.tgz#ef280a05ec253712e486233db5c6f23441e7342d"
@@ -7523,7 +7716,7 @@ resolve@^1.10.0:
   dependencies:
     path-parse "^1.0.6"
 
-resolve@^1.14.2, resolve@^1.20.0:
+resolve@^1.14.2, resolve@^1.20.0, resolve@^1.8.1:
   version "1.20.0"
   resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
   integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
@@ -7994,6 +8187,23 @@ socks@~2.3.2:
     ip "1.1.5"
     smart-buffer "^4.1.0"
 
+sort-object-keys@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/sort-object-keys/-/sort-object-keys-1.1.3.tgz#bff833fe85cab147b34742e45863453c1e190b45"
+  integrity sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg==
+
+sort-package-json@1.50.0:
+  version "1.50.0"
+  resolved "https://registry.yarnpkg.com/sort-package-json/-/sort-package-json-1.50.0.tgz#19fc109fe23bd157bd03c8e572fa3251a52467d8"
+  integrity sha512-qZpqhMU9XTntebgAgc4hv/D6Fzhh7kFnwvV6a7+q8y8J5JoaDqPYQnvXPf7BBqG95tdE8X6JVNo7/jDzcbdfUg==
+  dependencies:
+    detect-indent "^6.0.0"
+    detect-newline "3.1.0"
+    git-hooks-list "1.0.3"
+    globby "10.0.0"
+    is-plain-obj "2.1.0"
+    sort-object-keys "^1.1.3"
+
 sorted-object@~2.0.1:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/sorted-object/-/sorted-object-2.0.1.tgz#7d631f4bd3a798a24af1dffcfbfe83337a5df5fc"
@@ -8685,6 +8895,11 @@ typedarray@^0.0.6:
   resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
   integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
 
+typescript@^3.2.4:
+  version "3.9.10"
+  resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8"
+  integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==
+
 typescript@^4.3.5:
   version "4.3.5"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4"