diff --git a/lang/default.json b/lang/default.json index 30379f9a89..ad3125a28d 100644 --- a/lang/default.json +++ b/lang/default.json @@ -1,4 +1,8 @@ { + "+7SAix": { + "defaultMessage": "Must be between 2-12 characters long.", + "description": "" + }, "+a+2ug": { "defaultMessage": "Members", "description": "" @@ -35,6 +39,10 @@ "defaultMessage": "replied to your comment on", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" }, + "/podGX": { + "defaultMessage": "Public", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, "0Azlrb": { "defaultMessage": "Manage", "description": "" @@ -47,10 +55,18 @@ "defaultMessage": "Bug Bounty", "description": "" }, + "1qQzV0": { + "defaultMessage": "Invitees", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "20bImY": { "defaultMessage": "Discussion", "description": "" }, + "2CqWQE": { + "defaultMessage": "Total", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "2atspc": { "defaultMessage": "Drafts", "description": "" @@ -63,6 +79,10 @@ "defaultMessage": "Likes", "description": "" }, + "2uwwz+": { + "defaultMessage": "Accumulated read time indicates the total time length that registered users read.", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, "32bml8": { "defaultMessage": "Following", "description": "src/components/Layout/SideNav/index.tsx" @@ -131,6 +151,14 @@ "defaultMessage": "Start Creating", "description": "" }, + "6BXcdo": { + "defaultMessage": "Set threshold for circle (per month)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "6OBAOi": { + "defaultMessage": "subscribers_empty", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "6flWFg": { "defaultMessage": "Term of Services", "description": "" @@ -151,6 +179,10 @@ "defaultMessage": "The article has been added to the Trending", "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" }, + "8KFsZN": { + "defaultMessage": "Read Counts", + "description": "" + }, "8cv9D4": { "defaultMessage": "Next Step", "description": "" @@ -207,10 +239,22 @@ "defaultMessage": "Start creating now!", "description": "src/components/Forms/EmailSignUpForm/Complete.tsx" }, + "AYTnjk": { + "defaultMessage": "Followers", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, "BHFHeY": { "defaultMessage": "commented in {commentCircle}", "description": "src/components/Notice/CommentNotice/CommentMentionedYouNotice.tsx" }, + "Bc20la": { + "defaultMessage": "days", + "description": "" + }, + "Bjdw71": { + "defaultMessage": "followers_empty", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, "BjzRe8": { "defaultMessage": ". Take a look at your income", "description": "src/components/Notice/TransactionNotice/PaymentReceivedDonationNotice.tsx" @@ -239,10 +283,22 @@ "defaultMessage": "Settings", "description": "" }, + "DMlmcU": { + "defaultMessage": "Free Trial", + "description": "src/views/Circle/Settings/index.tsx" + }, + "DXJ8ys": { + "defaultMessage": "Read counts indicates how many registered users read.", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, "E8W3qa": { "defaultMessage": "Must be between 2-20 characters long. Chinese characters, letters, numbers and underscores are allowed.", "description": "" }, + "EQeKnO": { + "defaultMessage": "Manage Invitation", + "description": "src/views/Circle/Settings/index.tsx" + }, "EW5R4p": { "defaultMessage": "Request an update, ask, share and discuss", "description": "src/views/Circle/Discussion/Discussion.tsx" @@ -271,10 +327,18 @@ "defaultMessage": "Install MetaMask", "description": "src/components/Forms/WalletAuthForm/Select.tsx" }, + "Fe682o": { + "defaultMessage": "Next Month (Estimation)", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, "FhWC22": { "defaultMessage": "Matters Community", "description": "" }, + "FmWYRt": { + "defaultMessage": "Free trial period", + "description": "" + }, "GBm/sD": { "defaultMessage": "posted a new topic and mentioned you", "description": "src/components/Notice/CircleNotice/CircleNewDiscussionComments.tsx" @@ -287,6 +351,10 @@ "defaultMessage": "Analytics", "description": "" }, + "GugBCe": { + "defaultMessage": "New Followers This Month", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, "H0JBH6": { "defaultMessage": "Log Out", "description": "" @@ -335,10 +403,18 @@ "defaultMessage": "Your article has been published to decentralized network", "description": "src/components/Notice/ArticleNotice/ArticlePublishedNotice.tsx" }, + "JXdbo8": { + "defaultMessage": "Done", + "description": "" + }, "Jc+W6M": { "defaultMessage": "resigned as tag maintainer. Would you like to be the new tag maintainer?", "description": "src/components/Notice/TagNotice/TagLeaveNotice.tsx" }, + "JpS59y": { + "defaultMessage": "Accepted", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, "Js/Fij": { "defaultMessage": "This article has been removed from Trending", "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" @@ -355,6 +431,10 @@ "defaultMessage": "Profile updated", "description": "src/components/UserProfile/DropdownActions/EditProfileDialog/Content.tsx" }, + "KLQ1/z": { + "defaultMessage": "Circle successfully created", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, "KMcrz8": { "defaultMessage": "Maintain Tag", "description": "src/views/TagDetail/Owner/index.tsx" @@ -367,6 +447,14 @@ "defaultMessage": "invites you to join Circle for", "description": "src/components/Notice/CircleNotice/CircleInvitationNotice.tsx" }, + "L0J61B": { + "defaultMessage": "Free", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "L4NXXh": { + "defaultMessage": "Total", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, "L7Si5/": { "defaultMessage": "Manage Community", "description": "src/views/TagDetail/DropdownActions/index.tsx" @@ -375,6 +463,10 @@ "defaultMessage": "Followed", "description": "" }, + "LOefol": { + "defaultMessage": "Paywalled", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, "LW1aX1": { "defaultMessage": "Congrats!", "description": "src/components/Notice/CircleNotice/CircleInvitationNotice.tsx" @@ -391,6 +483,10 @@ "defaultMessage": "Wallet address will be part of your digital identity and shown in your profile page.", "description": "src/components/Forms/WalletAuthForm/Select.tsx" }, + "MDNaxs": { + "defaultMessage": "followers", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, "MkwOFW": { "defaultMessage": "Read History", "description": "" @@ -419,6 +515,14 @@ "defaultMessage": "resigned as tag collaborator. You can invite new collaborators to join", "description": "src/components/Notice/TagNotice/TagLeaveEditorNotice.tsx" }, + "O0QB1v": { + "defaultMessage": "Friends will receive free trial invitations to Circle. Set up your invitations now!", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "OIj8pQ": { + "defaultMessage": "Invitation Sent", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, "OKhRC6": { "defaultMessage": "Share", "description": "" @@ -447,14 +551,38 @@ "defaultMessage": "Select NFT as your avatar", "description": "src/components/UserProfile/DropdownActions/EditProfileDialog/NFTCollection/index.tsx" }, + "QUqfbW": { + "defaultMessage": "Describe more about your Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, "QV19cI": { "defaultMessage": "Failed to republish article", "description": "src/components/Notice/ArticleNotice/RevisedArticleNotPublishedNotice.tsx" }, + "QZXKhG": { + "defaultMessage": "Set the Circle URL (cannot be modified after creation)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, "RFzVUD": { "defaultMessage": "Unpin Broadcast", "description": "src/components/Comment/DropdownActions/PinButton.tsx" }, + "RxiHr/": { + "defaultMessage": "friends have not accepted your invitations.", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx" + }, + "SENRqu": { + "defaultMessage": "Help", + "description": "" + }, + "SNh1n0": { + "defaultMessage": "View Members", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SdXoXI": { + "defaultMessage": "Invitations have been sent. You can check invitation status on the invitation management page.", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, "Seanpx": { "defaultMessage": "Required", "description": "" @@ -467,6 +595,10 @@ "defaultMessage": "Unpin", "description": "src/components/ArticleDigest/DropdownActions/StickyButton.tsx" }, + "TSDiqB": { + "defaultMessage": "Subscribers", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "TjWWxF": { "defaultMessage": "Broadcast sent", "description": "src/views/Circle/Broadcast/Broadcast.tsx" @@ -515,6 +647,10 @@ "defaultMessage": "Matters will never ask your wallet key through any channel.", "description": "src/components/Forms/WalletAuthForm/Select.tsx" }, + "VwuiYK": { + "defaultMessage": "This URL name has already been used, try another one", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, "WBVVYd": { "defaultMessage": "Responses", "description": "" @@ -523,6 +659,10 @@ "defaultMessage": "Add to Featured", "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" }, + "WpvsPu": { + "defaultMessage": "Subscribe", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "WuvE8X": { "defaultMessage": "Followers of {circleName}", "description": "src/views/Circle/Profile/FollowersDialog/index.tsx" @@ -535,6 +675,10 @@ "defaultMessage": "Welcome to Matters!", "description": "src/components/Forms/EmailSignUpForm/Complete.tsx" }, + "XHMco9": { + "defaultMessage": "subscribers", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "XVYrS/": { "defaultMessage": "No followers yet", "description": "" @@ -567,10 +711,18 @@ "defaultMessage": "Broadcast and mentioned you in comment", "description": "src/components/Notice/CircleNotice/CircleNewBroadcastComments.tsx" }, + "Z6cII7": { + "defaultMessage": "Accumulated Read Time", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, "Z6ewE3": { "defaultMessage": "Build Together", "description": "src/views/Me/Settings/AnonymousSettings/Enhance/index.tsx" }, + "ZAs170": { + "defaultMessage": "Profile", + "description": "src/views/Circle/Settings/index.tsx" + }, "ZUPQzl": { "defaultMessage": "comment", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" @@ -607,6 +759,10 @@ "defaultMessage": "Last {days} days", "description": "src/views/Me/Analytics/SelectPeriod/index.tsx" }, + "b8ogKp": { + "defaultMessage": "Add Invitation", + "description": "src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx" + }, "bBYO6x": { "defaultMessage": "Unblock", "description": "src/components/BlockUser/Button/index.tsx" @@ -643,6 +799,10 @@ "defaultMessage": "You haven‘t published any articles yet, so there is no data available. Create one now to introduce yourself!", "description": "src/views/Me/Analytics/EmptyAnalytics/index.tsx" }, + "d4waan": { + "defaultMessage": "Income", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, "deEeEI": { "defaultMessage": "Register", "description": "" @@ -667,10 +827,18 @@ "defaultMessage": "Maintainer", "description": "" }, + "ei+kyp": { + "defaultMessage": "Name of the Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, "enMIYK": { "defaultMessage": "My Page", "description": "" }, + "eov+J2": { + "defaultMessage": "Custom URL Name", + "description": "" + }, "euNJsE": { "defaultMessage": "A new article has been added to the circle, read it now!", "description": "src/components/Notice/ArticleNotice/CircleNewArticle.tsx" @@ -683,6 +851,10 @@ "defaultMessage": "Choose a method to enter", "description": "src/components/Forms/SelectAuthMethodForm/index.tsx" }, + "fWDtpq": { + "defaultMessage": "Pending", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, "ftD7Hy": { "defaultMessage": "mentioned you", "description": "src/components/Notice/CircleNotice/CircleNewDiscussionComments.tsx" @@ -691,6 +863,10 @@ "defaultMessage": "posted and replied to topics", "description": "src/components/Notice/CircleNotice/CircleNewDiscussionComments.tsx" }, + "gMZZ9I": { + "defaultMessage": "Must be between 2-20 characters long. Only letters, numbers and underscores are allowed.", + "description": "" + }, "gMZfHO": { "defaultMessage": "RSS Subscription", "description": "src/components/Dialogs/RssFeedDialog/Content.tsx" @@ -783,6 +959,14 @@ "defaultMessage": "Enter Email", "description": "" }, + "lIir/P": { + "defaultMessage": "I see", + "description": "" + }, + "lNjDPr": { + "defaultMessage": "You have not invited anyone yet! Invite friends to join your circle by clicking 'invite friends'.", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx" + }, "lhaIoi": { "defaultMessage": "Enter Display Name", "description": "" @@ -791,6 +975,10 @@ "defaultMessage": "Trending", "description": "" }, + "mCAIcg": { + "defaultMessage": "Hottest", + "description": "src/views/Circle/Analytics/ContentAnalytics/index.tsx" + }, "mPe6DK": { "defaultMessage": "subscribed your circle", "description": "src/components/Notice/CircleNotice/CircleNewUserNotice.tsx" @@ -807,6 +995,10 @@ "defaultMessage": "Edit", "description": "src/components/Comment/DropdownActions/EditButton.tsx" }, + "mjMpv4": { + "defaultMessage": "Circle Edited", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, "mk+LCk": { "defaultMessage": "Display Preferences", "description": "src/views/Me/Settings/AnonymousSettings/DisplayPreferences/index.tsx" @@ -850,9 +1042,9 @@ "defaultMessage": "Collapse", "description": "src/components/Comment/DropdownActions/CollapseComment/Button.tsx" }, - "pla6ZF": { - "defaultMessage": "Search articles, tags and authors", - "description": "src/components/Search/SearchBar/index.tsx" + "ptqBN1": { + "defaultMessage": "Not Now", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" }, "pwlQEY": { "defaultMessage": "Display Name", @@ -866,6 +1058,10 @@ "defaultMessage": "Manage Circle", "description": "src/views/Circle/Profile/DropdownActions/index.tsx" }, + "q9oMKE": { + "defaultMessage": "Circle Name", + "description": "" + }, "qPPrzm": { "defaultMessage": "supported your article", "description": "src/components/Notice/TransactionNotice/PaymentReceivedDonationNotice.tsx" @@ -894,6 +1090,10 @@ "defaultMessage": "Weibo", "description": "src/components/Share/Buttons/Weibo.tsx" }, + "rXnmeE": { + "defaultMessage": "Confirm and Send", + "description": "" + }, "reOeq5": { "defaultMessage": "You have created your personal creative space. Publish your first work!", "description": "src/components/Forms/EmailSignUpForm/Complete.tsx" @@ -910,6 +1110,10 @@ "defaultMessage": "Account Banned", "description": "src/components/UserProfile/index.tsx" }, + "sPgUkN": { + "defaultMessage": "This Month", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, "skbUBl": { "defaultMessage": "Log in", "description": "src/components/Buttons/Login/index.tsx" @@ -938,6 +1142,14 @@ "defaultMessage": "replied to topics and mentioned you", "description": "src/components/Notice/CircleNotice/CircleNewDiscussionComments.tsx" }, + "tW3hM/": { + "defaultMessage": "Description of the Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "tzq2+W": { + "defaultMessage": "Send", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, "u5aHb4": { "defaultMessage": "Copy Link", "description": "" @@ -982,6 +1194,10 @@ "defaultMessage": "Contact Channel", "description": "src/components/Forms/WalletAuthForm/Connect.tsx" }, + "wXzTZ0": { + "defaultMessage": "Enter the name of your Circle", + "description": "" + }, "wbcwKd": { "defaultMessage": "View All", "description": "" @@ -994,6 +1210,10 @@ "defaultMessage": "As a reminder, the email address will not be used as a login but only as a contact channel.", "description": "src/components/Forms/WalletAuthForm/Connect.tsx" }, + "xWZr13": { + "defaultMessage": "{follower, plural, =1 {follower} other {followers}}", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, "xiKjd/": { "defaultMessage": "Continue with Email", "description": "src/components/Forms/SelectAuthMethodForm/index.tsx" @@ -1006,6 +1226,10 @@ "defaultMessage": "invites you to become a collaborator", "description": "src/components/Notice/TagNotice/TagAddEditorNotice.tsx" }, + "y0b6Kp": { + "defaultMessage": "Pay", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, "y1Z3or": { "defaultMessage": "Language", "description": "" @@ -1022,6 +1246,10 @@ "defaultMessage": "Your", "description": "src/components/Notice/TransactionNotice/PaymentPayoutNotice.tsx" }, + "zKOr2x": { + "defaultMessage": "Conversion Rate of Followers", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, "zQvVDJ": { "defaultMessage": "All", "description": "" @@ -1032,5 +1260,9 @@ "zxlwbc": { "defaultMessage": "Waiting ...", "description": "src/components/Dialogs/RssFeedDialog/Content.tsx" + }, + "zxy15q": { + "defaultMessage": "{subscriber, plural, =1 {subscriber} other {subscribers}}", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" } } diff --git a/lang/en.json b/lang/en.json index e400ac2acd..fda640be9f 100644 --- a/lang/en.json +++ b/lang/en.json @@ -719,10 +719,6 @@ "defaultMessage": "You won't see announcements for 7 days", "description": "src/views/Home/Announcements/index.tsx" }, - "pla6ZF": { - "defaultMessage": "Search articles, tags and authors", - "description": "src/components/Search/SearchBar/index.tsx" - }, "3kbIhS": { "defaultMessage": "Untitled", "description": "" @@ -1061,5 +1057,237 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {article} other {articles}}", "description": "" + }, + "ZAs170": { + "defaultMessage": "Profile", + "description": "src/views/Circle/Settings/index.tsx" + }, + "DMlmcU": { + "defaultMessage": "Free Trial", + "description": "src/views/Circle/Settings/index.tsx" + }, + "EQeKnO": { + "defaultMessage": "Manage Invitation", + "description": "src/views/Circle/Settings/index.tsx" + }, + "KLQ1/z": { + "defaultMessage": "Circle successfully created", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "mjMpv4": { + "defaultMessage": "Circle Edited", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "ei+kyp": { + "defaultMessage": "Name of the Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "tW3hM/": { + "defaultMessage": "Description of the Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "CwWLOr": { + "defaultMessage": "Enter the name of your Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "QUqfbW": { + "defaultMessage": "Describe more about your Circle", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "JXdbo8": { + "defaultMessage": "Done", + "description": "" + }, + "q9oMKE": { + "defaultMessage": "Circle Name", + "description": "" + }, + "QZXKhG": { + "defaultMessage": "Set the Circle URL (cannot be modified after creation)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "6BXcdo": { + "defaultMessage": "Set threshold for circle (per month)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "VwuiYK": { + "defaultMessage": "This URL name has already been used, try another one", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "gMZZ9I": { + "defaultMessage": "Must be between 2-20 characters long. Only letters, numbers and underscores are allowed.", + "description": "" + }, + "+7SAix": { + "defaultMessage": "Must be between 2-12 characters long.", + "description": "" + }, + "eov+J2": { + "defaultMessage": "Custom URL Name", + "description": "" + }, + "8KFsZN": { + "defaultMessage": "Read Counts", + "description": "" + }, + "LOefol": { + "defaultMessage": "Paywalled", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, + "/podGX": { + "defaultMessage": "Public", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, + "mCAIcg": { + "defaultMessage": "Hottest", + "description": "src/views/Circle/Analytics/ContentAnalytics/index.tsx" + }, + "lNjDPr": { + "defaultMessage": "You have not invited anyone yet! Invite friends to join your circle by clicking 'invite friends'.", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx" + }, + "RxiHr/": { + "defaultMessage": "friends have not accepted your invitations.", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx" + }, + "b8ogKp": { + "defaultMessage": "Add Invitation", + "description": "src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx" + }, + "FmWYRt": { + "defaultMessage": "Free trial period", + "description": "" + }, + "Bc20la": { + "defaultMessage": "days", + "description": "" + }, + "O0QB1v": { + "defaultMessage": "Friends will receive free trial invitations to Circle. Set up your invitations now!", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "rXnmeE": { + "defaultMessage": "Confirm and Send", + "description": "" + }, + "ptqBN1": { + "defaultMessage": "Not Now", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "tzq2+W": { + "defaultMessage": "Send", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "fWDtpq": { + "defaultMessage": "Pending", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, + "JpS59y": { + "defaultMessage": "Accepted", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, + "Bjdw71": { + "defaultMessage": "", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "xWZr13": { + "defaultMessage": "{follower, plural, =1 {follower} other {followers}}", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "GugBCe": { + "defaultMessage": "New Followers This Month", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "MDNaxs": { + "defaultMessage": "", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "zKOr2x": { + "defaultMessage": "Conversion Rate of Followers", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "AYTnjk": { + "defaultMessage": "Followers", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "sPgUkN": { + "defaultMessage": "This Month", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "Fe682o": { + "defaultMessage": "Next Month (Estimation)", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "L4NXXh": { + "defaultMessage": "Total", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "d4waan": { + "defaultMessage": "Income", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "6OBAOi": { + "defaultMessage": "", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "zxy15q": { + "defaultMessage": "{subscriber, plural, =1 {subscriber} other {subscribers}}", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "TSDiqB": { + "defaultMessage": "Subscribers", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "XHMco9": { + "defaultMessage": "", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "1qQzV0": { + "defaultMessage": "Invitees", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "WpvsPu": { + "defaultMessage": "Subscribe", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SNh1n0": { + "defaultMessage": "View Members", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "2CqWQE": { + "defaultMessage": "Total", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "y0b6Kp": { + "defaultMessage": "Pay", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "L0J61B": { + "defaultMessage": "Free", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SdXoXI": { + "defaultMessage": "Invitations have been sent. You can check invitation status on the invitation management page.", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, + "OIj8pQ": { + "defaultMessage": "Invitation Sent", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, + "lIir/P": { + "defaultMessage": "I see", + "description": "" + }, + "2uwwz+": { + "defaultMessage": "Accumulated read time indicates the total time length that registered users read.", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, + "Z6cII7": { + "defaultMessage": "Accumulated Read Time", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, + "DXJ8ys": { + "defaultMessage": "Read counts indicates how many registered users read.", + "description": "src/components/Dialogs/HelpDialog/index.tsx" } } diff --git a/lang/zh-Hans.json b/lang/zh-Hans.json index 6d56e58083..1ef62673d4 100644 --- a/lang/zh-Hans.json +++ b/lang/zh-Hans.json @@ -727,10 +727,6 @@ "defaultMessage": "暂时隐藏公告栏 7 天", "description": "src/views/Home/Announcements/index.tsx" }, - "pla6ZF": { - "defaultMessage": "搜索作品、标签、作者", - "description": "src/components/Search/SearchBar/index.tsx" - }, "3kbIhS": { "defaultMessage": "未命名", "description": "" @@ -1061,5 +1057,237 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {篇文章} other {篇文章}}", "description": "" + }, + "ZAs170": { + "defaultMessage": "基本资料", + "description": "src/views/Circle/Settings/index.tsx" + }, + "DMlmcU": { + "defaultMessage": "免费资格", + "description": "src/views/Circle/Settings/index.tsx" + }, + "EQeKnO": { + "defaultMessage": "邀请管理", + "description": "src/views/Circle/Settings/index.tsx" + }, + "KLQ1/z": { + "defaultMessage": "围炉创建成功", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "mjMpv4": { + "defaultMessage": "围炉已更新", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "ei+kyp": { + "defaultMessage": "围炉名称", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "tW3hM/": { + "defaultMessage": "围炉描述", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "CwWLOr": { + "defaultMessage": "给围炉取一个吸引人的名字吧", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "QUqfbW": { + "defaultMessage": "说说围炉的有趣之处,吸引支持者加入", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "JXdbo8": { + "defaultMessage": "完成", + "description": "" + }, + "q9oMKE": { + "defaultMessage": "围炉名称", + "description": "" + }, + "QZXKhG": { + "defaultMessage": "设置围炉网址(创建后不可修改)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "6BXcdo": { + "defaultMessage": "设定围炉门槛(每月)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "VwuiYK": { + "defaultMessage": "Oops!此网址名称已被使用了,换一个试试", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "gMZZ9I": { + "defaultMessage": "2-20 个字符,仅支持英文、数字或下划线", + "description": "" + }, + "+7SAix": { + "defaultMessage": "2-12 个字符", + "description": "" + }, + "eov+J2": { + "defaultMessage": "自定义网址名称", + "description": "" + }, + "8KFsZN": { + "defaultMessage": "阅读次数", + "description": "" + }, + "LOefol": { + "defaultMessage": "上锁", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, + "/podGX": { + "defaultMessage": "公开", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, + "mCAIcg": { + "defaultMessage": "站内阅读热门排行", + "description": "src/views/Circle/Analytics/ContentAnalytics/index.tsx" + }, + "lNjDPr": { + "defaultMessage": "你还没有邀请任何用户喔!点击新增邀请,添加站内或站外朋友加入围炉赠与对方免费资格的固定时长", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx" + }, + "RxiHr/": { + "defaultMessage": "还没有任何用户回覆你的邀请喔!", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx" + }, + "b8ogKp": { + "defaultMessage": "新增邀请", + "description": "src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx" + }, + "FmWYRt": { + "defaultMessage": "免费资格时长", + "description": "" + }, + "Bc20la": { + "defaultMessage": "天", + "description": "" + }, + "O0QB1v": { + "defaultMessage": "用户将收到你的围炉免费资格邀请函,设置免费的时限,邀请他们一起加入吧!", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "rXnmeE": { + "defaultMessage": "确认发送", + "description": "" + }, + "ptqBN1": { + "defaultMessage": "暂时不要", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "tzq2+W": { + "defaultMessage": "寄出邀请", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "fWDtpq": { + "defaultMessage": "邀请中", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, + "JpS59y": { + "defaultMessage": "已接受", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, + "Bjdw71": { + "defaultMessage": "目前总追踪人数", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "xWZr13": { + "defaultMessage": "{follower, plural, =1 {人} other {人}}", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "GugBCe": { + "defaultMessage": "本月新增追踪人数", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "MDNaxs": { + "defaultMessage": "人", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "zKOr2x": { + "defaultMessage": "已追踪用户占总观看人数比例", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "AYTnjk": { + "defaultMessage": "追踪", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "sPgUkN": { + "defaultMessage": "本月营收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "Fe682o": { + "defaultMessage": "下月预期营收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "L4NXXh": { + "defaultMessage": "目前总营收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "d4waan": { + "defaultMessage": "营收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "6OBAOi": { + "defaultMessage": "目前总订阅人数", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "zxy15q": { + "defaultMessage": "{subscriber, plural, =1 {人} other {人}}", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "TSDiqB": { + "defaultMessage": "付费人数", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "XHMco9": { + "defaultMessage": "人", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "1qQzV0": { + "defaultMessage": "免费邀请", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "WpvsPu": { + "defaultMessage": "订阅", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SNh1n0": { + "defaultMessage": "查看名单", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "2CqWQE": { + "defaultMessage": "总数", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "y0b6Kp": { + "defaultMessage": "付费", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "L0J61B": { + "defaultMessage": "免费", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SdXoXI": { + "defaultMessage": "你已寄出邀请给朋友们,快去已邀请管理查看他们加入的进度吧!", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, + "OIj8pQ": { + "defaultMessage": "成功发送邀请", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, + "lIir/P": { + "defaultMessage": "我知道了", + "description": "" + }, + "2uwwz+": { + "defaultMessage": "累计阅读时長代表了你的作品被登入用户阅读的总时数,每次阅读过程超过一定时间后才会计入。此外,同一个用户的多次阅读也会进行累计。", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, + "Z6cII7": { + "defaultMessage": "累计阅读时数", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, + "DXJ8ys": { + "defaultMessage": "阅读次数代表了你的作品被登入用户阅读的总次数,每次阅读过程超过一定时间后才会计入。此外,同一个用户的多次阅读也会进行累计。", + "description": "src/components/Dialogs/HelpDialog/index.tsx" } } diff --git a/lang/zh-Hant.json b/lang/zh-Hant.json index 43472f4151..569ce30535 100644 --- a/lang/zh-Hant.json +++ b/lang/zh-Hant.json @@ -719,10 +719,6 @@ "defaultMessage": "暫時隱藏公告欄 7 天", "description": "src/views/Home/Announcements/index.tsx" }, - "pla6ZF": { - "defaultMessage": "搜尋作品、標籤、作者", - "description": "src/components/Search/SearchBar/index.tsx" - }, "3kbIhS": { "defaultMessage": "未命名", "description": "" @@ -1061,5 +1057,237 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {篇文章} other {篇文章}}", "description": "" + }, + "ZAs170": { + "defaultMessage": "基本資料", + "description": "src/views/Circle/Settings/index.tsx" + }, + "DMlmcU": { + "defaultMessage": "免費資格", + "description": "src/views/Circle/Settings/index.tsx" + }, + "EQeKnO": { + "defaultMessage": "邀請管理", + "description": "src/views/Circle/Settings/index.tsx" + }, + "KLQ1/z": { + "defaultMessage": "圍爐創建成功", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "mjMpv4": { + "defaultMessage": "圍爐已更新", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "ei+kyp": { + "defaultMessage": "圍爐名稱", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "tW3hM/": { + "defaultMessage": "圍爐描述", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "CwWLOr": { + "defaultMessage": "給圍爐取一個吸引人的名字吧", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "QUqfbW": { + "defaultMessage": "說說圍爐的有趣之處,吸引支持者加入", + "description": "src/components/Forms/CreateCircleForm/Profile.tsx" + }, + "JXdbo8": { + "defaultMessage": "完成", + "description": "" + }, + "q9oMKE": { + "defaultMessage": "圍爐名稱", + "description": "" + }, + "QZXKhG": { + "defaultMessage": "設置圍爐網址(創建後不可修改)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "6BXcdo": { + "defaultMessage": "設定圍爐門檻(每月)", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "VwuiYK": { + "defaultMessage": "Oops!此網址已被使用了,換一個試試", + "description": "src/components/Forms/CreateCircleForm/Init.tsx" + }, + "gMZZ9I": { + "defaultMessage": "2-20 個字元,僅支持英文、數字或下劃線", + "description": "" + }, + "+7SAix": { + "defaultMessage": "2-12 個字元", + "description": "" + }, + "eov+J2": { + "defaultMessage": "自定義網址名稱", + "description": "" + }, + "8KFsZN": { + "defaultMessage": "閱讀次數", + "description": "" + }, + "LOefol": { + "defaultMessage": "上鎖", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, + "/podGX": { + "defaultMessage": "公開", + "description": "src/views/Circle/Analytics/ContentAnalytics/ContentTabs/index.tsx" + }, + "mCAIcg": { + "defaultMessage": "站內閱讀熱門排行", + "description": "src/views/Circle/Analytics/ContentAnalytics/index.tsx" + }, + "lNjDPr": { + "defaultMessage": "你還沒有邀請任何用戶喔!點擊新增邀請,添加站內或站外朋友加入圍爐贈與對方免費資格的固定時長", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx" + }, + "RxiHr/": { + "defaultMessage": "還沒有任何用戶回覆你的邀請喔!", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx" + }, + "b8ogKp": { + "defaultMessage": "新增邀請", + "description": "src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx" + }, + "FmWYRt": { + "defaultMessage": "免費資格時長", + "description": "" + }, + "Bc20la": { + "defaultMessage": "天", + "description": "" + }, + "O0QB1v": { + "defaultMessage": "用戶將收到你的圍爐免費資格邀請函,設置免費的時限,邀請他們一起加入吧!", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "rXnmeE": { + "defaultMessage": "確認發送", + "description": "" + }, + "ptqBN1": { + "defaultMessage": "暫時不要", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "tzq2+W": { + "defaultMessage": "寄出邀請", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx" + }, + "fWDtpq": { + "defaultMessage": "邀請中", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, + "JpS59y": { + "defaultMessage": "已接受", + "description": "src/views/Circle/Settings/ManageInvitation/Invites/index.tsx" + }, + "Bjdw71": { + "defaultMessage": "目前總追蹤人數", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "xWZr13": { + "defaultMessage": "{follower, plural, =1 {人} other {人}}", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "GugBCe": { + "defaultMessage": "本月新增追蹤人數", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "MDNaxs": { + "defaultMessage": "人", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "zKOr2x": { + "defaultMessage": "已追蹤用戶佔總觀看人數比例", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "AYTnjk": { + "defaultMessage": "追蹤", + "description": "src/views/Circle/Analytics/FollowerAnalytics/index.tsx" + }, + "sPgUkN": { + "defaultMessage": "本月營收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "Fe682o": { + "defaultMessage": "下月預期營收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "L4NXXh": { + "defaultMessage": "目前總營收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "d4waan": { + "defaultMessage": "營收", + "description": "src/views/Circle/Analytics/IncomeAnalytics/index.tsx" + }, + "6OBAOi": { + "defaultMessage": "目前總訂閱人數", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "zxy15q": { + "defaultMessage": "{subscriber, plural, =1 {人} other {人}}", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "TSDiqB": { + "defaultMessage": "付費人數", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "XHMco9": { + "defaultMessage": "人", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "1qQzV0": { + "defaultMessage": "免費邀請", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "WpvsPu": { + "defaultMessage": "訂閱", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SNh1n0": { + "defaultMessage": "查看名單", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "2CqWQE": { + "defaultMessage": "總數", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "y0b6Kp": { + "defaultMessage": "付費", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "L0J61B": { + "defaultMessage": "免費", + "description": "src/views/Circle/Analytics/SubscriberAnalytics/index.tsx" + }, + "SdXoXI": { + "defaultMessage": "你已寄出邀請給朋友們,快去已邀請管理查看他們加入的進度吧!", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, + "OIj8pQ": { + "defaultMessage": "成功發送邀請", + "description": "src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx" + }, + "lIir/P": { + "defaultMessage": "我知道了", + "description": "" + }, + "2uwwz+": { + "defaultMessage": "累計閱讀時數代表了你的作品被登入用戶閱讀的總時數,每次閱讀過程超過一定時間後才會計入。此外,同一個用戶的多次閱讀也會進行累計。", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, + "Z6cII7": { + "defaultMessage": "累計閱讀時數", + "description": "src/components/Dialogs/HelpDialog/index.tsx" + }, + "DXJ8ys": { + "defaultMessage": "閱讀次數代表了你的作品被登入用戶閱讀的總次數,每次閱讀過程超過一定時間後才會計入。此外,同一個用戶的多次閱讀也會進行累計。", + "description": "src/components/Dialogs/HelpDialog/index.tsx" } } diff --git a/package.json b/package.json index 9383359928..03766085e3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matters-web", - "version": "4.17.2", + "version": "4.18.0", "description": "codebase of Matters' website", "sideEffects": false, "author": "Matters ", diff --git a/public/static/icons/24px/disableComment.svg b/public/static/icons/24px/disableComment.svg new file mode 100644 index 0000000000..ff0899c95f --- /dev/null +++ b/public/static/icons/24px/disableComment.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/public/static/icons/uncheckedGrey.svg b/public/static/icons/uncheckedGrey.svg new file mode 100644 index 0000000000..e5cef1816c --- /dev/null +++ b/public/static/icons/uncheckedGrey.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/static/images/illustration-empty-search-history.png b/public/static/images/illustration-empty-search-history.png new file mode 100644 index 0000000000..74b44cf9d0 Binary files /dev/null and b/public/static/images/illustration-empty-search-history.png differ diff --git a/src/common/enums/index.ts b/src/common/enums/index.ts index ec83b23bd8..6473056949 100644 --- a/src/common/enums/index.ts +++ b/src/common/enums/index.ts @@ -13,6 +13,7 @@ export * from './oauth' export * from './payment' export * from './responsive' export * from './route' +export * from './search' export * from './storage' export * from './test' export * from './text' diff --git a/src/common/enums/search.ts b/src/common/enums/search.ts new file mode 100644 index 0000000000..1dc0b9dfa4 --- /dev/null +++ b/src/common/enums/search.ts @@ -0,0 +1,17 @@ +export const MIN_QUICK_SEARCH_KEY_LENGTH = 2 + +export const MAX_QUICK_SEARCH_KEY_LENGTH = 10 + +export const SEARCH_START_FLAG = '@#@#' + +export const MAX_SEARCH_KEY_LENGTH = 60 + +export const MAX_SEARCH_RESULTS_LENGTH = 200 + +export const FIRST_SEARCH_RESULTS_LENGTH = 30 + +export const LATER_SEARCH_RESULTS_LENGTH = 20 + +export const SEARCH_HISTORY_LENGTH = 20 + +export const SEARCH_HISTORY_DISPLAY_LENGTH = 10 diff --git a/src/common/enums/storage.ts b/src/common/enums/storage.ts index 27257a7c37..6bb6468721 100644 --- a/src/common/enums/storage.ts +++ b/src/common/enums/storage.ts @@ -7,3 +7,5 @@ export const STORAGE_KEY_ONBOARDING_TASKS = '__ONBOARDING_TASKS' export const STORAGE_KEY_CIRCLE_BANNER = '__CIRCLE_BANNER' export const STORAGE_KEY_ANNOUNCEMENT = '__ANNOUNCEMENT' + +export const STORAGE_KEY_SEARCH_HISTORY = '__SEARCH_HISTORY' diff --git a/src/common/enums/text.ts b/src/common/enums/text.ts index 83e4cb9f95..5d0defee0e 100644 --- a/src/common/enums/text.ts +++ b/src/common/enums/text.ts @@ -21,6 +21,8 @@ export const TEXT = { all: '全部', allAuthors: '全部作者', allIcymi: '不要錯過', + allowResponses: '開啟回應', + allowResponsesHint: '允許讀者回應本文(開啟後無法關閉)', allTags: '全部標籤', allTopics: '熱議廣場', likesReceived: '讚賞我的', @@ -35,6 +37,7 @@ export const TEXT = { articleBanned: '作品因違反社區約章被隱藏', articleFingerprint: '作品指紋', articleManagement: '作品管理', + articleResponse: '回應設置', ASSET_NOT_FOUND: '資源不存在', back: '返回', backToDiscover: '返回發現', @@ -83,6 +86,8 @@ export const TEXT = { delete: '刪除', deleteArticleTag: '作品已移除標籤', deleteDraft: '刪除草稿', + disableResponses: '關閉回應', + disableResponsesHint: '不允許讀者回應本文(可通過修訂打開回應功能)', disagree: '我不同意', discover: '發現', DISPLAYNAME_INVALID: '名稱不正確', @@ -426,6 +431,8 @@ export const TEXT = { all: '全部', allAuthors: '全部作者', allIcymi: '不要错过', + allowResponses: '开启回应', + allowResponsesHint: '允许读者回应本文(开启后无法关闭)', allTags: '全部标签', allTopics: '热议广场', likesReceived: '赞赏我的', @@ -440,6 +447,7 @@ export const TEXT = { articleBanned: '作品因违反社区约章被隐藏', articleFingerprint: '作品指纹', articleManagement: '作品管理', + articleResponse: '回应设置', ASSET_NOT_FOUND: '资源不存在', back: '返回', backToDiscover: '返回发现', @@ -488,6 +496,8 @@ export const TEXT = { delete: '删除', deleteArticleTag: '作品已移除标签', deleteDraft: '刪除草稿', + disableResponses: '关闭回应', + disableResponsesHint: '不允许读者回应本文(可通过编辑打开回应功能)', disagree: '我不同意', discover: '发现', DISPLAYNAME_INVALID: '名称不正确', @@ -831,6 +841,9 @@ export const TEXT = { all: 'All time', allAuthors: 'All Authors', allIcymi: `Matters' Choice`, + allowResponses: 'Allow Responses', + allowResponsesHint: + 'Allow readers to respond to this article (can NOT be disabled afterwards)', allTags: 'Tags', allTopics: 'Recommended Topics', likesReceived: 'Likes Received', @@ -845,6 +858,7 @@ export const TEXT = { articleBanned: 'The article has been archived due to violation of terms', articleFingerprint: 'Content Hash', articleManagement: 'Article Management', + articleResponse: 'Response', ASSET_NOT_FOUND: 'Asset not found', back: 'Back', backToDiscover: 'Back to discovery', @@ -901,6 +915,9 @@ export const TEXT = { deleteArticleTag: 'Tag Removed', deleteComment: 'Delete', deleteDraft: 'Delete Draft', + disableResponses: 'Disable Responses', + disableResponsesHint: + 'Disallow readers to respond to this article (you can enable responses later by editing this article)', disagree: 'Disagree', discover: 'Discover', DISPLAYNAME_INVALID: 'Invalid display name', diff --git a/src/common/utils/analytics.ts b/src/common/utils/analytics.ts index 296a63bd14..3c219fdd6c 100644 --- a/src/common/utils/analytics.ts +++ b/src/common/utils/analytics.ts @@ -84,7 +84,9 @@ interface LoadMoreProp { | UserFeedType | TagFeedType | CircleFeedType + | 'quick_search' location: number + searchKey?: string } /** @@ -137,6 +139,7 @@ interface ClickFeedProp { contentType: ContentType | ActivityType location: number | string id?: string + searchKey?: string } /** @@ -158,7 +161,13 @@ interface TagExposureProp { } // content type -export type ContentType = 'article' | 'comment' | 'circle' | 'user' | 'tag' +export type ContentType = + | 'article' + | 'comment' + | 'circle' + | 'user' + | 'tag' + | 'key' export type ActivityType = | 'UserPublishArticleActivity' | 'UserBroadcastCircleActivity' @@ -182,6 +191,7 @@ export type FeedType = | TagFeedType | CircleFeedType | 'following' + | 'search_history' type ArticleFeedType = | 'all_authors' @@ -231,6 +241,7 @@ type UserFeedType = | 'newest' | 'search' | 'search_user' + | 'quick_search_user' | 'tag_detail_latest' | 'tag_detail_selected' | 'tag_detail_community' @@ -244,6 +255,7 @@ type TagFeedType = // | 'follow-tag' | 'search' | 'search_tag' + | 'quick_search_tag' | 'tags' // tag feed on home page | 'user_tag' diff --git a/src/common/utils/index.ts b/src/common/utils/index.ts index 1fc3b7f084..367eb4afff 100644 --- a/src/common/utils/index.ts +++ b/src/common/utils/index.ts @@ -18,6 +18,7 @@ export * from './payment' export * from './random' export * from './response' export * from './route' +export * from './search' export * from './storage' export * from './text' export * from './time' diff --git a/src/common/utils/search.ts b/src/common/utils/search.ts new file mode 100644 index 0000000000..7b6a901c78 --- /dev/null +++ b/src/common/utils/search.ts @@ -0,0 +1,6 @@ +export type SearchType = 'article' | 'user' | 'tag' | undefined + +export const getSearchType = (value: string): SearchType => { + const types = ['article', 'user', 'tag'] + return types.includes(value) ? (value as SearchType) : undefined +} diff --git a/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx b/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx index 4b6f6113ff..950b35eb2d 100644 --- a/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx +++ b/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx @@ -3,12 +3,7 @@ import _isArray from 'lodash/isArray' import { FormattedMessage } from 'react-intl' import { REFETCH_TAG_DETAIL_ARTICLES } from '~/common/enums' -import { - IconRemove24, - Menu, - TextIcon, - useMutation, -} from '~/components' +import { IconRemove24, Menu, TextIcon, useMutation } from '~/components' import updateTagArticlesCount from '~/components/GQL/updates/tagArticlesCount' import { DeleteArticlesTagsMutation, @@ -75,7 +70,10 @@ const RemoveTagButton = ({ }} > } size="md" spacing="base"> - + ) diff --git a/src/components/ArticleDigest/Feed/index.tsx b/src/components/ArticleDigest/Feed/index.tsx index f2041ec6f7..c2b5456733 100644 --- a/src/components/ArticleDigest/Feed/index.tsx +++ b/src/components/ArticleDigest/Feed/index.tsx @@ -2,7 +2,13 @@ import React from 'react' import { TEST_ID } from '~/common/enums' import { stripHtml, toPath, UtmParams } from '~/common/utils' -import { Card, CircleDigest, ResponsiveImage } from '~/components' +import { + Card, + CardProps, + CircleDigest, + DateTime, + ResponsiveImage, +} from '~/components' import { UserDigest } from '~/components/UserDigest' import { ArticleDigestFeedArticlePrivateFragment, @@ -18,6 +24,7 @@ import styles from './styles.css' export type ArticleDigestFeedControls = { onClick?: () => any onClickAuthor?: () => void + isConciseFooter?: boolean hasFollow?: boolean hasCircle?: boolean } @@ -28,13 +35,15 @@ export type ArticleDigestFeedProps = { header?: React.ReactNode } & ArticleDigestFeedControls & FooterActionsProps & - UtmParams + UtmParams & + Pick const BaseArticleDigestFeed = ({ article, header, date, + isConciseFooter = false, hasFollow, hasCircle = true, onClick, @@ -42,6 +51,7 @@ const BaseArticleDigestFeed = ({ utm_source, utm_medium, + is, ...controls }: ArticleDigestFeedProps) => { @@ -66,6 +76,7 @@ const BaseArticleDigestFeed = ({ spacing={['base', 'base']} onClick={onClick} testId={TEST_ID.DIGEST_ARTICLE_FEED} + is={is} > {header || (hasCircle && circle && ( @@ -103,7 +114,14 @@ const BaseArticleDigestFeed = ({ )} - + {isConciseFooter && ( +
+ +
+ )} + {!isConciseFooter && ( + + )} diff --git a/src/components/Comment/DropdownActions/CollapseComment/Button.tsx b/src/components/Comment/DropdownActions/CollapseComment/Button.tsx index 0b3e37f36b..d37d3ba16b 100644 --- a/src/components/Comment/DropdownActions/CollapseComment/Button.tsx +++ b/src/components/Comment/DropdownActions/CollapseComment/Button.tsx @@ -6,7 +6,10 @@ const CollapseCommentButton = ({ openDialog }: { openDialog: () => void }) => { return ( } size="md" spacing="base"> - + ) diff --git a/src/components/Comment/DropdownActions/DeleteComment/Dialog.tsx b/src/components/Comment/DropdownActions/DeleteComment/Dialog.tsx index 9aeba1687b..896ea10b9e 100644 --- a/src/components/Comment/DropdownActions/DeleteComment/Dialog.tsx +++ b/src/components/Comment/DropdownActions/DeleteComment/Dialog.tsx @@ -39,7 +39,7 @@ const DeleteCommentDialog = ({ const commentId = comment.id const { lang } = useContext(LanguageContext) - + const [deleteComment] = useMutation(DELETE_COMMENT, { variables: { id: commentId }, optimisticResponse: { @@ -59,9 +59,13 @@ const DeleteCommentDialog = ({ detail: { color: 'green', content: ( - + ), buttonPlacement: 'center', @@ -77,9 +81,13 @@ const DeleteCommentDialog = ({ + } closeDialog={closeDialog} mode="inner" @@ -87,9 +95,13 @@ const DeleteCommentDialog = ({

- +

@@ -101,7 +113,7 @@ const DeleteCommentDialog = ({ closeDialog() }} > - + void }) => React.ReactNode } & HelpDetailProps -const time = { - zh_hant: - '累計閱讀時數代表了你的作品被登入用戶閱讀的總時數,每次閱讀過程超過一定時間後才會計入。' + - '此外,同一個用戶的多次閱讀也會進行累計。', - zh_hans: - '累计阅读时長代表了你的作品被登入用户阅读的总时数,每次阅读过程超过一定时间后才会计入。' + - '此外,同一个用户的多次阅读也会进行累计。', - en: 'Accumulated read time indicates the total time length that registered users read.', -} - -const count = { - zh_hant: - '閱讀次數代表了你的作品被登入用戶閱讀的總次數,每次閱讀過程超過一定時間後才會計入。' + - '此外,同一個用戶的多次閱讀也會進行累計。', - zh_hans: - '阅读次数代表了你的作品被登入用户阅读的总次数,每次阅读过程超过一定时间后才会计入' + - '此外,同一个用户的多次阅读也会进行累计。', - en: 'Read counts indicates how many registered users read.', -} - const ReadTime = () => ( <>

} weight="md"> - +

- +

@@ -54,16 +36,12 @@ const ReadTime = () => ( const ReadCount = () => ( <>

- } weight="md"> - + } weight="md"> +

- +

@@ -78,7 +56,7 @@ const BaseHelpDialog = ({ children, hasCount, hasTime }: Props) => { } + title={} closeDialog={closeDialog} /> @@ -93,7 +71,7 @@ const BaseHelpDialog = ({ children, hasCount, hasTime }: Props) => { bgColor="green" onClick={closeDialog} > - +
diff --git a/src/components/Editor/BottomBar/AccessDialog/index.tsx b/src/components/Editor/BottomBar/AccessDialog/index.tsx index 7d22cee1c2..d3d4a306f2 100644 --- a/src/components/Editor/BottomBar/AccessDialog/index.tsx +++ b/src/components/Editor/BottomBar/AccessDialog/index.tsx @@ -1,16 +1,29 @@ import _get from 'lodash/get' -import { Dialog, Translate, useDialogSwitch } from '~/components' +import { Dialog, Spacer, Translate, useDialogSwitch } from '~/components' import ToggleAccess, { ToggleAccessProps } from '../../ToggleAccess' +import ToggleResponse, { ToggleResponseProps } from '../../ToggleResponse' type AccessDialogProps = { children: ({ openDialog }: { openDialog: () => void }) => React.ReactNode -} & ToggleAccessProps - -const BaseAccessDialog = ({ children, ...props }: AccessDialogProps) => { +} & ToggleAccessProps & + ToggleResponseProps + +const BaseAccessDialog = ({ + children, + canComment, + toggleComment, + ...props +}: AccessDialogProps) => { const { show, openDialog, closeDialog } = useDialogSwitch(true) + const toggleResponseProps: ToggleResponseProps = { + canComment, + toggleComment, + disableChangeCanComment: props.article?.canComment, + } + return ( <> {children({ openDialog })} @@ -29,6 +42,8 @@ const BaseAccessDialog = ({ children, ...props }: AccessDialogProps) => { /> + + diff --git a/src/components/Editor/BottomBar/index.tsx b/src/components/Editor/BottomBar/index.tsx index 772eac51a6..c90eb48f36 100644 --- a/src/components/Editor/BottomBar/index.tsx +++ b/src/components/Editor/BottomBar/index.tsx @@ -16,8 +16,10 @@ import { SearchSelectDialog } from '~/components/Dialogs/SearchSelectDialog' import { SetCollectionProps, SetCoverProps, + SetResponseProps, SetTagsProps, ToggleAccessProps, + ToggleResponseProps, } from '~/components/Editor' import { SearchSelectNode } from '~/components/Forms/SearchSelectForm' import { @@ -37,6 +39,7 @@ export type BottomBarProps = { } & SetCoverProps & SetCollectionProps & SetTagsProps & + SetResponseProps & ToggleAccessProps /** @@ -77,6 +80,9 @@ const BottomBar: React.FC = ({ togglePublishISCN, iscnPublishSaving, + canComment, + toggleComment, + saving, disabled, }) => { @@ -96,7 +102,7 @@ const BottomBar: React.FC = ({ entityType, coverSaving, } - const accessProps: ToggleAccessProps = { + const accessProps: ToggleAccessProps & ToggleResponseProps = { circle, accessType, license, @@ -113,6 +119,10 @@ const BottomBar: React.FC = ({ iscnPublish, togglePublishISCN, iscnPublishSaving, + + canComment, + toggleComment, + disableChangeCanComment: article?.canComment, } return ( @@ -201,7 +211,7 @@ const BottomBar: React.FC = ({ )} - {/* Circle & License & Support Feedback & ISCN */} + {/* Circle & License & Support Feedback & ISCN & canComment */} {({ openDialog }) => ( + ) +} + export const SearchBar: React.FC = ({ onChange, hasDropdown = true, }) => { - const { getQuery, router } = useRoute() + const { getQuery, router, isInPath } = useRoute() + const isInSearch = isInPath('SEARCH') const q = getQuery('q') - const [search, setSearch] = useState('') + const type = getSearchType(getQuery('type')) + const [search, setSearch] = useState(q) const [debouncedSearch] = useDebounce(search, INPUT_DEBOUNCE) const intl = useIntl() @@ -59,15 +83,85 @@ export const SearchBar: React.FC = ({ description: '', }) const textPlaceholder = intl.formatMessage({ - defaultMessage: 'Search articles, tags and authors', - description: 'src/components/Search/SearchBar/index.tsx', + defaultMessage: 'Search', + description: '', }) + const searchTextInput = useRef(null) + // dropdown const [showDropdown, setShowDropdown] = useState(false) const closeDropdown = () => setShowDropdown(false) const openDropdown = () => setShowDropdown(true) + // quick result hotkeys + const [data, setData] = useState() + const [activeItem, setActiveItem] = useState('input') + const resetActiveItem = () => setActiveItem('input') + const items = ['input'] + const { edges: userEdges } = data?.user || {} + const { edges: tagEdges } = data?.tag || {} + const hasUsers = userEdges && userEdges.length > 0 + const hasTags = tagEdges && tagEdges.length > 0 + + if (hasUsers) { + userEdges.map(({ cursor }, i) => { + items.push(`user${cursor}`) + }) + } + if (hasTags) { + tagEdges.map(({ cursor }, i) => { + items.push(`tag${cursor}`) + }) + } + + useNativeEventListener( + 'keydown', + (e: { code: string; preventDefault: () => void }) => { + if (e.code === 'ArrowUp') { + if (!showDropdown) return + + e.preventDefault() + const activeIndex = items.indexOf(activeItem) + if (activeIndex === 0) return + + setActiveItem(items[activeIndex - 1]) + } + + if (e.code === 'ArrowDown') { + if (!showDropdown) return + + e.preventDefault() + const activeIndex = items.indexOf(activeItem) + if (activeIndex === items.length - 1) return + + setActiveItem(items[activeIndex + 1]) + } + + if (e.code === 'Escape') { + if (!showDropdown) return + + setShowDropdown(false) + } + }, + true + ) + + useEffect(() => { + if ( + hasDropdown && + showDropdown && + searchTextInput.current && + activeItem === 'input' + ) { + searchTextInput.current.focus() + } + }, [activeItem]) + + useEffect(() => { + setSearch(q) + }, [q]) + useEffect(() => { if (onChange) { onChange(debouncedSearch) @@ -81,13 +175,24 @@ export const SearchBar: React.FC = ({ onSubmit={(values) => { const path = toPath({ page: 'search', - q: values.q.slice(0, 100), + q: encodeURIComponent(values.q.slice(0, MAX_SEARCH_KEY_LENGTH)), + type, }) - router.push(path.href) + + if (values.q.length <= 0) return + + searchTextInput.current?.blur() + + if (isInSearch) { + router.replace(path.href) + } else { + router.push(path.href) + } + closeDropdown() }} > - {({ values, handleSubmit, handleChange }) => { + {({ values, setValues, handleSubmit, handleChange }) => { if (!hasDropdown) { return ( = ({ aria-label={textPlaceholder} role="search" autoComplete="off" + action="" > = ({ setSearch(e.target.value) }} value={values.q} + maxLength={MAX_SEARCH_KEY_LENGTH} /> + {search.length > 0 && ( + { + setValues({ q: '' }) + setSearch('') + }} + /> + )} @@ -119,10 +235,22 @@ export const SearchBar: React.FC = ({ return ( - ) : ( - + !isInSearch && + debouncedSearch && ( + { + setData(newData) + }} + closeDropdown={() => { + closeDropdown() + + // clear input + setValues({ q: '' }) + setSearch('') + }} + activeItem={activeItem} + /> ) } trigger={undefined} @@ -132,20 +260,23 @@ export const SearchBar: React.FC = ({ visible={showDropdown} zIndex={Z_INDEX.OVER_GLOBAL_HEADER} > -
+ { handleChange(e) setSearch(e.target.value) + resetActiveItem() openDropdown() }} onFocus={openDropdown} onClick={openDropdown} + maxLength={MAX_SEARCH_KEY_LENGTH} /> diff --git a/src/components/Search/SearchBar/styles.css b/src/components/Search/SearchBar/styles.css index 38aee1579d..f8bc2fa106 100644 --- a/src/components/Search/SearchBar/styles.css +++ b/src/components/Search/SearchBar/styles.css @@ -19,8 +19,9 @@ form { padding: 0 var(--spacing-base) 0 var(--search-bar-button-width); font-size: var(--font-size-sm); color: var(--color-black); + text-overflow: ellipsis; background-color: var(--color-grey-lighter); - border: 1px solid var(--color-grey-lighter); + border: 1px solid var(--color-line-grey-light); border-radius: var(--search-bar-height); transition-property: border-color, background-color; @@ -42,4 +43,12 @@ form { width: var(--search-bar-button-width); height: 100%; } + + & :global(button[type='button']) { + position: absolute; + top: 0; + right: 0; + width: var(--search-bar-button-width); + height: 100%; + } } diff --git a/src/components/Search/SearchHistory/EmptySearchHistory/index.tsx b/src/components/Search/SearchHistory/EmptySearchHistory/index.tsx new file mode 100644 index 0000000000..2e036bd0a5 --- /dev/null +++ b/src/components/Search/SearchHistory/EmptySearchHistory/index.tsx @@ -0,0 +1,23 @@ +import IMAGE_EMPTY_SEARCH_HISTORY from '@/public/static/images/illustration-empty-search-history.png' +import { Translate } from '~/components' + +import styles from './styles.css' + +const EmptySearchHistory = () => { + return ( +
+ empty search history +
+ +
+ + +
+ ) +} + +export default EmptySearchHistory diff --git a/src/components/Search/SearchHistory/EmptySearchHistory/styles.css b/src/components/Search/SearchHistory/EmptySearchHistory/styles.css new file mode 100644 index 0000000000..9c36c53e0c --- /dev/null +++ b/src/components/Search/SearchHistory/EmptySearchHistory/styles.css @@ -0,0 +1,17 @@ +.container { + @mixin flex-center-all; + + flex-direction: column; + padding: 2.5rem 2rem 0; + + & img { + height: 200px; + } + + & .hint { + padding-top: var(--spacing-x-tight); + font-size: var(--font-size-sm-s); + line-height: 1.5rem; + color: var(--color-grey-darker); + } +} diff --git a/src/components/Search/SearchHistory/index.tsx b/src/components/Search/SearchHistory/index.tsx new file mode 100644 index 0000000000..2abe19340f --- /dev/null +++ b/src/components/Search/SearchHistory/index.tsx @@ -0,0 +1,61 @@ +import { analytics, toPath } from '~/common/utils' +import { Button, IconClose32, Menu, TextIcon, Translate } from '~/components' + +interface SearchHistoryProps { + data: string[] | undefined + removeSearchHistoryItem: (value: string) => void +} +import EmptySearchHistory from './EmptySearchHistory' +import styles from './styles.css' + +export const SearchHistory = ({ + data, + removeSearchHistoryItem, +}: SearchHistoryProps) => { + if (!data || data.length <= 0) { + return + } + + return ( +
+
+ + + +
+ + {data.map((value, i) => ( + { + analytics.trackEvent('click_feed', { + type: 'search_history', + contentType: 'key', + location: i, + searchKey: value, + }) + }} + > +
+ {value} + +
+
+ ))} +
+ +
+ ) +} diff --git a/src/components/Search/SearchHistory/styles.css b/src/components/Search/SearchHistory/styles.css new file mode 100644 index 0000000000..770c6c91b6 --- /dev/null +++ b/src/components/Search/SearchHistory/styles.css @@ -0,0 +1,17 @@ +.title { + padding: var(--spacing-loose) var(--spacing-base) var(--spacing-base); +} + +.item { + @mixin flex-center-space-between; + + & .key { + @mixin line-clamp; + + font-size: var(--font-size-md-s); + font-weight: var(--font-weight-medium); + line-height: 1.5rem; + color: var(--color-black); + word-break: break-all; + } +} diff --git a/src/components/Search/SearchQuickResult/TriggerFullSearchItem.tsx b/src/components/Search/SearchQuickResult/TriggerFullSearchItem.tsx new file mode 100644 index 0000000000..7e504b12b7 --- /dev/null +++ b/src/components/Search/SearchQuickResult/TriggerFullSearchItem.tsx @@ -0,0 +1,32 @@ +import { toPath } from '~/common/utils' +import { IconArrowRight16, Menu, TextIcon, Translate } from '~/components' + +interface TriggerFullSearchItemProps { + searchKey: string +} + +const TriggerFullSearchItem = ({ searchKey }: TriggerFullSearchItemProps) => { + return ( + + } + color="green" + weight="md" + textPlacement="left" + > + + + + ) +} + +export default TriggerFullSearchItem diff --git a/src/components/Search/SearchQuickResult/gql.ts b/src/components/Search/SearchQuickResult/gql.ts new file mode 100644 index 0000000000..88fcf9875a --- /dev/null +++ b/src/components/Search/SearchQuickResult/gql.ts @@ -0,0 +1,49 @@ +import gql from 'graphql-tag' + +// TODO: Why this line don't work +// import { TagDigest, UserDigest } from '~/components' +import { TagDigest } from '~/components/TagDigest' +import { UserDigest } from '~/components/UserDigest' + +export const QUICK_RESULT = gql` + query QuickResult($key: String!, $version: SearchAPIVersion = v20221212) { + user: search( + input: { + type: User + quicksearch: true + version: $version + first: 5 + key: $key + } + ) { + edges { + cursor + node { + ... on User { + ...UserDigestConciseUser + } + } + } + } + tag: search( + input: { + type: Tag + quicksearch: true + version: $version + first: 5 + key: $key + } + ) { + edges { + cursor + node { + ... on Tag { + ...TagDigestConciseTag + } + } + } + } + } + ${UserDigest.Concise.fragments.user} + ${TagDigest.Concise.fragments.tag} +` diff --git a/src/components/Search/SearchQuickResult/index.tsx b/src/components/Search/SearchQuickResult/index.tsx new file mode 100644 index 0000000000..425c0655e6 --- /dev/null +++ b/src/components/Search/SearchQuickResult/index.tsx @@ -0,0 +1,180 @@ +import { useApolloClient } from '@apollo/react-hooks' +import { Fragment, useEffect, useState } from 'react' + +import { + MAX_QUICK_SEARCH_KEY_LENGTH, + MIN_QUICK_SEARCH_KEY_LENGTH, + SEARCH_START_FLAG, +} from '~/common/enums' +import { analytics, toPath } from '~/common/utils' +import { + Media, + Menu, + Spacer, + Spinner, + TagDigest, + UserDigest, + useRoute, +} from '~/components' +import { QuickResultQuery } from '~/gql/graphql' + +import { QUICK_RESULT } from './gql' +import TriggerFullSearchItem from './TriggerFullSearchItem' + +interface QuickSearchProps { + searchKey: string + activeItem?: string + onUpdateData?: (data: QuickResultQuery | undefined) => void + closeDropdown: () => void + + inPage?: boolean +} + +export const SearchQuickResult = (props: QuickSearchProps) => { + // TODO: Just test for team, will be removed when release + const { getQuery } = useRoute() + const version = getQuery('version') + + const { searchKey, inPage, activeItem, onUpdateData, closeDropdown } = props + const client = useApolloClient() + const [data, setData] = useState() + const clearData = () => setData(undefined) + const [loading, setLoading] = useState(false) + + const { edges: userEdges } = data?.user || {} + const { edges: tagEdges } = data?.tag || {} + + const hasUsers = userEdges && userEdges.length > 0 + const hasTags = tagEdges && tagEdges.length > 0 + + useEffect(() => { + if (onUpdateData) { + onUpdateData(data) + } + }, [JSON.stringify(data)]) + + useEffect(() => { + ;(async () => { + clearData() + if ( + SEARCH_START_FLAG.includes(searchKey[0]) && + (searchKey.length < MIN_QUICK_SEARCH_KEY_LENGTH + 1 || + searchKey.length > MAX_QUICK_SEARCH_KEY_LENGTH + 1) + ) { + return + } + + if ( + searchKey.length < MIN_QUICK_SEARCH_KEY_LENGTH || + searchKey.length > MAX_QUICK_SEARCH_KEY_LENGTH + ) + return + + setLoading(true) + // Why not useLazyQuery 👇🔗 + // https://github.com/apollographql/apollo-client/issues/5912 + const response = await client.query({ + query: QUICK_RESULT, + variables: { + key: searchKey, + version: version === '' ? undefined : version, + }, + fetchPolicy: 'no-cache', + }) + analytics.trackEvent('load_more', { + type: 'quick_search', + location: 0, + searchKey: searchKey, + }) + setData(response.data) + setLoading(response.loading) + })() + }, [searchKey]) + + if (loading) { + return ( + + + + ) + } + + if (!hasUsers && !hasTags) { + return null + } + + return ( + + + + + + {hasUsers && + userEdges.map( + ({ node, cursor }, i) => + node.__typename === 'User' && ( + + { + closeDropdown() + analytics.trackEvent('click_feed', { + type: 'quick_search_user', + contentType: 'user', + location: i, + id: node.id, + searchKey: searchKey, + }) + }} + > + + + + ) + )} + {hasUsers && } + {hasUsers && hasTags && } + {hasUsers && } + {hasTags && + tagEdges.map( + ({ node, cursor }, i) => + node.__typename === 'Tag' && ( + + { + closeDropdown() + analytics.trackEvent('click_feed', { + type: 'quick_search_tag', + contentType: 'tag', + location: i, + id: node.id, + searchKey: searchKey, + }) + }} + > + + + + ) + )} + + ) +} diff --git a/src/components/Search/index.tsx b/src/components/Search/index.tsx index d991de45ef..55f2576179 100644 --- a/src/components/Search/index.tsx +++ b/src/components/Search/index.tsx @@ -1,3 +1,6 @@ export * from './SearchAutoComplete' export * from './SearchBar' +export * from './SearchHistory' +export * from './SearchHistory' export * from './SearchOverview' +export * from './SearchQuickResult' diff --git a/src/components/TagDigest/Concise/index.tsx b/src/components/TagDigest/Concise/index.tsx new file mode 100644 index 0000000000..a94405c5bb --- /dev/null +++ b/src/components/TagDigest/Concise/index.tsx @@ -0,0 +1,70 @@ +import gql from 'graphql-tag' + +import { numAbbr, toPath } from '~/common/utils' +import { + IconArticle16, + IconHashTag16, + LinkWrapper, + TextIcon, +} from '~/components' +import { TagDigestConciseTagFragment } from '~/gql/graphql' + +import styles from './styles.css' + +export type TagDigestConciseTagProps = { + tag: TagDigestConciseTagFragment + textSize?: 'sm' | 'md-s' + showArticlesNum?: boolean +} + +const fragments = { + tag: gql` + fragment TagDigestConciseTag on Tag { + id + content + numArticles + } + `, +} + +const Concise = ({ + tag, + textSize = 'md-s', + showArticlesNum, +}: TagDigestConciseTagProps) => { + const path = toPath({ + page: 'tagDetail', + tag, + }) + return ( + +
+ } + color="black" + size={textSize} + spacing="xxtight" + weight="md" + > + {tag.content} + + + {showArticlesNum && ( + } + size="xs" + spacing="xxtight" + color="grey-dark" + > + {numAbbr(tag.numArticles)} + + )} + +
+
+ ) +} + +Concise.fragments = fragments + +export default Concise diff --git a/src/components/TagDigest/Concise/styles.css b/src/components/TagDigest/Concise/styles.css new file mode 100644 index 0000000000..8e95ee81d6 --- /dev/null +++ b/src/components/TagDigest/Concise/styles.css @@ -0,0 +1,5 @@ +.content { + & :global(span + span) { + margin-left: 0.625rem; + } +} diff --git a/src/components/TagDigest/index.tsx b/src/components/TagDigest/index.tsx index faae96e758..f5fd06a8db 100644 --- a/src/components/TagDigest/index.tsx +++ b/src/components/TagDigest/index.tsx @@ -1,8 +1,10 @@ +import Concise from './Concise' import Feed from './Feed' import Rich from './Rich' import Sidebar from './Sidebar' export const TagDigest = { + Concise, Rich, Sidebar, Feed, diff --git a/src/components/UserDigest/Concise/gql.ts b/src/components/UserDigest/Concise/gql.ts new file mode 100644 index 0000000000..a9dfbac214 --- /dev/null +++ b/src/components/UserDigest/Concise/gql.ts @@ -0,0 +1,20 @@ +import gql from 'graphql-tag' + +import { Avatar } from '~/components/Avatar' + +export const fragments = { + user: gql` + fragment UserDigestConciseUser on User { + id + userName + displayName + status { + state + } + ...AvatarUser + ...AvatarUserLogbook + } + ${Avatar.fragments.user} + ${Avatar.fragments.logbook} + `, +} diff --git a/src/components/UserDigest/Concise/index.tsx b/src/components/UserDigest/Concise/index.tsx new file mode 100644 index 0000000000..619951b453 --- /dev/null +++ b/src/components/UserDigest/Concise/index.tsx @@ -0,0 +1,102 @@ +import classNames from 'classnames' + +import { toPath } from '~/common/utils' +import { LinkWrapper, Translate } from '~/components' +import { Avatar, AvatarProps, AvatarSize } from '~/components/Avatar' +import { UserDigestConciseUserFragment } from '~/gql/graphql' + +import { fragments } from './gql' +import styles from './styles.css' + +/** + * UserDigest.Concise is a component for presenting user's: + * + * - avatar + * - userName + * - displayName + * + * Usage: + * + * + */ + +export type UserDigestConciseProps = { + user: UserDigestConciseUserFragment + avatarSize?: Extract + nameStyle?: 'tight' | 'loose' + + disabled?: boolean + onClick?: () => void +} & AvatarProps + +export const toUserDigestConcisePlaceholder = (displayName: string) => + ({ + __typename: 'User', + id: '', + userName: '', + displayName, + status: null, + avatar: null, + liker: { + __typename: 'Liker', + civicLiker: false, + }, + } as UserDigestConciseUserFragment) + +const Concise = ({ + user, + avatarSize, + nameStyle = 'loose', + disabled, + + onClick, +}: UserDigestConciseProps) => { + const isArchived = user?.status?.state === 'archived' + const path = toPath({ + page: 'userProfile', + userName: user.userName || '', + }) + const containerClasses = classNames({ + container: true, + disabled: disabled || isArchived, + }) + const nameClasses = classNames({ + name: true, + [`name-style-${nameStyle}`]: !!nameStyle, + }) + + if (isArchived) { + return ( + + + + + + + + + + + + ) + } + + return ( + +
+ + + + {user.displayName} + {user.userName && @{user.userName}} + + + +
+
+ ) +} + +Concise.fragments = fragments + +export default Concise diff --git a/src/components/UserDigest/Concise/styles.css b/src/components/UserDigest/Concise/styles.css new file mode 100644 index 0000000000..1e6264a135 --- /dev/null +++ b/src/components/UserDigest/Concise/styles.css @@ -0,0 +1,46 @@ +.container { + @mixin flex-center-start; +} + +.name { + display: flex; + flex-flow: column wrap; + align-items: flex-start; + margin-left: var(--spacing-x-tight); +} + +.displayname { + @mixin line-clamp; + + font-weight: var(--font-weight-medium); +} + +.username { + @mixin line-clamp; + + color: var(--color-grey); +} + +.name-style-loose { + & .displayname { + font-size: var(--font-size-md-s); + line-height: 1.5rem; + } + + & .username { + font-size: var(--font-size-sm-s); + line-height: 1.5rem; + } +} + +.name-style-tight { + & .displayname { + font-size: var(--font-size-sm); + line-height: 1rem; + } + + & .username { + font-size: var(--font-size-xs); + line-height: 1rem; + } +} diff --git a/src/components/UserDigest/index.tsx b/src/components/UserDigest/index.tsx index bb4b147434..470b797c1a 100644 --- a/src/components/UserDigest/index.tsx +++ b/src/components/UserDigest/index.tsx @@ -1,9 +1,11 @@ +import Concise from './Concise' import Mini from './Mini' import Plain from './Plain' import Rich from './Rich' import Verbose from './Verbose' export const UserDigest = { + Concise, Mini, Rich, Plain, diff --git a/src/stories/components/TagDigest/Concise.stories.tsx b/src/stories/components/TagDigest/Concise.stories.tsx new file mode 100644 index 0000000000..2f22e4eda7 --- /dev/null +++ b/src/stories/components/TagDigest/Concise.stories.tsx @@ -0,0 +1,24 @@ +import { MockedProvider } from '@apollo/react-testing' +import { ComponentMeta, ComponentStory } from '@storybook/react' +import React from 'react' + +import { TagDigest } from '~/components' + +import { MOCK_TAG } from '../../mocks' + +export default { + title: 'Components/TagDigest/Concise', + component: TagDigest.Concise, +} as ComponentMeta + +const Template: ComponentStory = (args) => ( + + + +) + +export const Default = Template.bind({}) +Default.args = { + tag: MOCK_TAG as any, + showArticlesNum: true, +} diff --git a/src/stories/components/TagDigest/Rich.stories.tsx b/src/stories/components/TagDigest/Rich.stories.tsx new file mode 100644 index 0000000000..ddeec8bef2 --- /dev/null +++ b/src/stories/components/TagDigest/Rich.stories.tsx @@ -0,0 +1,30 @@ +import { MockedProvider } from '@apollo/react-testing' +import { ComponentMeta, ComponentStory } from '@storybook/react' +import React from 'react' + +import { TagDigest } from '~/components' + +import { MOCK_TAG } from '../../mocks' + +export default { + title: 'Components/TagDigest/Rich', + component: TagDigest.Rich, +} as ComponentMeta + +const Template: ComponentStory = (args) => ( + + + +) + +export const Default = Template.bind({}) +Default.args = { + tag: MOCK_TAG as any, +} + +export const HasFollow = Template.bind({}) +HasFollow.args = { + tag: MOCK_TAG as any, + hasDesc: true, + hasFollow: true, +} diff --git a/src/stories/components/UserDigest/Concise.stories.tsx b/src/stories/components/UserDigest/Concise.stories.tsx new file mode 100644 index 0000000000..40ad162085 --- /dev/null +++ b/src/stories/components/UserDigest/Concise.stories.tsx @@ -0,0 +1,31 @@ +import { MockedProvider } from '@apollo/react-testing' +import { ComponentMeta, ComponentStory } from '@storybook/react' +import React from 'react' + +import { UserDigest } from '~/components' + +import { MOCK_USER } from '../../mocks' + +export default { + title: 'Components/UserDigest', + component: UserDigest.Concise, +} as ComponentMeta + +const Template: ComponentStory = (args) => ( + + + +) + +export const Concise = Template.bind({}) +Concise.args = { + user: MOCK_USER, + avatarSize: 'xl', +} + +export const ConciseTight = Template.bind({}) +ConciseTight.args = { + user: MOCK_USER, + avatarSize: 'lg', + nameStyle: 'tight', +} diff --git a/src/stories/mocks/index.ts b/src/stories/mocks/index.ts index ace48b1e61..66bf6adb2c 100644 --- a/src/stories/mocks/index.ts +++ b/src/stories/mocks/index.ts @@ -167,6 +167,8 @@ export const MOCK_TAG = { editors: [MOCK_USER], owner: MOCK_USER, content: '香港', + description: + '香港(英語:Hong Kong;縮寫:HK/HKG),全稱香港特別行政區(英語:Hong Kong Special Administrative Region;縮寫:HKSAR),簡稱「港」,雅稱「香江」', articles: { __typename: 'ArticleConnection' as any, totalCount: 8, diff --git a/src/views/ArticleDetail/EditMode/Header/gql.ts b/src/views/ArticleDetail/EditMode/Header/gql.ts index d3cd940516..6bc5a039fc 100644 --- a/src/views/ArticleDetail/EditMode/Header/gql.ts +++ b/src/views/ArticleDetail/EditMode/Header/gql.ts @@ -25,6 +25,7 @@ export const EDIT_ARTICLE = gql` $first: first_Int_min_0 = null $requestForDonation: requestForDonation_String_maxLength_140 $replyToDonator: replyToDonator_String_maxLength_140 + $canComment: Boolean ) { editArticle( input: { @@ -39,6 +40,7 @@ export const EDIT_ARTICLE = gql` iscnPublish: $iscnPublish requestForDonation: $requestForDonation replyToDonator: $replyToDonator + canComment: $canComment } ) { id @@ -49,6 +51,7 @@ export const EDIT_ARTICLE = gql` access { type } + canComment license requestForDonation replyToDonator diff --git a/src/views/ArticleDetail/EditMode/Header/index.tsx b/src/views/ArticleDetail/EditMode/Header/index.tsx index b5b2b504ac..eecf73b965 100644 --- a/src/views/ArticleDetail/EditMode/Header/index.tsx +++ b/src/views/ArticleDetail/EditMode/Header/index.tsx @@ -72,6 +72,7 @@ const EditModeHeader = ({ ...(isContentRevised ? { content } : {}), first: null, iscnPublish: restProps.iscnPublish, + canComment: restProps.canComment, }, }) diff --git a/src/views/ArticleDetail/EditMode/index.tsx b/src/views/ArticleDetail/EditMode/index.tsx index a6c56b0c01..47c242a81c 100644 --- a/src/views/ArticleDetail/EditMode/index.tsx +++ b/src/views/ArticleDetail/EditMode/index.tsx @@ -15,6 +15,7 @@ import { import { SetCollectionProps, SetCoverProps, + SetResponseProps, SetTagsProps, ToggleAccessProps, } from '~/components/Editor' @@ -161,6 +162,8 @@ const EditMode: React.FC = ({ article, onCancel, onSaved }) => { const [iscnPublish, setIscnPublish] = useState(false) // always start false + const [canComment, setCanComment] = useState(article.canComment) + /** * Render */ @@ -218,6 +221,12 @@ const EditMode: React.FC = ({ article, onCancel, onSaved }) => { editCollection: async (c: ArticleDigestDropdownArticleFragment[]) => editCollection(c), } + + const setCommentProps: SetResponseProps = { + canComment, + toggleComment: setCanComment, + } + const accessProps: ToggleAccessProps = { circle, accessType, @@ -248,6 +257,11 @@ const EditMode: React.FC = ({ article, onCancel, onSaved }) => { + = ({ article, onCancel, onSaved }) => { {...tagsProps} {...collectionProps} {...accessProps} + {...setCommentProps} article={article} editData={editData} coverId={cover?.id} @@ -325,6 +340,7 @@ const EditMode: React.FC = ({ article, onCancel, onSaved }) => { {...tagsProps} {...collectionProps} {...accessProps} + {...setCommentProps} onOpenSupportSetting={openDialog} /> )} diff --git a/src/views/ArticleDetail/Responses/index.tsx b/src/views/ArticleDetail/Responses/index.tsx index 2d4a23981e..80dd10a92d 100644 --- a/src/views/ArticleDetail/Responses/index.tsx +++ b/src/views/ArticleDetail/Responses/index.tsx @@ -1,7 +1,7 @@ import { useQuery } from '@apollo/react-hooks' import gql from 'graphql-tag' -import { Title, Translate } from '~/components' +import { IconDisableComment24, TextIcon, Title, Translate } from '~/components' import { ArticleResponseQuery, ResponseCountArticleFragment, @@ -10,6 +10,7 @@ import { import FeatureComments from './FeaturedComments' import LatestResponses from './LatestResponses' import ResponseCount from './ResponseCount' +import styles from './styles.css' const ARTICLE_RESPONSE = gql` query ArticleResponse( @@ -18,6 +19,7 @@ const ARTICLE_RESPONSE = gql` article: node(input: { id: $id }) { ... on Article { id + canComment author { id isBlocking @@ -40,6 +42,27 @@ const Responses = ({ id, lock }: { id: string; lock: boolean }) => { const { article } = data + const canComment = article.__typename === 'Article' && article.canComment + if (!canComment) { + return ( +
+ } + color="grey" + size="sm-s" + allowUserSelect + > + + + +
+ ) + } + return (
diff --git a/src/views/ArticleDetail/Responses/styles.css b/src/views/ArticleDetail/Responses/styles.css index 532512de5c..2fad3b2899 100644 --- a/src/views/ArticleDetail/Responses/styles.css +++ b/src/views/ArticleDetail/Responses/styles.css @@ -23,3 +23,9 @@ margin-left: var(--spacing-x-tight); } } + +.disable-response { + @mixin flex-center-all; + + padding-top: var(--spacing-tight); +} diff --git a/src/views/ArticleDetail/SupportWidget/Donators/index.tsx b/src/views/ArticleDetail/SupportWidget/Donators/index.tsx index f8c1eedf2c..f71ae996a6 100644 --- a/src/views/ArticleDetail/SupportWidget/Donators/index.tsx +++ b/src/views/ArticleDetail/SupportWidget/Donators/index.tsx @@ -98,19 +98,17 @@ const Donators = ({ article, showAvatarAnimation = false }: DonatorsProps) => { {donatorsCount - (maxAvatarNum - 1)} )} + + {donatorsCount === 1 && ( + + + + )}
{donatorsCount === 1 && ( -
- - - - +
diff --git a/src/views/ArticleDetail/SupportWidget/Donators/styles.css b/src/views/ArticleDetail/SupportWidget/Donators/styles.css index 93266f9614..0bcd997a9c 100644 --- a/src/views/ArticleDetail/SupportWidget/Donators/styles.css +++ b/src/views/ArticleDetail/SupportWidget/Donators/styles.css @@ -54,6 +54,14 @@ background: var(--color-matters-gold); border-radius: 50%; } + + & .donator-name { + margin-left: var(--spacing-x-tight); + font-size: var(--font-size-xs); + font-weight: var(--font-weight-medium); + line-height: 1.25rem; + color: var(--color-black); + } } .avatar-list-footer { @@ -67,15 +75,4 @@ font-weight: var(--font-weight-bold); color: var(--color-black); } - - & .footer { - @mixin flex-center-start; - } - - & .donator-name { - margin-right: var(--spacing-xx-tight); - font-size: var(--font-size-xs); - font-weight: var(--font-weight-medium); - color: var(--color-black); - } } diff --git a/src/views/ArticleDetail/Toolbar/CommentBar/index.tsx b/src/views/ArticleDetail/Toolbar/CommentBar/index.tsx index cfa86baf57..1f6a47bf10 100644 --- a/src/views/ArticleDetail/Toolbar/CommentBar/index.tsx +++ b/src/views/ArticleDetail/Toolbar/CommentBar/index.tsx @@ -45,6 +45,7 @@ const fragments = { fragment CommentBarArticlePublic on Article { id responseCount + canComment } `, private: gql` diff --git a/src/views/ArticleDetail/Toolbar/index.tsx b/src/views/ArticleDetail/Toolbar/index.tsx index 87cfde9e44..3287c5b172 100644 --- a/src/views/ArticleDetail/Toolbar/index.tsx +++ b/src/views/ArticleDetail/Toolbar/index.tsx @@ -105,7 +105,10 @@ const Toolbar = ({ />
- +
diff --git a/src/views/ArticleDetail/gql.ts b/src/views/ArticleDetail/gql.ts index 9b7c71174e..e65fd56bdb 100644 --- a/src/views/ArticleDetail/gql.ts +++ b/src/views/ArticleDetail/gql.ts @@ -41,6 +41,7 @@ const articlePublicFragment = gql` ...CircleWallCirclePrivate } } + canComment license requestForDonation replyToDonator diff --git a/src/views/Circle/Analytics/ContentAnalytics/ContentDigest/index.tsx b/src/views/Circle/Analytics/ContentAnalytics/ContentDigest/index.tsx index eb85c37b10..574566a7ee 100644 --- a/src/views/Circle/Analytics/ContentAnalytics/ContentDigest/index.tsx +++ b/src/views/Circle/Analytics/ContentAnalytics/ContentDigest/index.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { FormattedMessage } from 'react-intl' import { toPath } from '~/common/utils' import { @@ -8,7 +9,6 @@ import { LinkWrapper, TextIcon, Tooltip, - Translate, } from '~/components' import { CircleContentAnalyticsArticleFragment } from '~/gql/graphql' @@ -23,7 +23,10 @@ interface CircleAnalyticsContentProps { const Count = ({ count }: { count: number }) => { return ( - } trigger="click"> + } + trigger="click" + > diff --git a/src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx b/src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx index ab8fc206e3..f4c168dd96 100644 --- a/src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx +++ b/src/views/Circle/Settings/ManageInvitation/AddButton/index.tsx @@ -1,4 +1,6 @@ -import { Button, TextIcon, Translate } from '~/components' +import { FormattedMessage } from 'react-intl' + +import { Button, TextIcon } from '~/components' import AddInvitationDialog from '../AddInvitationDialog' @@ -22,7 +24,10 @@ const CircleInvitationAddButton = () => { aria-haspopup="dialog" > - + )} diff --git a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx index a3841649f9..7e4b7ddfc4 100644 --- a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx +++ b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/PreSend.tsx @@ -1,5 +1,6 @@ import { useQuery } from '@apollo/react-hooks' import { useState } from 'react' +import { FormattedMessage } from 'react-intl' import { REFETCH_CIRCLE_PENDING_INVITES } from '~/common/enums' import { @@ -9,7 +10,6 @@ import { QueryError, Spinner, Throw404, - Translate, useMutation, UserDigest, useRoute, @@ -101,10 +101,9 @@ const BaseInviteePreSend = ({ closeDialog, confirm, invitees }: Props) => { <>

-

@@ -135,11 +134,7 @@ const BaseInviteePreSend = ({ closeDialog, confirm, invitees }: Props) => { send()} loading={inviteLoading}> - + { textColor="black" onClick={closeDialog} > - + @@ -166,7 +164,12 @@ const BaseInviteePreSend = ({ closeDialog, confirm, invitees }: Props) => { const InviteePreSend = (props: Props) => ( <> } + title={ + + } closeDialog={props.closeDialog} closeTextId="cancel" /> diff --git a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Search.tsx b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Search.tsx index 2181c528fc..4a04677bb3 100644 --- a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Search.tsx +++ b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Search.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' +import { FormattedMessage } from 'react-intl' -import { Dialog, Translate } from '~/components' +import { Dialog } from '~/components' import SearchingArea, { SelectNode, } from '~/components/SearchSelect/SearchingArea' @@ -54,7 +55,7 @@ const InviteeSearchEditor = ({ closeDialog, save }: Props) => { save({ nodes: selectedNodes })} - text={} + text={} /> } /> diff --git a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/SelectPeriod/index.tsx b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/SelectPeriod/index.tsx index a55ae44771..f786ded92f 100644 --- a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/SelectPeriod/index.tsx +++ b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/SelectPeriod/index.tsx @@ -1,4 +1,6 @@ -import { Form, Translate } from '~/components' +import { FormattedMessage } from 'react-intl' + +import { Form } from '~/components' interface Props { period: number @@ -12,17 +14,14 @@ const SelectPeriod = ({ period, onChange }: Props) => { + } onChange={(option) => onChange(option.value)} options={options.map((value) => ({ name: ( <> - {value} + {value} + ), value, diff --git a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx index fc8bfb0c4d..099f1a1559 100644 --- a/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx +++ b/src/views/Circle/Settings/ManageInvitation/AddInvitationDialog/Sent.tsx @@ -1,14 +1,15 @@ -import { Dialog, Translate } from '~/components' +import { FormattedMessage } from 'react-intl' + +import { Dialog } from '~/components' interface Props { closeDialog: () => void } const InvitationSentTitle = ( - ) @@ -33,10 +34,9 @@ const InvitationSent = ({ closeDialog }: Props) => (

{InvitationSentTitle}

-

@@ -47,7 +47,7 @@ const InvitationSent = ({ closeDialog }: Props) => ( textColor="black" onClick={closeDialog} > - + diff --git a/src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx b/src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx index c0fed199f1..189addcd53 100644 --- a/src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx +++ b/src/views/Circle/Settings/ManageInvitation/Invites/Accepted/index.tsx @@ -1,5 +1,6 @@ import { useQuery } from '@apollo/react-hooks' import { useContext } from 'react' +import { FormattedMessage } from 'react-intl' import { mergeConnections } from '~/common/utils' import { @@ -10,7 +11,6 @@ import { QueryError, Spinner, Throw404, - Translate, useRoute, ViewerContext, } from '~/components' @@ -79,10 +79,9 @@ const AcceptedInvites = () => { return ( } /> diff --git a/src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx b/src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx index 63f83de7f4..54783bccf8 100644 --- a/src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx +++ b/src/views/Circle/Settings/ManageInvitation/Invites/Pending/index.tsx @@ -1,5 +1,6 @@ import { useQuery } from '@apollo/react-hooks' import { useContext } from 'react' +import { FormattedMessage } from 'react-intl' import { REFETCH_CIRCLE_PENDING_INVITES } from '~/common/enums' import { mergeConnections } from '~/common/utils' @@ -11,7 +12,6 @@ import { QueryError, Spinner, Throw404, - Translate, useEventListener, useRoute, ViewerContext, @@ -83,10 +83,9 @@ const PendingInvites = () => { return ( } /> diff --git a/src/views/Circle/Settings/ManageInvitation/Invites/index.tsx b/src/views/Circle/Settings/ManageInvitation/Invites/index.tsx index e0fe715ab4..d40bdb24ac 100644 --- a/src/views/Circle/Settings/ManageInvitation/Invites/index.tsx +++ b/src/views/Circle/Settings/ManageInvitation/Invites/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react' +import { FormattedMessage } from 'react-intl' -import { Spacer, Tabs, Translate } from '~/components' +import { Spacer, Tabs } from '~/components' import AcceptedInvites from './Accepted' import PendingInvites from './Pending' @@ -19,11 +20,17 @@ const InvitesFeed: React.FC = () => { setType('pending')} selected={isPending}> - + setType('accepted')} selected={isAccepted}> - + diff --git a/src/views/Circle/Settings/index.tsx b/src/views/Circle/Settings/index.tsx index 4f0247561e..a2fa025595 100644 --- a/src/views/Circle/Settings/index.tsx +++ b/src/views/Circle/Settings/index.tsx @@ -1,5 +1,7 @@ +import { FormattedMessage } from 'react-intl' + import { toPath } from '~/common/utils' -import { Form, Head, Layout, Spacer, Translate, useRoute } from '~/components' +import { Form, Head, Layout, Spacer, useRoute } from '~/components' const Settings = () => { const { getQuery } = useRoute() @@ -14,9 +16,18 @@ const Settings = () => { - }> + + } + > } + title={ + + } {...toPath({ page: 'circleEditProfile', circle: { name } })} role="link" /> @@ -24,11 +35,19 @@ const Settings = () => { + } > } + title={ + + } {...toPath({ page: 'circleManageInvitation', circle: { name } })} role="link" /> diff --git a/src/views/Follow/Feed/FollowingFeedComment/index.tsx b/src/views/Follow/Feed/FollowingFeedComment/index.tsx index 0c2b08c942..7c6579d626 100644 --- a/src/views/Follow/Feed/FollowingFeedComment/index.tsx +++ b/src/views/Follow/Feed/FollowingFeedComment/index.tsx @@ -1,6 +1,6 @@ import React from 'react' -import { Comment, DateTime, Expandable } from '~/components' +import { Comment, DateTime } from '~/components' import { FollowingFeedCommentPrivateFragment, FollowingFeedCommentPublicFragment, @@ -25,13 +25,7 @@ const FollowingFeedComment: React.FC & { {header}
- - - +