diff --git a/lang/default.json b/lang/default.json index 5e67b3d6ea..784c113eba 100644 --- a/lang/default.json +++ b/lang/default.json @@ -127,15 +127,9 @@ "0/gRer": { "defaultMessage": "I am migrating to Matters, and I invite you to come along" }, - "0/iEw/": { - "defaultMessage": "Manage Communities" - }, "06XHBC": { "defaultMessage": "Add to Circle" }, - "0Azlrb": { - "defaultMessage": "Manage" - }, "0CyECR": { "defaultMessage": "Matters ID has been set up. More account info can be found in Settings", "description": "src/components/Dialogs/SetUserNameDialog/ConfirmStep.tsx" @@ -228,9 +222,6 @@ "defaultMessage": "No data yet", "description": "src/views/Me/History/index.tsx" }, - "1ZFwRz": { - "defaultMessage": "Confirm Removal" - }, "1exrSw": { "defaultMessage": "Welcome onboard!" }, @@ -343,9 +334,6 @@ "3YAasP": { "defaultMessage": "What is Liker ID?" }, - "3fqQHv": { - "defaultMessage": "Add tag editor" - }, "3kbIhS": { "defaultMessage": "Untitled" }, @@ -416,9 +404,6 @@ "defaultMessage": "Do you want to disconnect from {type}?", "description": "src/components/Dialogs/RemoveSocialLoginDialog/Content.tsx" }, - "5FO4vn": { - "defaultMessage": "You do not have permission to perform this operation" - }, "5Ga0iK": { "defaultMessage": "Insert code" }, @@ -480,10 +465,6 @@ "62nsdy": { "defaultMessage": "Retry" }, - "63HuBz": { - "defaultMessage": "This tag has no manager currently", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "69+D96": { "defaultMessage": "Start Creating" }, @@ -609,10 +590,6 @@ "7oytv9": { "defaultMessage": "(edited)" }, - "7xnrxG": { - "defaultMessage": "The article has been added to the Trending", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "7ykJ+l": { "defaultMessage": "Still quiet here. {br}Be the first one to say hello!", "description": "src/components/Empty/EmptyComment.tsx" @@ -632,6 +609,10 @@ "defaultMessage": "Unpin from profile", "description": "src/views/User/Articles/PinBoard/UnPinButton/index.tsx" }, + "8GXAUX": { + "defaultMessage": "All results for", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "8KFsZN": { "defaultMessage": "Read Counts" }, @@ -645,6 +626,9 @@ "8YgVvt": { "defaultMessage": "Like collection" }, + "8ZyDQJ": { + "defaultMessage": "Bookmark removed" + }, "8cv9D4": { "defaultMessage": "Next Step" }, @@ -766,10 +750,6 @@ "AGDFGs": { "defaultMessage": "Discrimination, insult, or hatred" }, - "ANA7sk": { - "defaultMessage": "Maintain", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "AVpR3Q": { "defaultMessage": "Wallet linked", "description": "src/components/UserProfile/WalletLabel/index.tsx" @@ -785,6 +765,10 @@ "AeVndq": { "defaultMessage": "mentioned you in a comment at {commentMoment}" }, + "Ajc5SE": { + "defaultMessage": "Articles", + "description": "src/views/Me/Bookmarks/Tabs.tsx" + }, "AlHYvk": { "defaultMessage": "{type} edited" }, @@ -863,10 +847,6 @@ "defaultMessage": "Connected to {type}", "description": "src/views/Me/Settings/Settings/Socials/index.tsx" }, - "C8GQaD": { - "defaultMessage": "upadted {date}", - "description": "src/components/CollectionDigest/Feed/index.tsx" - }, "C9jbHn": { "defaultMessage": "Number of claps", "description": "src/components/ArticleDigest/Published/FooterActions/index.tsx" @@ -1102,10 +1082,6 @@ "GRrsEH": { "defaultMessage": "View published article" }, - "GRtGnZ": { - "defaultMessage": "Resign From Maintainer", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "GU6vV0": { "defaultMessage": "No collection created yet", "description": "src/components/Empty/EmptyCollection.tsx" @@ -1182,6 +1158,10 @@ "HbEL82": { "defaultMessage": "Comment has been deleted" }, + "HbwwAe": { + "defaultMessage": "Updated {date}", + "description": "src/components/CollectionDigest/Feed/index.tsx" + }, "HgY+72": { "defaultMessage": "Apply", "description": "src/views/CampaignDetail/Apply/Button/index.tsx" @@ -1193,9 +1173,6 @@ "Hlwud7": { "defaultMessage": "More ENS information, check {node}." }, - "Hm2DAQ": { - "defaultMessage": "Confirm collaborator removal" - }, "HnxG15": { "defaultMessage": "Set" }, @@ -1236,6 +1213,10 @@ "ISly67": { "defaultMessage": "Agree" }, + "IUS82d": { + "defaultMessage": "Tag active authors", + "description": "src/views/TagDetail/RecommendedAuthors/index.tsx" + }, "IXycMo": { "defaultMessage": "Resend" }, @@ -1301,10 +1282,6 @@ "Jr12wo": { "defaultMessage": "Insert video" }, - "Js/Fij": { - "defaultMessage": "This article has been removed from Trending", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "Jxr/TM": { "defaultMessage": "FULL", "description": "src/components/Dialogs/AddCollectionsArticleDialog/SelectDialogContent.tsx" @@ -1330,10 +1307,6 @@ "defaultMessage": "Circle successfully created", "description": "src/components/Forms/CreateCircleForm/Profile.tsx" }, - "KMcrz8": { - "defaultMessage": "Maintain Tag", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "KQi/UZ": { "defaultMessage": "Archive works" }, @@ -1348,9 +1321,6 @@ "defaultMessage": "Wallet connected", "description": "src/components/Forms/WalletAuthForm/Connect.tsx" }, - "KoR0wt": { - "defaultMessage": "Collaborator can manage selected feed with you." - }, "Kwv1n3": { "defaultMessage": "registration is about 1 LIKE. During promotion period it is sponsored by Matters.News." }, @@ -1377,10 +1347,6 @@ "defaultMessage": "Expand", "description": "src/components/Expandable/index.tsx" }, - "L7Si5/": { - "defaultMessage": "Manage Community", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "LETb4b": { "defaultMessage": "Collections allow up to {count} articles currently", "description": "src/views/User/CollectionDetail/CollectionArticles/ViewerArticles.tsx" @@ -1423,9 +1389,6 @@ "defaultMessage": "You do not have permissionn to perform this operation", "description": "FORBIDDEN_BY_TARGET_STATE" }, - "LnesNr": { - "defaultMessage": "Successfully removed collaborator" - }, "LoQ3BF": { "defaultMessage": "This badge represents your completion of Free Write in 7 days. Congratulations on finishing this meaningful writing journey!" }, @@ -1602,12 +1565,6 @@ "defaultMessage": "guide", "description": "src/components/Forms/PaymentForm/PayTo/SetAmount/SetAmountHeader/WhyOptimismDialog/index.tsx" }, - "P1AKC5": { - "defaultMessage": "Collaborator" - }, - "P2Btra": { - "defaultMessage": "Adopted" - }, "P3y9Bo": { "defaultMessage": "Go to sign", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -1693,9 +1650,6 @@ "QvPc1q": { "defaultMessage": "Upload Cover" }, - "Qzdtxi": { - "defaultMessage": "Resign as tag maintainer" - }, "R410ei": { "defaultMessage": "Incorrect verification code", "description": "CODE_INVALID" @@ -1830,9 +1784,6 @@ "T9oZC8": { "defaultMessage": "Are you sure you want to delete this collection ‘{collection}’?" }, - "TAPLOf": { - "defaultMessage": "Every tag can have maximum {count} collaborators." - }, "TF1OhT": { "defaultMessage": "This login code has expired, please try to resend" }, @@ -1863,16 +1814,10 @@ "defaultMessage": "Optimism is a standalone blockchain. If you have USDT on other chains, you need to transfer them to Optimism. See details in the {tutorial}.", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" }, - "ThSfXQ": { - "defaultMessage": "Successfully added collaborator" - }, "TjWWxF": { "defaultMessage": "Broadcast sent", "description": "src/views/Circle/Broadcast/Broadcast.tsx" }, - "TzhzIH": { - "defaultMessage": "Creators" - }, "U+qEBM": { "defaultMessage": "Switch Network", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -1910,10 +1855,6 @@ "defaultMessage": "Move to bottom", "description": "src/components/ArticleDigest/DropdownActions/SetBottomCollectionButton.tsx" }, - "UjKkhq": { - "defaultMessage": "Tags added", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "Up5U7K": { "defaultMessage": "Block" }, @@ -1924,9 +1865,6 @@ "Uq6tfM": { "defaultMessage": "Add caption…" }, - "Uv0hqn": { - "defaultMessage": "Adopt Tag" - }, "UxAA/V": { "defaultMessage": "Optimism is a Layer 2 scaling solution based on Ethereum that can provide faster and cheaper transactions, while ensuring security, making it easier for you to support creators.", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2014,10 +1952,6 @@ "WQT8ZA": { "defaultMessage": "Edit collection" }, - "WSUAwk": { - "defaultMessage": "Add to Featured", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "WiGHyF": { "defaultMessage": "Web Monetization standard" }, @@ -2121,6 +2055,9 @@ "Y8zV4A": { "defaultMessage": "Write a comment" }, + "YDMrKK": { + "defaultMessage": "Users" + }, "YPMn9n": { "defaultMessage": "Please log in.", "description": "UNAUTHENTICATED" @@ -2194,9 +2131,6 @@ "ZZ9zIR": { "defaultMessage": "Downvote" }, - "Zakh0i": { - "defaultMessage": "Not following any tag" - }, "ZjDH42": { "defaultMessage": "About Us" }, @@ -2217,9 +2151,6 @@ "defaultMessage": "Number of readers: unique registered users plus number of anonymous IP addresses visited the article (Data will be updated periodically and may be delayed)", "description": "src/views/Me/Works/Published/SortTabs.tsx" }, - "a3j20X": { - "defaultMessage": "Maintain immediately" - }, "aCTmEO": { "defaultMessage": "I don't have a wallet yet", "description": "src/components/Forms/SelectAuthMethodForm/WalletFeed.tsx" @@ -2235,9 +2166,6 @@ "aKEiNd": { "defaultMessage": "You missed the registration period, you can still join as a latecomer. Apply earlier next time for the chance to get the badge." }, - "aKlTO2": { - "defaultMessage": "You can add {count} more collaborators." - }, "aOFCqL": { "defaultMessage": "Most comments", "description": "src/views/Me/Works/Published/SortTabs.tsx" @@ -2248,10 +2176,6 @@ "aTmmkr": { "defaultMessage": "You have unsubscribed the circle." }, - "aa0nss": { - "defaultMessage": "Unpin from Trending", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "aaUBvF": { "defaultMessage": "comment_circle", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" @@ -2347,6 +2271,10 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {article} other {articles}}" }, + "cd8EmU": { + "defaultMessage": "of search results", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "cg1VJ2": { "defaultMessage": "Connect Wallet" }, @@ -2409,9 +2337,6 @@ "deEeEI": { "defaultMessage": "Register" }, - "dg3JCQ": { - "defaultMessage": "collaborators" - }, "djJp6c": { "defaultMessage": "History" }, @@ -2438,9 +2363,6 @@ "eWXgsZ": { "defaultMessage": "Clear Content" }, - "eXDZGQ": { - "defaultMessage": "Maintainer" - }, "eY3YIa": { "defaultMessage": "Copy comment" }, @@ -2591,10 +2513,6 @@ "defaultMessage": "Insufficient:", "description": "src/components/Balance/index.tsx" }, - "hYG5fb": { - "defaultMessage": "are following", - "description": "src/views/TagDetail/Followers/index.tsx" - }, "hgtWIO": { "defaultMessage": "Articles have been collected", "description": "src/views/Me/Settings/Notifications/GeneralSettings/index.tsx" @@ -2626,6 +2544,9 @@ "iEJeQH": { "defaultMessage": "Liker ID" }, + "iIitRg": { + "defaultMessage": "Tag not bookmarked yet" + }, "iNZdM/": { "defaultMessage": "Switch to support creators with the Optimism network {br} Make support more convenient and affordable", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2696,8 +2617,8 @@ "defaultMessage": "broadcast in {circlename}", "description": "src/components/Notice/CommentNotice/CircleNewBroadcastNotice.tsx" }, - "k0ooDW": { - "defaultMessage": "Tag Description" + "k0fraU": { + "defaultMessage": "Bookmarked" }, "k2veDA": { "defaultMessage": "Write" @@ -2715,9 +2636,6 @@ "kCPl0r": { "defaultMessage": "Collect" }, - "kCp8A9": { - "defaultMessage": "After resignation, you will not be able to manage tags." - }, "kEDrXh": { "defaultMessage": "liked your collection" }, @@ -2736,10 +2654,6 @@ "defaultMessage": "Liker ID", "description": "src/views/Me/Settings/Misc/LikerID.tsx" }, - "kSt4il": { - "defaultMessage": "Bookmark removed", - "description": "src/components/Buttons/Bookmark/Unsubscribe.tsx" - }, "kc79d3": { "defaultMessage": "Topics" }, @@ -2796,9 +2710,6 @@ "lIir/P": { "defaultMessage": "I see" }, - "lMKb5N": { - "defaultMessage": "Resignation Success" - }, "lNWFnL": { "defaultMessage": "Share this article in translated version" }, @@ -2809,9 +2720,6 @@ "lO7wKc": { "defaultMessage": "Not yet" }, - "lT6Dt8": { - "defaultMessage": "Confirm Resignation" - }, "lZukEr": { "defaultMessage": "commented", "description": "src/components/Notice/CommentNotice/ArticleNewCommentNotice.tsx" @@ -2931,9 +2839,6 @@ "defaultMessage": "replied your comment in", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" }, - "nNLkZ8": { - "defaultMessage": "Add collaborator" - }, "nWhqw9": { "defaultMessage": "Publish Now" }, @@ -2952,9 +2857,6 @@ "defaultMessage": "Invalid Email", "description": "USER_EMAIL_INVALID" }, - "o2Na0B": { - "defaultMessage": "Back to All" - }, "oGiO//": { "defaultMessage": "Insert audio" }, @@ -3030,10 +2932,6 @@ "defaultMessage": "commented in your moment", "description": "src/components/Notice/CommentNotice/MomentNewCommentNotice.tsx" }, - "qE8ew4": { - "defaultMessage": "Bookmarked", - "description": "src/components/Buttons/Bookmark/Subscribe.tsx" - }, "qNuRmA": { "defaultMessage": "Send login code", "description": "src/components/Forms/EmailLoginForm/Buttons.tsx" @@ -3074,10 +2972,6 @@ "qhVSGI": { "defaultMessage": "Hmm... It seems the author has hidden this work. Go see something else" }, - "qlki7w": { - "defaultMessage": "Remove Article", - "description": "src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx" - }, "qlxeW+": { "defaultMessage": "Undo downvote" }, @@ -3120,9 +3014,6 @@ "defaultMessage": "Edit", "description": "src/components/Dialogs/ReviseArticleDialog/index.tsx" }, - "rLlTQ9": { - "defaultMessage": "Tag Name" - }, "rXnmeE": { "defaultMessage": "Confirm and Send" }, @@ -3240,9 +3131,6 @@ "defaultMessage": "Comment has been deleted", "description": "Moment" }, - "uJkv2X": { - "defaultMessage": "Edit Tag" - }, "uM5qZr": { "defaultMessage": "Likes Given" }, @@ -3336,9 +3224,6 @@ "defaultMessage": "supported", "description": "src/components/Notice/TransactionNotice/PaymentReceivedDonationNotice.tsx" }, - "vLcHiG": { - "defaultMessage": "After removal, {user} user will not be able to manage selected feed." - }, "vRCDr8": { "defaultMessage": "You can quickly log in to your account after binding.{br}Readers can also freely transfer money through other channels to support you!", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -3508,10 +3393,6 @@ "yOhatg": { "defaultMessage": "Other malicious behavior" }, - "ySGgTo": { - "defaultMessage": "Add Articles into Featured", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "ySSF/a": { "defaultMessage": "In order to ensure the identity security of the citizens of Matters City, we've upgraded some security settings. Please confirm your Matters ID (cannot be modified once confirmation).", "description": "src/components/Dialogs/SetUserNameDialog/Content.tsx" @@ -3520,9 +3401,6 @@ "defaultMessage": "Please refresh the page and try again.", "description": "NETWORK_ERROR" }, - "yXWwSW": { - "defaultMessage": "Are you sure 😭" - }, "yZfKI4": { "defaultMessage": "discussion and mentioned you", "description": "src/components/Notice/CommentNotice/CommentMentionedYouNotice.tsx" diff --git a/lang/en.json b/lang/en.json index 42e5229aa7..2fcbe0300c 100644 --- a/lang/en.json +++ b/lang/en.json @@ -127,15 +127,9 @@ "0/gRer": { "defaultMessage": "I am migrating to Matters, and I invite you to come along" }, - "0/iEw/": { - "defaultMessage": "Manage Communities" - }, "06XHBC": { "defaultMessage": "Add to Circle" }, - "0Azlrb": { - "defaultMessage": "Manage" - }, "0CyECR": { "defaultMessage": "Matters ID has been set up. More account info can be found in Settings", "description": "src/components/Dialogs/SetUserNameDialog/ConfirmStep.tsx" @@ -228,9 +222,6 @@ "defaultMessage": "No data yet", "description": "src/views/Me/History/index.tsx" }, - "1ZFwRz": { - "defaultMessage": "Confirm Removal" - }, "1exrSw": { "defaultMessage": "Welcome onboard!" }, @@ -343,9 +334,6 @@ "3YAasP": { "defaultMessage": "What is Liker ID?" }, - "3fqQHv": { - "defaultMessage": "Add tag editor" - }, "3kbIhS": { "defaultMessage": "Untitled" }, @@ -416,9 +404,6 @@ "defaultMessage": "Do you want to disconnect from {type}?", "description": "src/components/Dialogs/RemoveSocialLoginDialog/Content.tsx" }, - "5FO4vn": { - "defaultMessage": "You do not have permission to perform this operation" - }, "5Ga0iK": { "defaultMessage": "Insert code" }, @@ -480,10 +465,6 @@ "62nsdy": { "defaultMessage": "Retry" }, - "63HuBz": { - "defaultMessage": "This tag has no manager currently", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "69+D96": { "defaultMessage": "Start Creating" }, @@ -609,10 +590,6 @@ "7oytv9": { "defaultMessage": " (edited) " }, - "7xnrxG": { - "defaultMessage": "The article has been added to the Trending", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "7ykJ+l": { "defaultMessage": "Still quiet here. {br}Be the first one to say hello!", "description": "src/components/Empty/EmptyComment.tsx" @@ -632,6 +609,10 @@ "defaultMessage": "Unpin from profile", "description": "src/views/User/Articles/PinBoard/UnPinButton/index.tsx" }, + "8GXAUX": { + "defaultMessage": "All results for", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "8KFsZN": { "defaultMessage": "Read Counts" }, @@ -645,6 +626,9 @@ "8YgVvt": { "defaultMessage": "Like collection" }, + "8ZyDQJ": { + "defaultMessage": "Bookmark removed" + }, "8cv9D4": { "defaultMessage": "Next Step" }, @@ -766,10 +750,6 @@ "AGDFGs": { "defaultMessage": "Discrimination, insult, or hatred" }, - "ANA7sk": { - "defaultMessage": "Maintain", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "AVpR3Q": { "defaultMessage": "Wallet linked", "description": "src/components/UserProfile/WalletLabel/index.tsx" @@ -785,6 +765,10 @@ "AeVndq": { "defaultMessage": "mentioned you in a comment at {commentMoment}" }, + "Ajc5SE": { + "defaultMessage": "Articles", + "description": "src/views/Me/Bookmarks/Tabs.tsx" + }, "AlHYvk": { "defaultMessage": "{type} edited" }, @@ -863,10 +847,6 @@ "defaultMessage": "Connected to {type}", "description": "src/views/Me/Settings/Settings/Socials/index.tsx" }, - "C8GQaD": { - "defaultMessage": "Upadted {date}", - "description": "src/components/CollectionDigest/Feed/index.tsx" - }, "C9jbHn": { "defaultMessage": "Number of claps", "description": "src/components/ArticleDigest/Published/FooterActions/index.tsx" @@ -1102,10 +1082,6 @@ "GRrsEH": { "defaultMessage": "View published article" }, - "GRtGnZ": { - "defaultMessage": "Resign From Maintainer", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "GU6vV0": { "defaultMessage": "No collection created yet", "description": "src/components/Empty/EmptyCollection.tsx" @@ -1182,6 +1158,10 @@ "HbEL82": { "defaultMessage": "Comment has been deleted" }, + "HbwwAe": { + "defaultMessage": "Updated {date}", + "description": "src/components/CollectionDigest/Feed/index.tsx" + }, "HgY+72": { "defaultMessage": "Apply", "description": "src/views/CampaignDetail/Apply/Button/index.tsx" @@ -1193,9 +1173,6 @@ "Hlwud7": { "defaultMessage": "More ENS information, check {node}." }, - "Hm2DAQ": { - "defaultMessage": "Confirm collaborator removal" - }, "HnxG15": { "defaultMessage": "Set" }, @@ -1236,6 +1213,10 @@ "ISly67": { "defaultMessage": "Agree" }, + "IUS82d": { + "defaultMessage": "Tag active authors", + "description": "src/views/TagDetail/RecommendedAuthors/index.tsx" + }, "IXycMo": { "defaultMessage": "Resend" }, @@ -1301,10 +1282,6 @@ "Jr12wo": { "defaultMessage": "Insert video" }, - "Js/Fij": { - "defaultMessage": "This article has been removed from Trending", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "Jxr/TM": { "defaultMessage": "FULL", "description": "src/components/Dialogs/AddCollectionsArticleDialog/SelectDialogContent.tsx" @@ -1330,10 +1307,6 @@ "defaultMessage": "Circle successfully created", "description": "src/components/Forms/CreateCircleForm/Profile.tsx" }, - "KMcrz8": { - "defaultMessage": "Maintain Tag", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "KQi/UZ": { "defaultMessage": "Archive works" }, @@ -1348,9 +1321,6 @@ "defaultMessage": "Wallet connected", "description": "src/components/Forms/WalletAuthForm/Connect.tsx" }, - "KoR0wt": { - "defaultMessage": "Collaborator can manage selected feed with you." - }, "Kwv1n3": { "defaultMessage": " registration is about 1 LIKE. During promotion period it is sponsored by Matters.News." }, @@ -1377,10 +1347,6 @@ "defaultMessage": "Expand", "description": "src/components/Expandable/index.tsx" }, - "L7Si5/": { - "defaultMessage": "Manage Community", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "LETb4b": { "defaultMessage": "Collections allow up to {count} articles currently", "description": "src/views/User/CollectionDetail/CollectionArticles/ViewerArticles.tsx" @@ -1423,9 +1389,6 @@ "defaultMessage": "You do not have permissionn to perform this operation", "description": "FORBIDDEN_BY_TARGET_STATE" }, - "LnesNr": { - "defaultMessage": "Successfully removed collaborator" - }, "LoQ3BF": { "defaultMessage": "This badge represents your completion of Free Write in 7 days. Congratulations on finishing this meaningful writing journey!" }, @@ -1602,12 +1565,6 @@ "defaultMessage": "guide", "description": "src/components/Forms/PaymentForm/PayTo/SetAmount/SetAmountHeader/WhyOptimismDialog/index.tsx" }, - "P1AKC5": { - "defaultMessage": "Collaborator" - }, - "P2Btra": { - "defaultMessage": "Adopted" - }, "P3y9Bo": { "defaultMessage": "Go to sign", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -1693,9 +1650,6 @@ "QvPc1q": { "defaultMessage": "Upload Cover" }, - "Qzdtxi": { - "defaultMessage": "Resign as tag maintainer" - }, "R410ei": { "defaultMessage": "Incorrect verification code", "description": "CODE_INVALID" @@ -1830,9 +1784,6 @@ "T9oZC8": { "defaultMessage": "Are you sure you want to delete this collection ‘{collection}’?" }, - "TAPLOf": { - "defaultMessage": "Every tag can have maximum {count} collaborators." - }, "TF1OhT": { "defaultMessage": "This login code has expired, please try to resend" }, @@ -1863,16 +1814,10 @@ "defaultMessage": "Optimism is a standalone blockchain. If you have USDT on other chains, you need to transfer them to Optimism. See details in the {tutorial}.", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" }, - "ThSfXQ": { - "defaultMessage": "Successfully added collaborator" - }, "TjWWxF": { "defaultMessage": "Broadcast sent", "description": "src/views/Circle/Broadcast/Broadcast.tsx" }, - "TzhzIH": { - "defaultMessage": "Creators" - }, "U+qEBM": { "defaultMessage": "Switch Network", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -1910,10 +1855,6 @@ "defaultMessage": "Move to bottom", "description": "src/components/ArticleDigest/DropdownActions/SetBottomCollectionButton.tsx" }, - "UjKkhq": { - "defaultMessage": "Tags added", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "Up5U7K": { "defaultMessage": "Block" }, @@ -1924,9 +1865,6 @@ "Uq6tfM": { "defaultMessage": "Add caption…" }, - "Uv0hqn": { - "defaultMessage": "Adopt Tag" - }, "UxAA/V": { "defaultMessage": "Optimism is a Layer 2 scaling solution based on Ethereum that can provide faster and cheaper transactions, while ensuring security, making it easier for you to support creators.", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2014,10 +1952,6 @@ "WQT8ZA": { "defaultMessage": "Edit collection" }, - "WSUAwk": { - "defaultMessage": "Add to Featured", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "WiGHyF": { "defaultMessage": "Web Monetization standard" }, @@ -2121,6 +2055,9 @@ "Y8zV4A": { "defaultMessage": "Write a comment" }, + "YDMrKK": { + "defaultMessage": "Users" + }, "YPMn9n": { "defaultMessage": "Please log in.", "description": "UNAUTHENTICATED" @@ -2194,9 +2131,6 @@ "ZZ9zIR": { "defaultMessage": "Downvote" }, - "Zakh0i": { - "defaultMessage": "Not following any tag" - }, "ZjDH42": { "defaultMessage": "About Us" }, @@ -2217,9 +2151,6 @@ "defaultMessage": "Number of readers: unique registered users plus number of anonymous IP addresses visited the article (Data will be updated periodically and may be delayed)", "description": "src/views/Me/Works/Published/SortTabs.tsx" }, - "a3j20X": { - "defaultMessage": "Maintain immediately" - }, "aCTmEO": { "defaultMessage": "I don't have a wallet yet", "description": "src/components/Forms/SelectAuthMethodForm/WalletFeed.tsx" @@ -2235,9 +2166,6 @@ "aKEiNd": { "defaultMessage": "You missed the registration period, you can still join as a latecomer. Apply earlier next time for the chance to get the badge." }, - "aKlTO2": { - "defaultMessage": "You can add {count} more collaborators." - }, "aOFCqL": { "defaultMessage": "Most comments", "description": "src/views/Me/Works/Published/SortTabs.tsx" @@ -2248,10 +2176,6 @@ "aTmmkr": { "defaultMessage": "You have unsubscribed the circle." }, - "aa0nss": { - "defaultMessage": "Unpin from Trending", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "aaUBvF": { "defaultMessage": "comment_circle", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" @@ -2347,6 +2271,10 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {article} other {articles}}" }, + "cd8EmU": { + "defaultMessage": "", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "cg1VJ2": { "defaultMessage": "Connect Wallet" }, @@ -2409,9 +2337,6 @@ "deEeEI": { "defaultMessage": "Register" }, - "dg3JCQ": { - "defaultMessage": "collaborators" - }, "djJp6c": { "defaultMessage": "History" }, @@ -2438,9 +2363,6 @@ "eWXgsZ": { "defaultMessage": "Clear Content" }, - "eXDZGQ": { - "defaultMessage": "Maintainer" - }, "eY3YIa": { "defaultMessage": "Copy comment" }, @@ -2591,10 +2513,6 @@ "defaultMessage": "Insufficient: ", "description": "src/components/Balance/index.tsx" }, - "hYG5fb": { - "defaultMessage": "are following", - "description": "src/views/TagDetail/Followers/index.tsx" - }, "hgtWIO": { "defaultMessage": "Articles have been collected", "description": "src/views/Me/Settings/Notifications/GeneralSettings/index.tsx" @@ -2626,6 +2544,9 @@ "iEJeQH": { "defaultMessage": "Liker ID" }, + "iIitRg": { + "defaultMessage": "Tag not bookmarked yet" + }, "iNZdM/": { "defaultMessage": "Switch to support creators with the Optimism network {br} Make support more convenient and affordable", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2696,8 +2617,8 @@ "defaultMessage": "broadcast in {circlename}", "description": "src/components/Notice/CommentNotice/CircleNewBroadcastNotice.tsx" }, - "k0ooDW": { - "defaultMessage": "Tag Description" + "k0fraU": { + "defaultMessage": "Bookmarked" }, "k2veDA": { "defaultMessage": "Write" @@ -2715,9 +2636,6 @@ "kCPl0r": { "defaultMessage": "Collect" }, - "kCp8A9": { - "defaultMessage": "After resignation, you will not be able to manage tags." - }, "kEDrXh": { "defaultMessage": "liked your collection" }, @@ -2736,10 +2654,6 @@ "defaultMessage": "Liker ID", "description": "src/views/Me/Settings/Misc/LikerID.tsx" }, - "kSt4il": { - "defaultMessage": "Bookmark removed", - "description": "src/components/Buttons/Bookmark/Unsubscribe.tsx" - }, "kc79d3": { "defaultMessage": "Topics" }, @@ -2796,9 +2710,6 @@ "lIir/P": { "defaultMessage": "I see" }, - "lMKb5N": { - "defaultMessage": "Resignation Success" - }, "lNWFnL": { "defaultMessage": "Share this article in translated version" }, @@ -2809,9 +2720,6 @@ "lO7wKc": { "defaultMessage": "Not yet" }, - "lT6Dt8": { - "defaultMessage": "Confirm Resignation" - }, "lZukEr": { "defaultMessage": "commented", "description": "src/components/Notice/CommentNotice/ArticleNewCommentNotice.tsx" @@ -2931,9 +2839,6 @@ "defaultMessage": "replied your comment in", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" }, - "nNLkZ8": { - "defaultMessage": "Add collaborator" - }, "nWhqw9": { "defaultMessage": "Publish Now" }, @@ -2952,9 +2857,6 @@ "defaultMessage": "Invalid Email", "description": "USER_EMAIL_INVALID" }, - "o2Na0B": { - "defaultMessage": "Back to All" - }, "oGiO//": { "defaultMessage": "Insert audio" }, @@ -3030,10 +2932,6 @@ "defaultMessage": "commented in your moment", "description": "src/components/Notice/CommentNotice/MomentNewCommentNotice.tsx" }, - "qE8ew4": { - "defaultMessage": "Bookmarked", - "description": "src/components/Buttons/Bookmark/Subscribe.tsx" - }, "qNuRmA": { "defaultMessage": "Send login code", "description": "src/components/Forms/EmailLoginForm/Buttons.tsx" @@ -3074,10 +2972,6 @@ "qhVSGI": { "defaultMessage": "Hmm... It seems the author has hidden this work. Go see something else" }, - "qlki7w": { - "defaultMessage": "Remove Article", - "description": "src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx" - }, "qlxeW+": { "defaultMessage": "Undo downvote" }, @@ -3120,9 +3014,6 @@ "defaultMessage": "Edit", "description": "src/components/Dialogs/ReviseArticleDialog/index.tsx" }, - "rLlTQ9": { - "defaultMessage": "Tag Name" - }, "rXnmeE": { "defaultMessage": "Confirm and Send" }, @@ -3240,9 +3131,6 @@ "defaultMessage": "Comment has been deleted", "description": "Moment" }, - "uJkv2X": { - "defaultMessage": "Edit Tag" - }, "uM5qZr": { "defaultMessage": "Likes Given" }, @@ -3336,9 +3224,6 @@ "defaultMessage": "supported", "description": "src/components/Notice/TransactionNotice/PaymentReceivedDonationNotice.tsx" }, - "vLcHiG": { - "defaultMessage": "After removal, {user} user will not be able to manage selected feed." - }, "vRCDr8": { "defaultMessage": "You can quickly log in to your account after binding.{br}Readers can also freely transfer money through other channels to support you!", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -3508,10 +3393,6 @@ "yOhatg": { "defaultMessage": "Other malicious behavior" }, - "ySGgTo": { - "defaultMessage": "Add Articles into Featured", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "ySSF/a": { "defaultMessage": "In order to ensure the identity security of the citizens of Matters City, we've upgraded some security settings. Please confirm your Matters ID (cannot be modified once confirmation).", "description": "src/components/Dialogs/SetUserNameDialog/Content.tsx" @@ -3520,9 +3401,6 @@ "defaultMessage": "Please refresh the page and try again.", "description": "NETWORK_ERROR" }, - "yXWwSW": { - "defaultMessage": "Are you sure 😭" - }, "yZfKI4": { "defaultMessage": "discussion and mentioned you", "description": "src/components/Notice/CommentNotice/CommentMentionedYouNotice.tsx" diff --git a/lang/zh-Hans.json b/lang/zh-Hans.json index 49213a590e..82a99d37af 100644 --- a/lang/zh-Hans.json +++ b/lang/zh-Hans.json @@ -127,15 +127,9 @@ "0/gRer": { "defaultMessage": "我正在搬家到 Matters,邀请你一起来" }, - "0/iEw/": { - "defaultMessage": "管理社群" - }, "06XHBC": { "defaultMessage": "加入围炉" }, - "0Azlrb": { - "defaultMessage": "管理" - }, "0CyECR": { "defaultMessage": "Matters ID 已设置,更多帐号相关设置可前往设置页修改", "description": "src/components/Dialogs/SetUserNameDialog/ConfirmStep.tsx" @@ -228,9 +222,6 @@ "defaultMessage": "尚无阅读记录", "description": "src/views/Me/History/index.tsx" }, - "1ZFwRz": { - "defaultMessage": "确认移除" - }, "1exrSw": { "defaultMessage": "欢迎上船!" }, @@ -343,9 +334,6 @@ "3YAasP": { "defaultMessage": "什么是 Liker ID?" }, - "3fqQHv": { - "defaultMessage": "添加协作者" - }, "3kbIhS": { "defaultMessage": "未命名" }, @@ -416,9 +404,6 @@ "defaultMessage": "确认要解绑 {type} 吗?", "description": "src/components/Dialogs/RemoveSocialLoginDialog/Content.tsx" }, - "5FO4vn": { - "defaultMessage": "你尚无权限进行该操作" - }, "5Ga0iK": { "defaultMessage": "插入代码" }, @@ -480,10 +465,6 @@ "62nsdy": { "defaultMessage": "重试" }, - "63HuBz": { - "defaultMessage": "此标签目前无人主理", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "69+D96": { "defaultMessage": "开始创作" }, @@ -609,10 +590,6 @@ "7oytv9": { "defaultMessage": "(修改过)" }, - "7xnrxG": { - "defaultMessage": "作品已添加至精选", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "7ykJ+l": { "defaultMessage": "暂无评论", "description": "src/components/Empty/EmptyComment.tsx" @@ -632,6 +609,10 @@ "defaultMessage": "取消代表作", "description": "src/views/User/Articles/PinBoard/UnPinButton/index.tsx" }, + "8GXAUX": { + "defaultMessage": "有关", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "8KFsZN": { "defaultMessage": "阅读次数" }, @@ -645,6 +626,9 @@ "8YgVvt": { "defaultMessage": "喜欢选集" }, + "8ZyDQJ": { + "defaultMessage": "收藏已取消" + }, "8cv9D4": { "defaultMessage": "下一步" }, @@ -766,10 +750,6 @@ "AGDFGs": { "defaultMessage": "歧视、侮辱或仇恨" }, - "ANA7sk": { - "defaultMessage": "主理", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "AVpR3Q": { "defaultMessage": "已绑定钱包", "description": "src/components/UserProfile/WalletLabel/index.tsx" @@ -785,6 +765,10 @@ "AeVndq": { "defaultMessage": "在动态留言中提及了你 {commentMoment}" }, + "Ajc5SE": { + "defaultMessage": "作品", + "description": "src/views/Me/Bookmarks/Tabs.tsx" + }, "AlHYvk": { "defaultMessage": "{type}已编辑" }, @@ -863,10 +847,6 @@ "defaultMessage": "{type} 已绑定", "description": "src/views/Me/Settings/Settings/Socials/index.tsx" }, - "C8GQaD": { - "defaultMessage": "{date}更新", - "description": "src/components/CollectionDigest/Feed/index.tsx" - }, "C9jbHn": { "defaultMessage": "拍手数量", "description": "src/components/ArticleDigest/Published/FooterActions/index.tsx" @@ -1102,10 +1082,6 @@ "GRrsEH": { "defaultMessage": "查看作品" }, - "GRtGnZ": { - "defaultMessage": "辞去权限", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "GU6vV0": { "defaultMessage": "尚未创建选集", "description": "src/components/Empty/EmptyCollection.tsx" @@ -1182,6 +1158,10 @@ "HbEL82": { "defaultMessage": "评论已刪除" }, + "HbwwAe": { + "defaultMessage": "{date}更新", + "description": "src/components/CollectionDigest/Feed/index.tsx" + }, "HgY+72": { "defaultMessage": "报名参加", "description": "src/views/CampaignDetail/Apply/Button/index.tsx" @@ -1193,9 +1173,6 @@ "Hlwud7": { "defaultMessage": "更多 ENS 资讯请参考 {node}." }, - "Hm2DAQ": { - "defaultMessage": "确定移除协作者" - }, "HnxG15": { "defaultMessage": "设定" }, @@ -1236,6 +1213,10 @@ "ISly67": { "defaultMessage": "同意" }, + "IUS82d": { + "defaultMessage": "标签活跃作者", + "description": "src/views/TagDetail/RecommendedAuthors/index.tsx" + }, "IXycMo": { "defaultMessage": "重新发送" }, @@ -1301,10 +1282,6 @@ "Jr12wo": { "defaultMessage": "插入视频" }, - "Js/Fij": { - "defaultMessage": "作品已取消精选", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "Jxr/TM": { "defaultMessage": "已满", "description": "src/components/Dialogs/AddCollectionsArticleDialog/SelectDialogContent.tsx" @@ -1330,10 +1307,6 @@ "defaultMessage": "围炉创建成功", "description": "src/components/Forms/CreateCircleForm/Profile.tsx" }, - "KMcrz8": { - "defaultMessage": "认领", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "KQi/UZ": { "defaultMessage": "归档作品" }, @@ -1348,9 +1321,6 @@ "defaultMessage": "钱包已绑定", "description": "src/components/Forms/WalletAuthForm/Connect.tsx" }, - "KoR0wt": { - "defaultMessage": "协作者可以与你共同管理精选" - }, "Kwv1n3": { "defaultMessage": " 用以出版 Writing NFT,费用 ≈1 LIKE,推广期由平台补助" }, @@ -1377,10 +1347,6 @@ "defaultMessage": "展开", "description": "src/components/Expandable/index.tsx" }, - "L7Si5/": { - "defaultMessage": "管理社群", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "LETb4b": { "defaultMessage": "选集暂时不允许超过 {count} 篇", "description": "src/views/User/CollectionDetail/CollectionArticles/ViewerArticles.tsx" @@ -1423,9 +1389,6 @@ "defaultMessage": "你无法对此对象进行该操作", "description": "FORBIDDEN_BY_TARGET_STATE" }, - "LnesNr": { - "defaultMessage": "移除协作者成功" - }, "LoQ3BF": { "defaultMessage": "这枚徽章代表你完成了七天写作,恭喜走完这趟意义非凡的写作之旅!" }, @@ -1602,12 +1565,6 @@ "defaultMessage": "教学指南", "description": "src/components/Forms/PaymentForm/PayTo/SetAmount/SetAmountHeader/WhyOptimismDialog/index.tsx" }, - "P1AKC5": { - "defaultMessage": "协作者" - }, - "P2Btra": { - "defaultMessage": "认领成功" - }, "P3y9Bo": { "defaultMessage": "前往签署", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -1693,9 +1650,6 @@ "QvPc1q": { "defaultMessage": "上传封面" }, - "Qzdtxi": { - "defaultMessage": "辞去权限" - }, "R410ei": { "defaultMessage": "验证码错误", "description": "CODE_INVALID" @@ -1830,9 +1784,6 @@ "T9oZC8": { "defaultMessage": "确认要删除该选集“{collection}”吗?" }, - "TAPLOf": { - "defaultMessage": "每个标签最多添加 {count} 名协作者" - }, "TF1OhT": { "defaultMessage": "临时密码已过期,请尝试重新发送" }, @@ -1863,16 +1814,10 @@ "defaultMessage": "Optimism 是独立运行的区块链,若你在其他链上已有 USDT 货币,需要将它们转移到 Optimism 网络才能使用,详情参考 {tutorial}.", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" }, - "ThSfXQ": { - "defaultMessage": "添加协作者成功" - }, "TjWWxF": { "defaultMessage": "广播已送出", "description": "src/views/Circle/Broadcast/Broadcast.tsx" }, - "TzhzIH": { - "defaultMessage": "创作者" - }, "U+qEBM": { "defaultMessage": "切换网络", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -1910,10 +1855,6 @@ "defaultMessage": "移至底部", "description": "src/components/ArticleDigest/DropdownActions/SetBottomCollectionButton.tsx" }, - "UjKkhq": { - "defaultMessage": "作品已添加标签", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "Up5U7K": { "defaultMessage": "屏蔽" }, @@ -1924,9 +1865,6 @@ "Uq6tfM": { "defaultMessage": "添加说明文字…" }, - "Uv0hqn": { - "defaultMessage": "认领标签" - }, "UxAA/V": { "defaultMessage": "Optimism 是基于以太坊的第二层(Layer2)扩容方案,能提升交易速度,并降低手续费,同时确保安全性,让你更轻松地支持创作者。", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2014,10 +1952,6 @@ "WQT8ZA": { "defaultMessage": "编辑选集" }, - "WSUAwk": { - "defaultMessage": "添加到精选", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "WiGHyF": { "defaultMessage": "Web Monetization 标准" }, @@ -2121,6 +2055,9 @@ "Y8zV4A": { "defaultMessage": "回复评论" }, + "YDMrKK": { + "defaultMessage": "用户" + }, "YPMn9n": { "defaultMessage": "请先登入再进行操作", "description": "UNAUTHENTICATED" @@ -2194,9 +2131,6 @@ "ZZ9zIR": { "defaultMessage": "点踩" }, - "Zakh0i": { - "defaultMessage": "还没有关注任何标签" - }, "ZjDH42": { "defaultMessage": "关于我们" }, @@ -2217,9 +2151,6 @@ "defaultMessage": "读者数量:访问过作品页的不重复的登录用户数加匿名 IP 数(数据周期更新,可能存在延迟)", "description": "src/views/Me/Works/Published/SortTabs.tsx" }, - "a3j20X": { - "defaultMessage": "即刻主理" - }, "aCTmEO": { "defaultMessage": "我还没有钱包", "description": "src/components/Forms/SelectAuthMethodForm/WalletFeed.tsx" @@ -2235,9 +2166,6 @@ "aKEiNd": { "defaultMessage": "错过报名期没关系,仍然可以用晚鸟身份参与,一起书写人生故事。下次早点报名,就有机会获得大满贯徽章!" }, - "aKlTO2": { - "defaultMessage": "你还可以添加 {count} 名协作者" - }, "aOFCqL": { "defaultMessage": "最多评论", "description": "src/views/Me/Works/Published/SortTabs.tsx" @@ -2248,10 +2176,6 @@ "aTmmkr": { "defaultMessage": "你已经与围炉告别,感谢曾经的付出与参与。" }, - "aa0nss": { - "defaultMessage": "取消精选", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "aaUBvF": { "defaultMessage": " 中的发言", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" @@ -2347,6 +2271,10 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {篇文章} other {篇文章}}" }, + "cd8EmU": { + "defaultMessage": "的搜索结果", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "cg1VJ2": { "defaultMessage": "连接加密钱包" }, @@ -2409,9 +2337,6 @@ "deEeEI": { "defaultMessage": "注册" }, - "dg3JCQ": { - "defaultMessage": "协作者" - }, "djJp6c": { "defaultMessage": "我的足跡" }, @@ -2438,9 +2363,6 @@ "eWXgsZ": { "defaultMessage": "清空内容" }, - "eXDZGQ": { - "defaultMessage": "主理人" - }, "eY3YIa": { "defaultMessage": "复制评论" }, @@ -2591,10 +2513,6 @@ "defaultMessage": "余额不足:", "description": "src/components/Balance/index.tsx" }, - "hYG5fb": { - "defaultMessage": "人关注", - "description": "src/views/TagDetail/Followers/index.tsx" - }, "hgtWIO": { "defaultMessage": "作品被关联", "description": "src/views/Me/Settings/Notifications/GeneralSettings/index.tsx" @@ -2626,6 +2544,9 @@ "iEJeQH": { "defaultMessage": "设置 Liker ID" }, + "iIitRg": { + "defaultMessage": "尚未收藏标签" + }, "iNZdM/": { "defaultMessage": "切换后即可支持创作者,采用 Optimism 网络{br}让支持更方便且费用低廉", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2696,8 +2617,8 @@ "defaultMessage": "在 {circlename} 发布广播", "description": "src/components/Notice/CommentNotice/CircleNewBroadcastNotice.tsx" }, - "k0ooDW": { - "defaultMessage": "标签描述" + "k0fraU": { + "defaultMessage": "收藏成功" }, "k2veDA": { "defaultMessage": "创作" @@ -2715,9 +2636,6 @@ "kCPl0r": { "defaultMessage": "关联" }, - "kCp8A9": { - "defaultMessage": "如果辞去权限,你将无法继续管理标签。" - }, "kEDrXh": { "defaultMessage": "喜欢你的选集" }, @@ -2736,10 +2654,6 @@ "defaultMessage": "Liker ID", "description": "src/views/Me/Settings/Misc/LikerID.tsx" }, - "kSt4il": { - "defaultMessage": "收藏已取消", - "description": "src/components/Buttons/Bookmark/Unsubscribe.tsx" - }, "kc79d3": { "defaultMessage": "找你想看的" }, @@ -2796,9 +2710,6 @@ "lIir/P": { "defaultMessage": "我知道了" }, - "lMKb5N": { - "defaultMessage": "辞去权限成功" - }, "lNWFnL": { "defaultMessage": "分享这篇文章的翻译版本" }, @@ -2809,9 +2720,6 @@ "lO7wKc": { "defaultMessage": "再想想" }, - "lT6Dt8": { - "defaultMessage": "确认辞去" - }, "lZukEr": { "defaultMessage": "评论了", "description": "src/components/Notice/CommentNotice/ArticleNewCommentNotice.tsx" @@ -2931,9 +2839,6 @@ "defaultMessage": "在 ", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" }, - "nNLkZ8": { - "defaultMessage": "新增协作者" - }, "nWhqw9": { "defaultMessage": "立即发布" }, @@ -2952,9 +2857,6 @@ "defaultMessage": "邮箱不正确", "description": "USER_EMAIL_INVALID" }, - "o2Na0B": { - "defaultMessage": "返回全部" - }, "oGiO//": { "defaultMessage": "插入音频" }, @@ -3030,10 +2932,6 @@ "defaultMessage": "在动态中留言", "description": "src/components/Notice/CommentNotice/MomentNewCommentNotice.tsx" }, - "qE8ew4": { - "defaultMessage": "收藏成功", - "description": "src/components/Buttons/Bookmark/Subscribe.tsx" - }, "qNuRmA": { "defaultMessage": "发送临时密码", "description": "src/components/Forms/EmailLoginForm/Buttons.tsx" @@ -3074,10 +2972,6 @@ "qhVSGI": { "defaultMessage": "呐,作者亲手掩盖了这篇作品的痕迹,看看别的吧" }, - "qlki7w": { - "defaultMessage": "移除作品", - "description": "src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx" - }, "qlxeW+": { "defaultMessage": "取消点踩" }, @@ -3120,9 +3014,6 @@ "defaultMessage": "开始修改", "description": "src/components/Dialogs/ReviseArticleDialog/index.tsx" }, - "rLlTQ9": { - "defaultMessage": "标签名称" - }, "rXnmeE": { "defaultMessage": "确认发送" }, @@ -3240,9 +3131,6 @@ "defaultMessage": "留言已刪除", "description": "Moment" }, - "uJkv2X": { - "defaultMessage": "编辑标签" - }, "uM5qZr": { "defaultMessage": "我赞赏的" }, @@ -3336,9 +3224,6 @@ "defaultMessage": "支持了", "description": "src/components/Notice/TransactionNotice/PaymentReceivedDonationNotice.tsx" }, - "vLcHiG": { - "defaultMessage": "移除后,{user} 将无法继续参与「精选」作品管理。" - }, "vRCDr8": { "defaultMessage": "绑定后可以快速登入帐户{br}读者也能够透过其他管道自由转钱支持你!", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -3508,10 +3393,6 @@ "yOhatg": { "defaultMessage": "其他恶意行为" }, - "ySGgTo": { - "defaultMessage": "添加精选", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "ySSF/a": { "defaultMessage": "为了保障马特市市民的身份安全,我们升级了管理设定。请确认您的 Matters ID(确认后不可再次修改)", "description": "src/components/Dialogs/SetUserNameDialog/Content.tsx" @@ -3520,9 +3401,6 @@ "defaultMessage": "网络错误,请刷新页面", "description": "NETWORK_ERROR" }, - "yXWwSW": { - "defaultMessage": "确定要这么做吗 😭" - }, "yZfKI4": { "defaultMessage": " 眾聊提及你", "description": "src/components/Notice/CommentNotice/CommentMentionedYouNotice.tsx" diff --git a/lang/zh-Hant.json b/lang/zh-Hant.json index fbbffb8901..4d31476398 100644 --- a/lang/zh-Hant.json +++ b/lang/zh-Hant.json @@ -127,15 +127,9 @@ "0/gRer": { "defaultMessage": "我正在搬家到 Matters,邀請你一起來" }, - "0/iEw/": { - "defaultMessage": "管理社群" - }, "06XHBC": { "defaultMessage": "加入圍爐" }, - "0Azlrb": { - "defaultMessage": "管理" - }, "0CyECR": { "defaultMessage": "Matters ID 已設置,更多帳號相關設置可前往設定頁修改", "description": "src/components/Dialogs/SetUserNameDialog/ConfirmStep.tsx" @@ -228,9 +222,6 @@ "defaultMessage": "尚無閱讀紀錄", "description": "src/views/Me/History/index.tsx" }, - "1ZFwRz": { - "defaultMessage": "確認移除" - }, "1exrSw": { "defaultMessage": "歡迎上船!" }, @@ -343,9 +334,6 @@ "3YAasP": { "defaultMessage": "什麼是 Liker ID?" }, - "3fqQHv": { - "defaultMessage": "添加協作者" - }, "3kbIhS": { "defaultMessage": "未命名" }, @@ -416,9 +404,6 @@ "defaultMessage": "確認要解綁 {type} 嗎?", "description": "src/components/Dialogs/RemoveSocialLoginDialog/Content.tsx" }, - "5FO4vn": { - "defaultMessage": "你尚無權限進行該操作" - }, "5Ga0iK": { "defaultMessage": "插入程式碼" }, @@ -480,10 +465,6 @@ "62nsdy": { "defaultMessage": "重試" }, - "63HuBz": { - "defaultMessage": "此標籤目前無人主理", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "69+D96": { "defaultMessage": "開始創作" }, @@ -609,10 +590,6 @@ "7oytv9": { "defaultMessage": "(修改過)" }, - "7xnrxG": { - "defaultMessage": "作品已添加至精選", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "7ykJ+l": { "defaultMessage": "暫無評論", "description": "src/components/Empty/EmptyComment.tsx" @@ -632,6 +609,10 @@ "defaultMessage": "取消代表作", "description": "src/views/User/Articles/PinBoard/UnPinButton/index.tsx" }, + "8GXAUX": { + "defaultMessage": "有關", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "8KFsZN": { "defaultMessage": "閱讀次數" }, @@ -645,6 +626,9 @@ "8YgVvt": { "defaultMessage": "喜歡選集" }, + "8ZyDQJ": { + "defaultMessage": "收藏已取消" + }, "8cv9D4": { "defaultMessage": "下一步" }, @@ -766,10 +750,6 @@ "AGDFGs": { "defaultMessage": "歧視、侮辱或仇恨" }, - "ANA7sk": { - "defaultMessage": "主理", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "AVpR3Q": { "defaultMessage": "已綁定錢包", "description": "src/components/UserProfile/WalletLabel/index.tsx" @@ -785,6 +765,10 @@ "AeVndq": { "defaultMessage": "在動態留言中提及了你 {commentMoment}" }, + "Ajc5SE": { + "defaultMessage": "作品", + "description": "src/views/Me/Bookmarks/Tabs.tsx" + }, "AlHYvk": { "defaultMessage": "{type}已編輯" }, @@ -863,10 +847,6 @@ "defaultMessage": "{type} 已綁定", "description": "src/views/Me/Settings/Settings/Socials/index.tsx" }, - "C8GQaD": { - "defaultMessage": "{date}更新", - "description": "src/components/CollectionDigest/Feed/index.tsx" - }, "C9jbHn": { "defaultMessage": "拍手數量", "description": "src/components/ArticleDigest/Published/FooterActions/index.tsx" @@ -1102,10 +1082,6 @@ "GRrsEH": { "defaultMessage": "查看作品" }, - "GRtGnZ": { - "defaultMessage": "辭去權限", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "GU6vV0": { "defaultMessage": "尚未創建選集", "description": "src/components/Empty/EmptyCollection.tsx" @@ -1182,6 +1158,10 @@ "HbEL82": { "defaultMessage": "評論已刪除" }, + "HbwwAe": { + "defaultMessage": "{date}更新", + "description": "src/components/CollectionDigest/Feed/index.tsx" + }, "HgY+72": { "defaultMessage": "報名參加", "description": "src/views/CampaignDetail/Apply/Button/index.tsx" @@ -1193,9 +1173,6 @@ "Hlwud7": { "defaultMessage": "更多 ENS 資訊請參考 {node}." }, - "Hm2DAQ": { - "defaultMessage": "確定移除協作者" - }, "HnxG15": { "defaultMessage": "設定" }, @@ -1236,6 +1213,10 @@ "ISly67": { "defaultMessage": "同意" }, + "IUS82d": { + "defaultMessage": "標籤活躍作者", + "description": "src/views/TagDetail/RecommendedAuthors/index.tsx" + }, "IXycMo": { "defaultMessage": "重新發送" }, @@ -1301,10 +1282,6 @@ "Jr12wo": { "defaultMessage": "插入影片" }, - "Js/Fij": { - "defaultMessage": "作品已取消精選", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "Jxr/TM": { "defaultMessage": "已滿", "description": "src/components/Dialogs/AddCollectionsArticleDialog/SelectDialogContent.tsx" @@ -1330,10 +1307,6 @@ "defaultMessage": "圍爐創建成功", "description": "src/components/Forms/CreateCircleForm/Profile.tsx" }, - "KMcrz8": { - "defaultMessage": "認領", - "description": "src/views/TagDetail/Owner/index.tsx" - }, "KQi/UZ": { "defaultMessage": "封存作品" }, @@ -1348,9 +1321,6 @@ "defaultMessage": "錢包已綁定", "description": "src/components/Forms/WalletAuthForm/Connect.tsx" }, - "KoR0wt": { - "defaultMessage": "協作者可以與你共同管理精選" - }, "Kwv1n3": { "defaultMessage": " 用以出版 Writing NFT,費用 ≈1 LIKE,推廣期由平台補助" }, @@ -1377,10 +1347,6 @@ "defaultMessage": "展開", "description": "src/components/Expandable/index.tsx" }, - "L7Si5/": { - "defaultMessage": "管理社群", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "LETb4b": { "defaultMessage": "選集暫時不允許超過 {count} 篇", "description": "src/views/User/CollectionDetail/CollectionArticles/ViewerArticles.tsx" @@ -1423,9 +1389,6 @@ "defaultMessage": "你無法對此對象進行該操作", "description": "FORBIDDEN_BY_TARGET_STATE" }, - "LnesNr": { - "defaultMessage": "移除協作者成功" - }, "LoQ3BF": { "defaultMessage": "這枚徽章代表你完成了七天寫作,恭喜走完這趟意義非凡的寫作之旅!" }, @@ -1602,12 +1565,6 @@ "defaultMessage": "教學指南", "description": "src/components/Forms/PaymentForm/PayTo/SetAmount/SetAmountHeader/WhyOptimismDialog/index.tsx" }, - "P1AKC5": { - "defaultMessage": "協作者" - }, - "P2Btra": { - "defaultMessage": "認領成功" - }, "P3y9Bo": { "defaultMessage": "前往簽署", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -1693,9 +1650,6 @@ "QvPc1q": { "defaultMessage": "上傳封面" }, - "Qzdtxi": { - "defaultMessage": "辭去權限" - }, "R410ei": { "defaultMessage": "驗證碼錯誤", "description": "CODE_INVALID" @@ -1830,9 +1784,6 @@ "T9oZC8": { "defaultMessage": "確認要刪除該選集「{collection}」嗎?" }, - "TAPLOf": { - "defaultMessage": "每個標籤最多添加 {count} 名協作者" - }, "TF1OhT": { "defaultMessage": "臨時密碼已過期,請嘗試重新發送" }, @@ -1863,16 +1814,10 @@ "defaultMessage": "Optimism 是獨立運行的區塊鏈,若你在其他鏈上已有 USDT 貨幣,需要將它們轉移到 Optimism 網絡才能使用,詳情參考 {tutorial}.", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" }, - "ThSfXQ": { - "defaultMessage": "添加協作者成功" - }, "TjWWxF": { "defaultMessage": "廣播已送出", "description": "src/views/Circle/Broadcast/Broadcast.tsx" }, - "TzhzIH": { - "defaultMessage": "創作者" - }, "U+qEBM": { "defaultMessage": "切換網路", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -1910,10 +1855,6 @@ "defaultMessage": "移至底部", "description": "src/components/ArticleDigest/DropdownActions/SetBottomCollectionButton.tsx" }, - "UjKkhq": { - "defaultMessage": "作品已添加標籤", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "Up5U7K": { "defaultMessage": "封鎖" }, @@ -1924,9 +1865,6 @@ "Uq6tfM": { "defaultMessage": "添加說明文字…" }, - "Uv0hqn": { - "defaultMessage": "認領標籤" - }, "UxAA/V": { "defaultMessage": "Optimism 是基於以太坊的第二層(Layer2)擴容方案,能提升交易速度,並降低手續費,同時確保安全性,讓你更輕鬆地支持創作者。", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2014,10 +1952,6 @@ "WQT8ZA": { "defaultMessage": "編輯選集" }, - "WSUAwk": { - "defaultMessage": "添加到精選", - "description": "src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx" - }, "WiGHyF": { "defaultMessage": "Web Monetization 標準" }, @@ -2121,6 +2055,9 @@ "Y8zV4A": { "defaultMessage": "回覆評論" }, + "YDMrKK": { + "defaultMessage": "用戶" + }, "YPMn9n": { "defaultMessage": "請先登入再進行操作", "description": "UNAUTHENTICATED" @@ -2194,9 +2131,6 @@ "ZZ9zIR": { "defaultMessage": "點踩" }, - "Zakh0i": { - "defaultMessage": "還沒有追蹤任何標籤" - }, "ZjDH42": { "defaultMessage": "關於我們" }, @@ -2217,9 +2151,6 @@ "defaultMessage": "讀者數量:訪問過作品頁的不重複的登入用戶數加匿名 IP 數(數據週期更新,可能存在延遲)", "description": "src/views/Me/Works/Published/SortTabs.tsx" }, - "a3j20X": { - "defaultMessage": "即刻主理" - }, "aCTmEO": { "defaultMessage": "我還沒有錢包", "description": "src/components/Forms/SelectAuthMethodForm/WalletFeed.tsx" @@ -2235,9 +2166,6 @@ "aKEiNd": { "defaultMessage": "錯過報名期沒關係,仍然可以用晚鳥身份參與,一起書寫人生故事。下次早點報名,就有機會獲得大滿貫徽章!" }, - "aKlTO2": { - "defaultMessage": "你還可以添加 {count} 名協作者" - }, "aOFCqL": { "defaultMessage": "最多評論", "description": "src/views/Me/Works/Published/SortTabs.tsx" @@ -2248,10 +2176,6 @@ "aTmmkr": { "defaultMessage": "你已經與圍爐告別,感謝曾經的付出與參與。" }, - "aa0nss": { - "defaultMessage": "取消精選", - "description": "src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx" - }, "aaUBvF": { "defaultMessage": " 中的發言", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" @@ -2347,6 +2271,10 @@ "cd/II9": { "defaultMessage": "{totalCount, plural, =1 {篇文章} other {篇文章}}" }, + "cd8EmU": { + "defaultMessage": "的檢索結果", + "description": "src/views/Search/AggregateResults/index.tsx" + }, "cg1VJ2": { "defaultMessage": "連接加密錢包" }, @@ -2409,9 +2337,6 @@ "deEeEI": { "defaultMessage": "註冊" }, - "dg3JCQ": { - "defaultMessage": "協作者" - }, "djJp6c": { "defaultMessage": "我的足跡" }, @@ -2438,9 +2363,6 @@ "eWXgsZ": { "defaultMessage": "清空内容" }, - "eXDZGQ": { - "defaultMessage": "主理人" - }, "eY3YIa": { "defaultMessage": "複製評論" }, @@ -2591,10 +2513,6 @@ "defaultMessage": "餘額不足:", "description": "src/components/Balance/index.tsx" }, - "hYG5fb": { - "defaultMessage": "人追蹤", - "description": "src/views/TagDetail/Followers/index.tsx" - }, "hgtWIO": { "defaultMessage": "作品被關聯", "description": "src/views/Me/Settings/Notifications/GeneralSettings/index.tsx" @@ -2626,6 +2544,9 @@ "iEJeQH": { "defaultMessage": "設置 Liker ID" }, + "iIitRg": { + "defaultMessage": "尚未收藏標籤" + }, "iNZdM/": { "defaultMessage": "切換後即可支持創作者,採用 Optimism 網路{br}讓支持更方便且費用低廉", "description": "src/components/Forms/PaymentForm/SwitchNetwork/index.tsx" @@ -2696,8 +2617,8 @@ "defaultMessage": "在 {circlename} 發布廣播", "description": "src/components/Notice/CommentNotice/CircleNewBroadcastNotice.tsx" }, - "k0ooDW": { - "defaultMessage": "標籤描述" + "k0fraU": { + "defaultMessage": "收藏成功" }, "k2veDA": { "defaultMessage": "創作" @@ -2715,9 +2636,6 @@ "kCPl0r": { "defaultMessage": "關聯" }, - "kCp8A9": { - "defaultMessage": "如果辭去權限,你將無法繼續管理標籤。" - }, "kEDrXh": { "defaultMessage": "喜歡你的選集" }, @@ -2736,10 +2654,6 @@ "defaultMessage": "Liker ID", "description": "src/views/Me/Settings/Misc/LikerID.tsx" }, - "kSt4il": { - "defaultMessage": "收藏已取消", - "description": "src/components/Buttons/Bookmark/Unsubscribe.tsx" - }, "kc79d3": { "defaultMessage": "找你想看的" }, @@ -2796,9 +2710,6 @@ "lIir/P": { "defaultMessage": "我知道了" }, - "lMKb5N": { - "defaultMessage": "辭去權限成功" - }, "lNWFnL": { "defaultMessage": "分享這篇文章的翻譯版本" }, @@ -2809,9 +2720,6 @@ "lO7wKc": { "defaultMessage": "再想想" }, - "lT6Dt8": { - "defaultMessage": "確認辭去" - }, "lZukEr": { "defaultMessage": "評論了", "description": "src/components/Notice/CommentNotice/ArticleNewCommentNotice.tsx" @@ -2931,9 +2839,6 @@ "defaultMessage": "在", "description": "src/components/Notice/CommentCommentNotice/CommentNewReplyNotice.tsx" }, - "nNLkZ8": { - "defaultMessage": "新增協作者" - }, "nWhqw9": { "defaultMessage": "立即發布" }, @@ -2952,9 +2857,6 @@ "defaultMessage": "電子信箱不正確", "description": "USER_EMAIL_INVALID" }, - "o2Na0B": { - "defaultMessage": "返回全部" - }, "oGiO//": { "defaultMessage": "插入音訊" }, @@ -3030,10 +2932,6 @@ "defaultMessage": "在動態中留言", "description": "src/components/Notice/CommentNotice/MomentNewCommentNotice.tsx" }, - "qE8ew4": { - "defaultMessage": "收藏成功", - "description": "src/components/Buttons/Bookmark/Subscribe.tsx" - }, "qNuRmA": { "defaultMessage": "發送臨時密碼", "description": "src/components/Forms/EmailLoginForm/Buttons.tsx" @@ -3074,10 +2972,6 @@ "qhVSGI": { "defaultMessage": "吶,作者親手掩蓋了這篇作品的痕跡,看看別的吧" }, - "qlki7w": { - "defaultMessage": "移除作品", - "description": "src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx" - }, "qlxeW+": { "defaultMessage": "取消點踩" }, @@ -3120,9 +3014,6 @@ "defaultMessage": "開始修改", "description": "src/components/Dialogs/ReviseArticleDialog/index.tsx" }, - "rLlTQ9": { - "defaultMessage": "標籤名稱" - }, "rXnmeE": { "defaultMessage": "確認發送" }, @@ -3240,9 +3131,6 @@ "defaultMessage": "留言已刪除", "description": "Moment" }, - "uJkv2X": { - "defaultMessage": "編輯標籤" - }, "uM5qZr": { "defaultMessage": "我讚賞的" }, @@ -3336,9 +3224,6 @@ "defaultMessage": "支持了", "description": "src/components/Notice/TransactionNotice/PaymentReceivedDonationNotice.tsx" }, - "vLcHiG": { - "defaultMessage": "移除后,{user} 將無法繼續參與「精選」作品管理。" - }, "vRCDr8": { "defaultMessage": "綁定後可以快速登入帳戶{br}讀者也能夠透過其他管道自由轉錢支持你!", "description": "src/components/Forms/PaymentForm/BindWallet/index.tsx" @@ -3508,10 +3393,6 @@ "yOhatg": { "defaultMessage": "其他惡意行為" }, - "ySGgTo": { - "defaultMessage": "添加精選", - "description": "src/views/TagDetail/DropdownActions/index.tsx" - }, "ySSF/a": { "defaultMessage": "爲了保障馬特市市民的身份安全,我們升級了管理設定。請確認您的 Matters ID(確認後不可再次修改)", "description": "src/components/Dialogs/SetUserNameDialog/Content.tsx" @@ -3520,9 +3401,6 @@ "defaultMessage": "網路錯誤,請刷新頁面", "description": "NETWORK_ERROR" }, - "yXWwSW": { - "defaultMessage": "確定要這麼做嗎 😭" - }, "yZfKI4": { "defaultMessage": " 众聊提及你", "description": "src/components/Notice/CommentNotice/CommentMentionedYouNotice.tsx" diff --git a/package.json b/package.json index 242319ed45..d0c625f838 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matters-web", - "version": "5.6.6", + "version": "5.7.0", "description": "codebase of Matters' website", "author": "Matters ", "engines": { diff --git a/src/common/enums/events.ts b/src/common/enums/events.ts index 7dfcf5783b..f40039c0a2 100644 --- a/src/common/enums/events.ts +++ b/src/common/enums/events.ts @@ -55,6 +55,7 @@ export const SUPPORT_SUCCESS_ANIMATION = 'supportSuccessAnimation' export enum UNIVERSAL_AUTH_TRIGGER { appreciation = 'appreciation', bookmark = 'bookmark', + bookmarkTag = 'bookmarkTag', circlePrice = 'circlePrice', circleSubscription = 'circleSubscription', collectArticle = 'collectArticle', diff --git a/src/common/enums/oauth.ts b/src/common/enums/oauth.ts index d310f3032b..28594a3968 100644 --- a/src/common/enums/oauth.ts +++ b/src/common/enums/oauth.ts @@ -31,7 +31,7 @@ export const OAUTH_SCOPE_TREE = { zh_hans: '草稿', }, }, - subscriptions: { + bookmarkedArticles: { _t: { zh_hant: '收藏作品', zh_hans: '收藏作品', @@ -87,42 +87,18 @@ export const OAUTH_SCOPE_TREE = { zh_hant: '管理個人資料、標籤、評論、封鎖、追蹤等', zh_hans: '管理个人资料、标签、评论、封锁、关注等', }, - toggleSubscribeArticle: { + toggleBookmarkArticle: { _t: { zh_hant: '收藏作品', zh_hans: '收藏作品', }, }, - toggleFollowTag: { + toggleBookmarkTag: { _t: { zh_hant: '追蹤標籤', zh_hans: '关注标签', }, }, - updateTagSetting: { - _t: { - zh_hant: '管理標籤', - zh_hans: '管理标签', - }, - }, - addArticlesTags: { - _t: { - zh_hant: '添加作品到標籤', - zh_hans: '添加作品到标签', - }, - }, - updateArticlesTags: { - _t: { - zh_hant: '管理標籤作品', - zh_hans: '管理标签作品', - }, - }, - deleteArticlesTags: { - _t: { - zh_hant: '移除標籤作品', - zh_hans: '移除标签作品', - }, - }, togglePinComment: { _t: { zh_hant: '精选評論', diff --git a/src/common/enums/route.ts b/src/common/enums/route.ts index 182f5951b2..7ab3eb77f5 100644 --- a/src/common/enums/route.ts +++ b/src/common/enums/route.ts @@ -40,7 +40,8 @@ type ROUTE_KEY = | 'ME_DRAFTS' | 'ME_PUBLISHED' | 'ME_ARCHIVED' - | 'ME_BOOKMARKS' + | 'ME_BOOKMARKS_ARTICLES' + | 'ME_BOOKMARKS_TAGS' | 'ME_HISTORY' | 'ME_HISTORY_COMMENTS' | 'ME_HISTORY_LIKES_SENT' @@ -146,7 +147,8 @@ export const ROUTES: { { key: 'ME_DRAFTS', pathname: '/me/drafts' }, { key: 'ME_PUBLISHED', pathname: '/me/published' }, { key: 'ME_ARCHIVED', pathname: '/me/archived' }, - { key: 'ME_BOOKMARKS', pathname: '/me/bookmarks' }, + { key: 'ME_BOOKMARKS_ARTICLES', pathname: '/me/bookmarks/articles' }, + { key: 'ME_BOOKMARKS_TAGS', pathname: '/me/bookmarks/tags' }, { key: 'ME_HISTORY', pathname: '/me/history' }, { key: 'ME_HISTORY_COMMENTS', pathname: '/me/history/comments' }, { key: 'ME_HISTORY_LIKES_SENT', pathname: '/me/history/likes/sent' }, diff --git a/src/common/enums/test.ts b/src/common/enums/test.ts index 1dc25f7832..3cb983ce83 100644 --- a/src/common/enums/test.ts +++ b/src/common/enums/test.ts @@ -31,8 +31,9 @@ export enum TEST_ID { DIGEST_USER_RICH_DISPLAY_NAME = 'digest/user/rich/display-name', DIGEST_USER_VERBOSE = 'digest/user/verbose', DIGEST_TAG_CONCISE = 'digest/tag/concise', + DIGEST_TAG_BOOKMARK = 'digest/tag/bookmark', DIGEST_TAG_FEED = 'digest/tag/feed', - DIGEST_TAG_FEED_COVER = 'digest/tag/feed/cover', + DIGEST_TAG_FEED_NUM_ARTICLES = 'digest/tag/feed/num-articles', DIGEST_TAG_RICH = 'digest/tag/rich', DIGEST_TAG_SIDEBAR = 'digest/tag/sidebar', DIGRET_CIRCLE_PLAIN = 'digest/circle/plain', @@ -44,7 +45,6 @@ export enum TEST_ID { DIGEST_CIRCLE_MEMBER_COUNT = 'digest/circle/member-count', DIGEST_CIRCLE_ARTICLE_COUNT = 'digest/circle/article-count', DIGEST_CIRCLE_PRICE = 'digest/circle/price', - DIGEST_TAG_SIDEBAR_COVER = 'digest/tag/sidebar/cover', DIGEST_COLLECTION_FEED = 'digest/collection/feed', DIGEST_DRAFT_FEED = 'digest/draft/feed', // dialogs diff --git a/src/common/styles/variables/spacing.css b/src/common/styles/variables/spacing.css index 4db77aa7c0..0c7f191178 100644 --- a/src/common/styles/variables/spacing.css +++ b/src/common/styles/variables/spacing.css @@ -9,6 +9,7 @@ --sp12: 0.75rem; /* 12px */ --sp14: 0.875rem; /* 14px */ --sp16: 1rem; /* 16px */ + --sp18: 1.125rem; /* 18px */ --sp20: 1.25rem; /* 20px */ --sp24: 1.5rem; /* 24px */ --sp32: 2rem; /* 32px */ diff --git a/src/common/utils/analytics.ts b/src/common/utils/analytics.ts index 74c59c2a37..43db1a8f84 100644 --- a/src/common/utils/analytics.ts +++ b/src/common/utils/analytics.ts @@ -40,6 +40,7 @@ type EventArgs = | ['authenticate', AuthenticateProp] | ['billboard_exposure', BillboardExposureProp] | ['click_billboard', ClickBillboardProp] + | ['read_time', ReadTimeProp] /** * Event: Page View @@ -239,6 +240,11 @@ interface AuthenticateProp { trigger?: string } +interface ReadTimeProp { + articleId: string + time: number +} + // content type export type ContentType = | 'article' @@ -340,6 +346,7 @@ type UserFeedType = | 'tag_detail_latest' | 'tag_detail_selected' | 'tag_detail_community' + | 'tag_detail_recommended_authors' | 'transaction' type TagFeedType = diff --git a/src/common/utils/text/tag.ts b/src/common/utils/text/tag.ts index 1242d582dc..1d716d4816 100644 --- a/src/common/utils/text/tag.ts +++ b/src/common/utils/text/tag.ts @@ -25,7 +25,7 @@ const stripTagAllPunct = (content: string) => { return words[0] default: const [first, ...rest] = words - return `${first} ${rest.join('')}` + return `${first} ${rest.join(' ')}` } } diff --git a/src/common/utils/url.ts b/src/common/utils/url.ts index 7b21c4c012..39927a9206 100644 --- a/src/common/utils/url.ts +++ b/src/common/utils/url.ts @@ -48,7 +48,7 @@ const changeExt = ({ key, ext }: { key: string; ext?: 'webp' }) => { } export const toSizedImageURL = ({ - url, + url = '', width, height, ext, diff --git a/src/components/ArticleDigest/DropdownActions/ArchiveArticle/Dialog.tsx b/src/components/ArticleDigest/DropdownActions/ArchiveArticle/Dialog.tsx index 416f15af9c..f8a06ee41f 100644 --- a/src/components/ArticleDigest/DropdownActions/ArchiveArticle/Dialog.tsx +++ b/src/components/ArticleDigest/DropdownActions/ArchiveArticle/Dialog.tsx @@ -22,7 +22,6 @@ const ARCHIVE_ARTICLE = gql` editArticle(input: { id: $id, state: archived }) { id articleState: state - sticky } } ` @@ -52,7 +51,6 @@ const ArchiveArticleDialog = ({ editArticle: { id: article.id, articleState: 'archived' as any, - sticky: false, __typename: 'Article', }, }, diff --git a/src/components/ArticleDigest/DropdownActions/DropdownActions.test.tsx b/src/components/ArticleDigest/DropdownActions/DropdownActions.test.tsx index 5ec21d4495..7d686fd2b6 100644 --- a/src/components/ArticleDigest/DropdownActions/DropdownActions.test.tsx +++ b/src/components/ArticleDigest/DropdownActions/DropdownActions.test.tsx @@ -190,19 +190,8 @@ describe('', () => { expect($archiveButton).toBeInTheDocument() }) - // hasSetTagSelected - // hasSetTagUnselected - // hasRemoveTag it('should render tag buttons', async () => { - render( - - ) + render() const $button = screen.getByLabelText('More Actions') expect($button).toBeInTheDocument() @@ -211,24 +200,6 @@ describe('', () => { $button.click() const $menu = screen.getByRole('menu') expect($menu).toBeInTheDocument() - - // hasSetTagSelected - const $setTagSelectedBtn = screen.getByRole('menuitem', { - name: 'Add to Featured', - }) - expect($setTagSelectedBtn).toBeInTheDocument() - - // hasUnsetTagSelected - const $setTagUnselectedBtn = screen.getByRole('menuitem', { - name: 'Unpin from Trending', - }) - expect($setTagUnselectedBtn).toBeInTheDocument() - - // hasRemoveTag - const $removeTagBtn = screen.getByRole('menuitem', { - name: 'Remove Article', - }) - expect($removeTagBtn).toBeInTheDocument() }) // hasSetTopCollection diff --git a/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx b/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx deleted file mode 100644 index 73becee7d3..0000000000 --- a/src/components/ArticleDigest/DropdownActions/RemoveTagButton.tsx +++ /dev/null @@ -1,86 +0,0 @@ -import gql from 'graphql-tag' -import _isArray from 'lodash/isArray' -import { FormattedMessage } from 'react-intl' - -import { ReactComponent as IconCircleMinus } from '@/public/static/icons/24px/circle-minus.svg' -import { REFETCH_TAG_DETAIL_ARTICLES } from '~/common/enums' -import { Icon, Menu, useMutation } from '~/components' -import { updateTagArticlesCount } from '~/components/GQL' -import { - DeleteArticlesTagsMutation, - RemoveTagButtonArticleFragment, -} from '~/gql/graphql' - -const DELETE_ARTICLES_TAGS = gql` - mutation DeleteArticlesTags($id: ID!, $articles: [ID!]) { - deleteArticlesTags(input: { id: $id, articles: $articles }) { - id - articles(input: { first: 0, selected: true }) { - totalCount - } - } - } -` - -const fragments = { - article: gql` - fragment RemoveTagButtonArticle on Article { - id - tags { - id - creator { - id - } - editors { - id - } - } - } - `, -} - -const RemoveTagButton = ({ - article, - tagId, -}: { - article: RemoveTagButtonArticleFragment - tagId: string -}) => { - const [deleteArticlesTags] = useMutation( - DELETE_ARTICLES_TAGS, - { - variables: { id: tagId, articles: [article.id] }, - update: (cache) => { - updateTagArticlesCount({ cache, type: 'decrement', id: tagId }) - }, - } - ) - - return ( - - } - icon={} - onClick={async () => { - await deleteArticlesTags() - - window.dispatchEvent( - new CustomEvent(REFETCH_TAG_DETAIL_ARTICLES, { - detail: { - event: 'delete', - }, - }) - ) - }} - /> - ) -} - -RemoveTagButton.fragments = fragments - -export default RemoveTagButton diff --git a/src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx b/src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx deleted file mode 100644 index b049a29675..0000000000 --- a/src/components/ArticleDigest/DropdownActions/SetTagSelectedButton.tsx +++ /dev/null @@ -1,81 +0,0 @@ -import gql from 'graphql-tag' -import { FormattedMessage } from 'react-intl' - -import { ReactComponent as IconCirclePlus } from '@/public/static/icons/24px/circle-plus.svg' -import { Icon, Menu, toast, useMutation } from '~/components' -import { - SetTagSelectedButtonArticleFragment, - SetTagSelectedMutation, -} from '~/gql/graphql' - -const SET_TAG_SELECTED = gql` - mutation SetTagSelected($id: ID!, $articles: [ID!]) { - updateArticlesTags( - input: { id: $id, articles: $articles, isSelected: true } - ) { - id - articles(input: { first: 0, selected: true }) { - totalCount - } - } - } -` - -const fragments = { - article: gql` - fragment SetTagSelectedButtonArticle on Article { - id - tags { - id - creator { - id - } - editors { - id - } - } - } - `, -} - -const SetTagSelectedButton = ({ - article, - tagId, -}: { - article: SetTagSelectedButtonArticleFragment - tagId: string -}) => { - const [update] = useMutation(SET_TAG_SELECTED, { - variables: { id: tagId, articles: [article.id] }, - }) - - return ( - - } - icon={} - onClick={async () => { - await update() - - toast.success({ - message: ( - - ), - }) - }} - /> - ) -} - -SetTagSelectedButton.fragments = fragments - -export default SetTagSelectedButton diff --git a/src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx b/src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx deleted file mode 100644 index 595b5e93fe..0000000000 --- a/src/components/ArticleDigest/DropdownActions/SetTagUnselectedButton.tsx +++ /dev/null @@ -1,129 +0,0 @@ -import gql from 'graphql-tag' -import _filter from 'lodash/filter' -import _get from 'lodash/get' -import { FormattedMessage } from 'react-intl' - -import { ReactComponent as IconLTime } from '@/public/static/icons/24px/l-time.svg' -import { Icon, Menu, toast, useMutation } from '~/components' -import { - SetTagUnselectedButtonArticleFragment, - SetTagUnselectedMutation, - TagArticlesPublicQuery, -} from '~/gql/graphql' - -const SET_TAG_UNSELECTED = gql` - mutation SetTagUnselected($id: ID!, $articles: [ID!]) { - updateArticlesTags( - input: { id: $id, articles: $articles, isSelected: false } - ) { - id - articles(input: { first: 0, selected: true }) { - totalCount - } - } - } -` - -const fragments = { - article: gql` - fragment SetTagUnselectedButtonArticle on Article { - id - tags { - id - creator { - id - } - editors { - id - } - } - } - `, -} - -const SetTagUnselectedButton = ({ - article, - tagId, -}: { - article: SetTagUnselectedButtonArticleFragment - tagId: string -}) => { - const [update] = useMutation(SET_TAG_UNSELECTED, { - variables: { id: tagId, articles: [article.id] }, - update: (cache) => { - try { - // FIXME: circular dependencies - const { - TAG_ARTICLES_PUBLIC: query, - } = require('~/components/GQL/queries/tagArticles') - const variables = { - id: tagId, - selected: true, - sortBy: 'byCreatedAtDesc', - } - const data = cache.readQuery({ - query, - variables, - }) - const node = _get(data, 'node') - const articles = node?.__typename === 'Tag' ? node?.articles : null - - if (!articles || !articles?.edges || articles?.edges?.length === 0) { - return - } - - const newEdges = articles.edges.filter( - (item) => item.node.id !== article.id - ) - cache.writeQuery({ - query, - variables, - data: { - node: { - ...node, - articles: { - ...articles, - edges: newEdges, - }, - }, - }, - }) - sync() - } catch (error) { - console.error(error) - } - }, - }) - - const sync = () => { - toast.success({ - message: ( - - ), - }) - } - - return ( - - } - icon={} - onClick={async () => { - await update() - }} - /> - ) -} - -SetTagUnselectedButton.fragments = fragments - -export default SetTagUnselectedButton diff --git a/src/components/ArticleDigest/DropdownActions/gql.ts b/src/components/ArticleDigest/DropdownActions/gql.ts index cdc666d643..19c8d3f16d 100644 --- a/src/components/ArticleDigest/DropdownActions/gql.ts +++ b/src/components/ArticleDigest/DropdownActions/gql.ts @@ -10,9 +10,6 @@ import ArchiveArticle from './ArchiveArticle' import EditButton from './EditButton' import ExtendButton from './ExtendButton' import PinButton from './PinButton' -import RemoveTagButton from './RemoveTagButton' -import SetTagSelectedButton from './SetTagSelectedButton' -import SetTagUnselectedButton from './SetTagUnselectedButton' export const fragments = { article: gql` @@ -23,19 +20,13 @@ export const fragments = { ...ArchiveArticleArticle ...PinButtonArticle ...ExtendButtonArticle - ...RemoveTagButtonArticle ...EditArticleButtonArticle - ...SetTagSelectedButtonArticle - ...SetTagUnselectedButtonArticle } ${AppreciatorsDialog.fragments.article} ${SupportersDialog.fragments.article} ${PinButton.fragments.article} ${ArchiveArticle.fragments.article} ${ExtendButton.fragments.article} - ${RemoveTagButton.fragments.article} ${EditButton.fragments.article} - ${SetTagSelectedButton.fragments.article} - ${SetTagUnselectedButton.fragments.article} `, } diff --git a/src/components/ArticleDigest/DropdownActions/index.tsx b/src/components/ArticleDigest/DropdownActions/index.tsx index 2e086e3ca6..ce0cac35c5 100644 --- a/src/components/ArticleDigest/DropdownActions/index.tsx +++ b/src/components/ArticleDigest/DropdownActions/index.tsx @@ -49,10 +49,7 @@ import { fragments } from './gql' import IPFSButton from './IPFSButton' import PinButton from './PinButton' import RemoveArticleCollectionButton from './RemoveArticleCollectionButton' -import RemoveTagButton from './RemoveTagButton' import SetBottomCollectionButton from './SetBottomCollectionButton' -import SetTagSelectedButton from './SetTagSelectedButton' -import SetTagUnselectedButton from './SetTagUnselectedButton' import SetTopCollectionButton from './SetTopCollectionButton' import ShareButton from './ShareButton' import styles from './styles.module.css' @@ -126,9 +123,6 @@ export interface DropdownActionsControls { // tag tagDetailId?: string - hasSetTagSelected?: boolean - hasSetTagUnselected?: boolean - hasRemoveTag?: boolean // campaign campaignId?: string @@ -163,9 +157,6 @@ interface Controls { hasExtend: boolean hasReport: boolean hasSticky: boolean - hasSetTagSelected: boolean - hasSetTagUnselected: boolean - hasRemoveTag: boolean } interface DialogProps { @@ -215,9 +206,6 @@ const BaseDropdownActions = ({ hasReport, hasSticky, hasArchive, - hasSetTagSelected, - hasSetTagUnselected, - hasRemoveTag, hasToggleCampaignFeatured, hasEdit, hasBookmark, @@ -278,16 +266,6 @@ const BaseDropdownActions = ({ )} - {hasSetTagSelected && tagDetailId && ( - - )} - {hasSetTagUnselected && tagDetailId && ( - - )} - {hasRemoveTag && tagDetailId && ( - - )} - {hasArchive && } {hasArchive && } @@ -412,10 +390,6 @@ const DropdownActions = (props: DropdownActionsProps) => { inCard, inUserArticles, - hasSetTagSelected, - hasSetTagUnselected, - hasRemoveTag, - hasEdit, hasArchive, hasBookmark = true, @@ -452,9 +426,6 @@ const DropdownActions = (props: DropdownActionsProps) => { ), hasArchive: !!hasArchive && isArticleAuthor && isActive && !viewer.isArchived, - hasSetTagSelected: !!hasSetTagSelected, - hasSetTagUnselected: !!hasSetTagUnselected, - hasRemoveTag: !!hasRemoveTag, hasEdit: !!hasEdit && isActive && isArticleAuthor, hasBookmark: !!hasBookmark, hasAddCollection: hasAddCollection && isActive && isArticleAuthor, diff --git a/src/components/ArticleDigest/Feed/index.tsx b/src/components/ArticleDigest/Feed/index.tsx index c0e8eec4d0..bc23c634a4 100644 --- a/src/components/ArticleDigest/Feed/index.tsx +++ b/src/components/ArticleDigest/Feed/index.tsx @@ -179,12 +179,9 @@ export const ArticleDigestFeed = React.memo( BaseArticleDigestFeed, ({ article: prevArticle, ...prevProps }, { article, ...props }) => { return ( - prevArticle.subscribed === article.subscribed && + prevArticle.bookmarked === article.bookmarked && prevArticle.articleState === article.articleState && - prevArticle.pinned === article.pinned && - prevProps.hasSetTagSelected === props.hasSetTagSelected && - prevProps.hasSetTagUnselected === props.hasSetTagUnselected && - prevProps.hasRemoveTag === props.hasRemoveTag + prevArticle.pinned === article.pinned ) } ) as MemoizedArticleDigestFeed diff --git a/src/components/Buttons/Bookmark/Bookmark.test.tsx b/src/components/Buttons/Bookmark/Bookmark.test.tsx index 6933c2d0f4..cbf5878a3f 100644 --- a/src/components/Buttons/Bookmark/Bookmark.test.tsx +++ b/src/components/Buttons/Bookmark/Bookmark.test.tsx @@ -6,13 +6,13 @@ import { MOCK_ARTILCE } from '~/stories/mocks' describe('', () => { it('should render a bookmark button', () => { - render() + render() const $button = screen.getByRole('button', { name: 'Bookmark' }) expect($button).toBeInTheDocument() }) it('should render a remove bookmark button', () => { - render() + render() const $button = screen.getByRole('button', { name: 'Remove bookmark' }) expect($button).toBeInTheDocument() }) diff --git a/src/components/Buttons/Bookmark/Subscribe.tsx b/src/components/Buttons/Bookmark/Subscribe.tsx index b070ee00f7..1ef0494750 100644 --- a/src/components/Buttons/Bookmark/Subscribe.tsx +++ b/src/components/Buttons/Bookmark/Subscribe.tsx @@ -19,9 +19,9 @@ import { useMutation, ViewerContext, } from '~/components' -import { ToggleSubscribeArticleMutation } from '~/gql/graphql' +import { ToggleBookmarkArticleMutation } from '~/gql/graphql' -import TOGGLE_SUBSCRIBE_ARTICLE from '../../GQL/mutations/toggleSubscribeArticle' +import TOGGLE_BOOKMARK_ARTICLE from '../../GQL/mutations/toggleBookmarkArticle' export type SubscribeProps = { articleId?: string @@ -40,8 +40,8 @@ const Subscribe = ({ const viewer = useContext(ViewerContext) const intl = useIntl() - const [subscribe] = useMutation( - TOGGLE_SUBSCRIBE_ARTICLE, + const [subscribe] = useMutation( + TOGGLE_BOOKMARK_ARTICLE, { variables: { id: articleId, enabled: true }, } @@ -71,13 +71,7 @@ const Subscribe = ({ await subscribe() toast.success({ - message: ( - - ), + message: , }) } diff --git a/src/components/Buttons/Bookmark/Unsubscribe.tsx b/src/components/Buttons/Bookmark/Unsubscribe.tsx index 475522531a..1acbf9a5d4 100644 --- a/src/components/Buttons/Bookmark/Unsubscribe.tsx +++ b/src/components/Buttons/Bookmark/Unsubscribe.tsx @@ -13,9 +13,9 @@ import { useMutation, ViewerContext, } from '~/components' -import { ToggleSubscribeArticleMutation } from '~/gql/graphql' +import { ToggleBookmarkArticleMutation } from '~/gql/graphql' -import TOGGLE_SUBSCRIBE_ARTICLE from '../../GQL/mutations/toggleSubscribeArticle' +import TOGGLE_BOOKMARK_ARTICLE from '../../GQL/mutations/toggleBookmarkArticle' export type UnsubscribeProps = { articleId?: string @@ -34,8 +34,8 @@ const Unsubscribe = ({ const viewer = useContext(ViewerContext) const intl = useIntl() - const [unsubscribe] = useMutation( - TOGGLE_SUBSCRIBE_ARTICLE, + const [unsubscribe] = useMutation( + TOGGLE_BOOKMARK_ARTICLE, { variables: { id: articleId, enabled: false }, } @@ -57,11 +57,7 @@ const Unsubscribe = ({ toast.success({ message: ( - + ), }) } diff --git a/src/components/Buttons/Bookmark/index.tsx b/src/components/Buttons/Bookmark/index.tsx index b8b1029f31..6409e0eaf5 100644 --- a/src/components/Buttons/Bookmark/index.tsx +++ b/src/components/Buttons/Bookmark/index.tsx @@ -18,7 +18,7 @@ const fragments = { private: gql` fragment BookmarkArticlePrivate on Article { id - subscribed + bookmarked } `, }, @@ -32,7 +32,7 @@ export const BookmarkButton = ({ }: BookmarkButtonProps) => { const viewer = useContext(ViewerContext) - if (article.subscribed) { + if (article.bookmarked) { return ( { + const viewer = useContext(ViewerContext) + const intl = useIntl() + const { + ME_BOOKMARK_TAGS_FEED, + } = require('~/views/Me/Bookmarks/BookmarksTags') + const [bookmark] = useMutation( + TOGGLE_BOOKMARK_TAG, + { + variables: { id: tag.id, enabled: true }, + optimisticResponse: + !_isNil(tag.id) && !_isNil(tag.isFollower) + ? { + toggleBookmarkTag: { + id: tag.id, + isFollower: true, + __typename: 'Tag', + }, + } + : undefined, + refetchQueries: [ + { + query: ME_BOOKMARK_TAGS_FEED, + }, + ], + } + ) + + const onClick = async () => { + if (!viewer.isAuthed) { + window.dispatchEvent( + new CustomEvent(OPEN_UNIVERSAL_AUTH_DIALOG, { + detail: { trigger: UNIVERSAL_AUTH_TRIGGER.bookmarkTag }, + }) + ) + return + } + + await bookmark() + + toast.success({ + message: intl.formatMessage({ + defaultMessage: 'Bookmarked', + id: 'k0fraU', + }), + }) + } + + return ( + + ) +} + +export default Bookmark diff --git a/src/components/Buttons/TagBookmark/Unbookmark.tsx b/src/components/Buttons/TagBookmark/Unbookmark.tsx new file mode 100644 index 0000000000..09d3289208 --- /dev/null +++ b/src/components/Buttons/TagBookmark/Unbookmark.tsx @@ -0,0 +1,61 @@ +import _isNil from 'lodash/isNil' +import { useIntl } from 'react-intl' + +import { ReactComponent as IconSave2 } from '@/public/static/icons/24px/save2.svg' +import { Button, Icon, toast, useMutation } from '~/components' +import TOGGLE_BOOKMARK_TAG from '~/components/GQL/mutations/toggleBookmarkTag' +import { + TagBookmarkButtonTagPrivateFragment, + ToggleBookmarkTagMutation, +} from '~/gql/graphql' + +interface UnbookmarkTagProps { + tag: TagBookmarkButtonTagPrivateFragment +} + +const Unbookmark = ({ tag }: UnbookmarkTagProps) => { + const intl = useIntl() + const [unbookmark] = useMutation( + TOGGLE_BOOKMARK_TAG, + { + variables: { id: tag.id, enabled: false }, + optimisticResponse: + !_isNil(tag.id) && !_isNil(tag.isFollower) + ? { + toggleBookmarkTag: { + id: tag.id, + isFollower: false, + __typename: 'Tag', + }, + } + : undefined, + } + ) + const onClick = async () => { + await unbookmark() + toast.success({ + message: intl.formatMessage({ + defaultMessage: 'Bookmark removed', + id: '8ZyDQJ', + }), + }) + } + + return ( + + ) +} + +export default Unbookmark diff --git a/src/components/Buttons/TagBookmark/index.tsx b/src/components/Buttons/TagBookmark/index.tsx new file mode 100644 index 0000000000..07704b538e --- /dev/null +++ b/src/components/Buttons/TagBookmark/index.tsx @@ -0,0 +1,31 @@ +import gql from 'graphql-tag' + +import { TagBookmarkButtonTagPrivateFragment } from '~/gql/graphql' + +import Bookmark from './Bookmark' +import Unbookmark from './Unbookmark' + +interface TagBookmarkButtonProps { + tag: TagBookmarkButtonTagPrivateFragment +} + +const fragments = { + tag: { + private: gql` + fragment TagBookmarkButtonTagPrivate on Tag { + id + isFollower + } + `, + }, +} + +export const TagBookmarkButton = ({ tag }: TagBookmarkButtonProps) => { + if (tag.isFollower) { + return + } else { + return + } +} + +TagBookmarkButton.fragments = fragments diff --git a/src/components/Buttons/index.tsx b/src/components/Buttons/index.tsx index c0f06f11f2..025fd353f7 100644 --- a/src/components/Buttons/index.tsx +++ b/src/components/Buttons/index.tsx @@ -8,6 +8,7 @@ export * from './Share' export * from './Shuffle' export * from './SignUp' export * from './StartWriting' +export * from './TagBookmark' export * from './UniversalAuth' export * from './ViewAll' export * from './ViewMore' diff --git a/src/components/CollectionDigest/Feed/index.tsx b/src/components/CollectionDigest/Feed/index.tsx index 5fae3445f3..d9ecb28f49 100644 --- a/src/components/CollectionDigest/Feed/index.tsx +++ b/src/components/CollectionDigest/Feed/index.tsx @@ -87,8 +87,8 @@ const BaseCollectionDigestFeed = ({ , diff --git a/src/components/Context/Viewer/index.tsx b/src/components/Context/Viewer/index.tsx index 1108f0e46d..fcf44623b2 100644 --- a/src/components/Context/Viewer/index.tsx +++ b/src/components/Context/Viewer/index.tsx @@ -56,9 +56,6 @@ const ViewerFragments = { users(input: { first: 0 }) { totalCount } - tags(input: { first: 0 }) { - totalCount - } } followers(input: { first: 0 }) { totalCount diff --git a/src/components/Dialogs/EditTagDialog/Content.tsx b/src/components/Dialogs/EditTagDialog/Content.tsx deleted file mode 100644 index 4c6948bca3..0000000000 --- a/src/components/Dialogs/EditTagDialog/Content.tsx +++ /dev/null @@ -1,223 +0,0 @@ -import { useFormik } from 'formik' -import gql from 'graphql-tag' -import _pickBy from 'lodash/pickBy' -import { useState } from 'react' -import { FormattedMessage, useIntl } from 'react-intl' - -import IMAGE_TAG_COVER from '@/public/static/images/tag-cover.png' -import { - ASSET_TYPE, - ENTITY_TYPE, - MAX_TAG_CONTENT_LENGTH, - MAX_TAG_DESCRIPTION_LENGTH, -} from '~/common/enums' -import { - normalizeTag, - parseFormSubmitErrors, - validateTagName, -} from '~/common/utils' -import { CoverUploader, Dialog, Form, toast, useMutation } from '~/components' -import { PutTagMutation } from '~/gql/graphql' - -import styles from './styles.module.css' - -const PUT_TAG = gql` - mutation PutTag($input: PutTagInput!) { - putTag(input: $input) { - id - content - cover - description - } - } -` - -export interface EditTagDialogContentProps { - id: string - content?: string - cover?: string | null - description?: string | null -} - -type BaseEditTagDialogContentProps = { - closeDialog: () => void -} & EditTagDialogContentProps - -interface FormValues { - newContent: string - newCover?: string - newDescription: string -} - -const UNCHANGED_FIELD = 'UNCHANGED_FIELD' - -const EditTagDialogContent: React.FC = ({ - id, - content, - cover, - description, - closeDialog, -}) => { - const intl = useIntl() - const [update] = useMutation(PUT_TAG, undefined, { - showToast: false, - }) - const formId = 'put-tag-form' - - const { - values, - errors, - touched, - handleBlur, - handleChange, - handleSubmit, - isSubmitting, - setFieldValue, - } = useFormik({ - initialValues: { - newContent: content || '', - newCover: UNCHANGED_FIELD, - newDescription: description || '', - }, - validateOnBlur: false, - validateOnChange: false, - validate: ({ newContent }) => - _pickBy({ - newContent: validateTagName(newContent, intl), - }), - - onSubmit: async ( - { newContent, newCover, newDescription }, - { setFieldError, setSubmitting } - ) => { - try { - await update({ - variables: { - input: { - id, - content: newContent, - description: newDescription, - ...(newCover !== UNCHANGED_FIELD ? { cover: newCover } : {}), - }, - }, - }) - - toast.success({ - message: , - }) - - setSubmitting(false) - - closeDialog() - } catch (error) { - setSubmitting(false) - - const [messages, codes] = parseFormSubmitErrors(error as any) - setFieldError('newContent', intl.formatMessage(messages[codes[0]])) - } - }, - }) - - const [coverLoading, setCoverLoading] = useState(false) - const InnerForm = ( -
-
- setFieldValue('newCover', assetId)} - onUploadStart={() => setCoverLoading(true)} - onUploadEnd={() => setCoverLoading(false)} - onReset={() => setFieldValue('newCover', null)} - /> -
- - { - const newContent = normalizeTag(e.target.value) - setFieldValue('newContent', newContent) - return newContent - }} - maxLength={MAX_TAG_CONTENT_LENGTH} - hint={`${values.newContent.length}/${MAX_TAG_CONTENT_LENGTH}`} - error={touched.newContent && errors.newContent} - hintAlign={touched.newContent && errors.newContent ? 'left' : 'right'} - spacingTop="loose" - spacingBottom="base" - /> - - - - ) - - const SubmitButton = ( - } - type="submit" - form={formId} - disabled={isSubmitting || coverLoading} - loading={isSubmitting || coverLoading} - /> - ) - - return ( - <> - } - closeDialog={closeDialog} - rightBtn={SubmitButton} - hasSmUpTitle={false} - /> - - {InnerForm} - - - } - color="greyDarker" - onClick={closeDialog} - /> - {SubmitButton} - - } - /> - - ) -} - -export default EditTagDialogContent diff --git a/src/components/Dialogs/EditTagDialog/index.tsx b/src/components/Dialogs/EditTagDialog/index.tsx deleted file mode 100644 index 3b4cd59aa1..0000000000 --- a/src/components/Dialogs/EditTagDialog/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import dynamic from 'next/dynamic' - -import { Dialog, SpinnerBlock, useDialogSwitch } from '~/components' - -import { EditTagDialogContentProps } from './Content' - -export type EditTagDialogProps = EditTagDialogContentProps - -const DynamicContent = dynamic(() => import('./Content'), { - ssr: false, - loading: () => , -}) - -type BaseEditTagDialogProps = { - children: ({ openDialog }: { openDialog: () => void }) => React.ReactNode -} & EditTagDialogProps - -const BaseEditTagDialog = ({ - children, - content, - ...restProps -}: BaseEditTagDialogProps) => { - const { show, openDialog, closeDialog } = useDialogSwitch(true) - - return ( - <> - {children({ openDialog })} - - - - - - ) -} - -export const EditTagDialog = (props: BaseEditTagDialogProps) => ( - }> - {({ openDialog }) => <>{props.children({ openDialog })}} - -) diff --git a/src/components/Dialogs/EditTagDialog/styles.module.css b/src/components/Dialogs/EditTagDialog/styles.module.css deleted file mode 100644 index dfb72e5055..0000000000 --- a/src/components/Dialogs/EditTagDialog/styles.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.coverField { - margin: calc(var(--sp16) * -1) calc(var(--sp16) * -1) 0; - - @media (--sm-up) { - margin: 0 calc(var(--sp20) * -1); - } -} diff --git a/src/components/Dialogs/TagAdoptionDialog/index.tsx b/src/components/Dialogs/TagAdoptionDialog/index.tsx deleted file mode 100644 index dc08570408..0000000000 --- a/src/components/Dialogs/TagAdoptionDialog/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import { useContext } from 'react' -import { FormattedMessage } from 'react-intl' - -import { - Dialog, - LanguageContext, - toast, - useDialogSwitch, - useMutation, -} from '~/components' -import UPDATE_TAG_SETTING from '~/components/GQL/mutations/updateTagSetting' -import { UpdateTagSettingMutation } from '~/gql/graphql' - -interface Props { - id: string - children: ({ openDialog }: { openDialog: () => void }) => React.ReactNode -} - -const texts = { - zh_hans: - '当你认领标签后,即刻成为该标签的主理人。' + - '你将可以为标签设置封面,编辑描述,并添加作品至精选列表。' + - '你主理的标签可以用作文集、策展,也可以变成圈子、小组、讨论区等,更多主理人玩法等你发掘!', - zh_hant: - '當你認領標籤後,即刻成為該標籤的主理人。' + - '你將可以為標籤設置封面,編輯描述,並添加作品至精選列表。' + - '你主理的標籤可以用作文集、策展,也可以變成圈子、小組、討論區等,更多主理人玩法等你發掘!', - en: - 'After adopting the tag, you become the maintainer of it.' + - ' You can set the cover and description of the tag, and add works to selected feed. ' + - ' You can use it for writing collection, curation, or subcommunity and group discussions, be creative and discover new usages!', -} - -const BaseDialog = ({ id, children }: Props) => { - const { lang } = useContext(LanguageContext) - const { show, openDialog, closeDialog } = useDialogSwitch(true) - - const [update, { loading }] = - useMutation(UPDATE_TAG_SETTING) - - const onClick = async () => { - const result = await update({ - variables: { input: { id, type: 'adopt' } }, - }) - - if (!result) { - throw new Error('tag adoption failed') - } - - toast.success({ - message: , - }) - } - - return ( - <> - {children({ openDialog })} - - - } - /> - - - -

{texts[lang]}

-
-
- - - } - btns={ - - } - loading={loading} - onClick={onClick} - /> - } - smUpBtns={ - - } - loading={loading} - onClick={onClick} - /> - } - /> -
- - ) -} - -export const TagAdoptionDialog = (props: Props) => ( - }> - {({ openDialog }) => <>{props.children({ openDialog })}} - -) diff --git a/src/components/Dialogs/TagEditorDialog/List/index.tsx b/src/components/Dialogs/TagEditorDialog/List/index.tsx deleted file mode 100644 index 1aeef23f33..0000000000 --- a/src/components/Dialogs/TagEditorDialog/List/index.tsx +++ /dev/null @@ -1,200 +0,0 @@ -import { useQuery } from '@apollo/react-hooks' -import { FormattedMessage } from 'react-intl' - -import { - Button, - Dialog, - List, - QueryError, - Spacer, - SpinnerBlock, - TextIcon, - UserDigest, -} from '~/components' -import TAG_MAINTAINERS from '~/components/GQL/queries/tagMaintainers' -import { TagMaintainersQuery } from '~/gql/graphql' - -import styles from './styles.module.css' - -/** - * This a sub-component of . It shows editors of a tag, and - * user can start to add or remove editors in this. - * - * Usage: - * - * ```tsx - * {}} - * toAddStep={() => {}} - * toRemoveStep={() => {}} - * /> - * ``` - */ -type TagMaintainersNodeTagEditor = NonNullable< - NonNullable['editors'] ->[0] - -interface Props { - id: string - - closeDialog: () => void - toAddStep: () => void - toRemoveStep: (editor: TagMaintainersNodeTagEditor) => void -} - -const RemoveButton = ({ remove }: { remove: () => void }) => ( -
- -
-) - -const TagEditorList = ({ id, closeDialog, toAddStep, toRemoveStep }: Props) => { - const { data, loading, error } = useQuery( - TAG_MAINTAINERS, - { - variables: { id }, - } - ) - - if (loading) { - return - } - - if (error) { - return - } - - const tag = data?.node?.__typename === 'Tag' && data?.node - - if (!tag) { - return null - } - - const editors = tag.editors || [] - const count = editors.length - - const isAllowAdd = count < 4 - const isHavingEditors = count > 0 - const isHavingNoneEditors = count === 0 - const isReachingLimit = count === 4 - - const AddEditorButton = () => ( - } - onClick={toAddStep} - /> - ) - - return ( - <> - - } - closeDialog={closeDialog} - rightBtn={} - /> - - - - {tag.owner && ( - - - } - spacing={[12, 16]} - hasFollow={false} - /> - - )} - - {editors.map((editor) => ( - - - } - extraButton={ - toRemoveStep(editor)} /> - } - spacing={[12, 16]} - /> - - ))} - - - - - - -

- - - {(isHavingNoneEditors || isReachingLimit) && ( -

- 4 , - }} - /> -

- )} - - {isAllowAdd && isHavingEditors && ( -

- {4 - count} - ), - }} - /> -

- )} -

-
-
- - -
- - {isAllowAdd && ( - - } - color="greyDarker" - onClick={closeDialog} - /> - - - } - /> - )} - - ) -} - -export default TagEditorList diff --git a/src/components/Dialogs/TagEditorDialog/List/styles.module.css b/src/components/Dialogs/TagEditorDialog/List/styles.module.css deleted file mode 100644 index 2ff7f7c835..0000000000 --- a/src/components/Dialogs/TagEditorDialog/List/styles.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.count { - color: var(--color-matters-green); -} diff --git a/src/components/Dialogs/TagEditorDialog/Remove/index.tsx b/src/components/Dialogs/TagEditorDialog/Remove/index.tsx deleted file mode 100644 index 92c22df087..0000000000 --- a/src/components/Dialogs/TagEditorDialog/Remove/index.tsx +++ /dev/null @@ -1,127 +0,0 @@ -import { FormattedMessage } from 'react-intl' - -import { Dialog, toast, Translate, useMutation } from '~/components' -import { updateTagMaintainers } from '~/components/GQL' -import UPDATE_TAG_SETTING from '~/components/GQL/mutations/updateTagSetting' -import { TagMaintainersQuery, UpdateTagSettingMutation } from '~/gql/graphql' - -import styles from './styles.module.css' - -/** - * This a sub-component of . It ask user to confirm - * of removal of selected editor. - * - * Usage: - * - * ```tsx - * {}} - * /> - * ``` - */ - -type TagMaintainersNodeTagEditor = NonNullable< - NonNullable['editors'] ->[0] - -interface Props { - id: string - editor: TagMaintainersNodeTagEditor - - closeDialog: () => void -} - -const TagRemoveEditor = ({ id, editor, closeDialog }: Props) => { - const [update, { loading }] = - useMutation(UPDATE_TAG_SETTING) - - const onClick = async () => { - const result = await update({ - variables: { - input: { id, type: 'remove_editor', editors: [editor.id] }, - }, - update: (cache) => - updateTagMaintainers({ - cache, - id, - type: 'remove', - editors: [editor.id], - }), - }) - - if (!result) { - throw new Error('tag leave failed') - } - - toast.success({ - message: ( - - ), - }) - - closeDialog() - } - - return ( - <> - - } - /> - - - -

- {editor.displayName}, - }} - /> - -

-
-
- - - } - color={loading ? 'green' : 'red'} - onClick={onClick} - loading={loading} - /> - } - smUpBtns={ - - } - color={loading ? 'green' : 'red'} - onClick={onClick} - loading={loading} - /> - } - /> - - ) -} - -export default TagRemoveEditor diff --git a/src/components/Dialogs/TagEditorDialog/Remove/styles.module.css b/src/components/Dialogs/TagEditorDialog/Remove/styles.module.css deleted file mode 100644 index 275c1b0094..0000000000 --- a/src/components/Dialogs/TagEditorDialog/Remove/styles.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.name { - font-weight: var(--font-medium); - color: var(--color-black); -} diff --git a/src/components/Dialogs/TagEditorDialog/SearchSelect/index.tsx b/src/components/Dialogs/TagEditorDialog/SearchSelect/index.tsx deleted file mode 100644 index 28356301aa..0000000000 --- a/src/components/Dialogs/TagEditorDialog/SearchSelect/index.tsx +++ /dev/null @@ -1,151 +0,0 @@ -import _get from 'lodash/get' -import { useState } from 'react' -import { FormattedMessage } from 'react-intl' - -import { Dialog, toast, useMutation } from '~/components' -import { updateTagMaintainers } from '~/components/GQL' -import UPDATE_TAG_SETTING from '~/components/GQL/mutations/updateTagSetting' -import SearchingArea, { - SelectNode, -} from '~/components/SearchSelect/SearchingArea' -import StagingArea, { StagingNode } from '~/components/SearchSelect/StagingArea' -import { UpdateTagSettingMutation } from '~/gql/graphql' - -interface Props { - id: string - - closeDialog: () => void - toListStep: () => void -} - -type Area = 'staging' | 'searching' - -/** - * This is a sub-component of . It allows user to search and - * select nodes from search results, and then submit selected nodes. - * - * Usage: - * - * ```tsx - * {}} - * /> - * ``` - */ -const TagSearchSelectEditor = ({ id, closeDialog, toListStep }: Props) => { - const [update, { loading }] = - useMutation(UPDATE_TAG_SETTING) - - // area - const [area, setArea] = useState('staging') - const inStagingArea = area === 'staging' - const inSearchingArea = area === 'searching' - const toStagingArea = () => setArea('staging') - const toSearchingArea = () => setArea('searching') - - // data - const [stagingNodes, setStagingNodes] = useState([]) - const addNodeToStaging = (node: SelectNode) => { - const isExists = stagingNodes.some(({ node: n }) => n.id === node.id) - - if (!isExists) { - setStagingNodes([...stagingNodes, { node, selected: true }]) - } - - toStagingArea() - } - - const onClickSave = async () => { - const editors = stagingNodes.filter(({ selected }) => !!selected) - const result = await update({ - variables: { - input: { - id, - type: 'add_editor', - editors: editors.map(({ node }) => node.id), - }, - }, - update: (cache) => { - // filter out matty for local cache update - const filteredEditors = editors.filter( - ({ node }) => _get(node, 'displayName') !== 'Matty' - ) - updateTagMaintainers({ - cache, - id, - type: 'add', - editors: filteredEditors, - }) - }, - }) - - if (!result) { - return - } - - toast.success({ - message: ( - - ), - }) - - closeDialog() - } - - const SubmitButton = ( - } - loading={loading} - /> - ) - - return ( - <> - } - closeDialog={closeDialog} - rightBtn={SubmitButton} - /> - - - - - } - inStagingArea={inStagingArea} - draggable={false} - /> - - - - } - color="greyDarker" - onClick={closeDialog} - /> - {SubmitButton} - - } - /> - - ) -} - -export default TagSearchSelectEditor diff --git a/src/components/Dialogs/TagEditorDialog/index.tsx b/src/components/Dialogs/TagEditorDialog/index.tsx deleted file mode 100644 index 3bf2397047..0000000000 --- a/src/components/Dialogs/TagEditorDialog/index.tsx +++ /dev/null @@ -1,101 +0,0 @@ -import { useState } from 'react' - -import { - Dialog, - useDialogSwitch, // useRoute, - useStep, -} from '~/components' -import { TagMaintainersQuery } from '~/gql/graphql' - -import TagEditorList from './List' -import TagRemoveEditor from './Remove' -import TagSearchSelectEditor from './SearchSelect' - -/** - * TagEditorDialog is composed of three steps: list, add and remove. - * - * Usage: - * - * ```tsx - * - * {({ openDialog })=> ()} - * - * ``` - */ -type Step = 'list' | 'add' | 'remove' - -type TagMaintainersNodeTagEditor = NonNullable< - NonNullable['editors'] ->[0] - -export interface TagEditorDialogProps { - id: string - children: ({ openDialog }: { openDialog: () => void }) => React.ReactNode -} - -const BaseDialog = ({ id, children }: TagEditorDialogProps) => { - const defaultStep = 'list' - - const { - show, - openDialog: baseOpenDialog, - closeDialog, - } = useDialogSwitch(true) - const [removeEditor, setRemoveEditor] = - useState() - const { currStep, forward, reset } = useStep(defaultStep) - - const openDialog = () => { - if (currStep !== defaultStep) { - reset(defaultStep) - } - setRemoveEditor(undefined) - baseOpenDialog() - } - - const isAdd = currStep === 'add' - const isList = currStep === 'list' - const isRemove = currStep === 'remove' - - return ( - <> - {children({ openDialog })} - - - {isList && ( - forward('add')} - toRemoveStep={(editor: TagMaintainersNodeTagEditor) => { - setRemoveEditor(editor) - forward('remove') - }} - /> - )} - - {isAdd && ( - forward('list')} - /> - )} - - {isRemove && removeEditor && ( - - )} - - - ) -} - -export const TagEditorDialog = (props: TagEditorDialogProps) => ( - }> - {({ openDialog }) => <>{props.children({ openDialog })}} - -) diff --git a/src/components/Dialogs/TagLeaveDialog/index.tsx b/src/components/Dialogs/TagLeaveDialog/index.tsx deleted file mode 100644 index e6ade8dde0..0000000000 --- a/src/components/Dialogs/TagLeaveDialog/index.tsx +++ /dev/null @@ -1,105 +0,0 @@ -import { FormattedMessage } from 'react-intl' - -import { Dialog, toast, useDialogSwitch, useMutation } from '~/components' -import UPDATE_TAG_SETTING from '~/components/GQL/mutations/updateTagSetting' -import { UpdateTagSettingMutation } from '~/gql/graphql' - -export interface TagLeaveDialogProps { - id: string - isOwner?: boolean - children: ({ openDialog }: { openDialog: () => void }) => React.ReactNode -} - -const BaseDialog = ({ id, isOwner, children }: TagLeaveDialogProps) => { - const { show, openDialog, closeDialog } = useDialogSwitch(true) - - const [update, { loading }] = - useMutation(UPDATE_TAG_SETTING) - - const onClick = async () => { - const result = await update({ - variables: { - input: { id, type: isOwner ? 'leave' : 'leave_editor' }, - }, - }) - - if (!result) { - throw new Error('tag leave failed') - } - - toast.success({ - message: ( - - ), - }) - - closeDialog() - } - - return ( - <> - {children({ openDialog })} - - - - } - /> - - - -

- -

-

- -

-
-
- - - } - color={loading ? 'green' : 'red'} - onClick={onClick} - loading={loading} - /> - } - smUpBtns={ - - } - color={loading ? 'green' : 'red'} - onClick={onClick} - loading={loading} - /> - } - /> -
- - ) -} - -export const TagLeaveDialog = (props: TagLeaveDialogProps) => ( - }> - {({ openDialog }) => <>{props.children({ openDialog })}} - -) diff --git a/src/components/Dialogs/index.tsx b/src/components/Dialogs/index.tsx index 5884df31ad..629e2215c0 100644 --- a/src/components/Dialogs/index.tsx +++ b/src/components/Dialogs/index.tsx @@ -37,12 +37,6 @@ export * from './RemoveArticleCollectionDialog' // Editor export * from './EditorSearchSelectDialog' -// Tag -export * from './EditTagDialog' -export * from './TagAdoptionDialog' -export * from './TagEditorDialog' -export * from './TagLeaveDialog' - // Re-use export * from './SearchSelectDialog' diff --git a/src/components/Drawer/BaseDrawer.tsx b/src/components/Drawer/BaseDrawer.tsx index 3fa67c593a..47eda8c754 100644 --- a/src/components/Drawer/BaseDrawer.tsx +++ b/src/components/Drawer/BaseDrawer.tsx @@ -82,6 +82,7 @@ export const BaseDrawer = ({ const containerClasses = classNames({ [styles.baseDrawerContainer]: true, + open: isOpen, // for read timer to identify the state }) const ref = useRef(null) diff --git a/src/components/Empty/EmptyTagArticles.tsx b/src/components/Empty/EmptyTagArticles.tsx index f2e7274d6b..3c726d332f 100644 --- a/src/components/Empty/EmptyTagArticles.tsx +++ b/src/components/Empty/EmptyTagArticles.tsx @@ -1,9 +1,9 @@ -import { ReactComponent as IconWarn } from '@/public/static/icons/24px/warn.svg' +import { ReactComponent as IconEmptyFile } from '@/public/static/icons/empty-file.svg' import { Empty, Icon, Translate } from '~/components' export const EmptyTagArticles = () => ( } + icon={} description={ } diff --git a/src/components/Empty/EmptyTagBookmark.tsx b/src/components/Empty/EmptyTagBookmark.tsx new file mode 100644 index 0000000000..30c8930fdf --- /dev/null +++ b/src/components/Empty/EmptyTagBookmark.tsx @@ -0,0 +1,15 @@ +import { FormattedMessage } from 'react-intl' + +import { ReactComponent as IconSave } from '@/public/static/icons/24px/save.svg' +import { Empty, Icon } from '~/components' + +export const EmptyTagBookmark = () => ( + } + description={ + <> + + + } + /> +) diff --git a/src/components/Empty/index.tsx b/src/components/Empty/index.tsx index 5d1916b856..d684f0358b 100644 --- a/src/components/Empty/index.tsx +++ b/src/components/Empty/index.tsx @@ -13,6 +13,7 @@ export * from './EmptyResponse' export * from './EmptySearch' export * from './EmptyTag' export * from './EmptyTagArticles' +export * from './EmptyTagBookmark' export * from './EmptyTransaction' export * from './EmptyTransactionCurrency' export * from './EmptyTransactionSubscription' diff --git a/src/components/GQL/fragments/tag.ts b/src/components/GQL/fragments/tag.ts deleted file mode 100644 index 9134e91560..0000000000 --- a/src/components/GQL/fragments/tag.ts +++ /dev/null @@ -1,36 +0,0 @@ -import gql from 'graphql-tag' - -import { Avatar } from '~/components/Avatar' - -const fragments = { - followers: gql` - fragment FollowersTag on Tag { - id - followers(input: { first: 5 }) { - totalCount - edges { - cursor - node { - ... on User { - id - ...AvatarUser - } - } - } - } - } - ${Avatar.fragments.user} - `, - articleCount: gql` - fragment ArticleCountTag on Tag { - id - numAuthors - numArticles - articles(input: { first: 0, selected: false }) { - totalCount - } - } - `, -} - -export default fragments diff --git a/src/components/GQL/mutations/addArticlesTags.ts b/src/components/GQL/mutations/addArticlesTags.ts deleted file mode 100644 index cc7df5376b..0000000000 --- a/src/components/GQL/mutations/addArticlesTags.ts +++ /dev/null @@ -1,14 +0,0 @@ -import gql from 'graphql-tag' - -export default gql` - mutation AddArticlesTags($id: ID!, $articles: [ID!], $selected: Boolean) { - addArticlesTags( - input: { id: $id, articles: $articles, selected: $selected } - ) { - id - articles(input: { first: 0, selected: $selected }) { - totalCount - } - } - } -` diff --git a/src/components/GQL/mutations/changeEmail.ts b/src/components/GQL/mutations/changeEmail.ts deleted file mode 100644 index 778f403a7d..0000000000 --- a/src/components/GQL/mutations/changeEmail.ts +++ /dev/null @@ -1,12 +0,0 @@ -import gql from 'graphql-tag' - -export const CHANGE_EMAIL = gql` - mutation ChangeEmail($input: ChangeEmailInput!) { - changeEmail(input: $input) { - id - info { - email - } - } - } -` diff --git a/src/components/GQL/mutations/toggleBookmarkArticle.ts b/src/components/GQL/mutations/toggleBookmarkArticle.ts new file mode 100644 index 0000000000..dc98afe05a --- /dev/null +++ b/src/components/GQL/mutations/toggleBookmarkArticle.ts @@ -0,0 +1,10 @@ +import gql from 'graphql-tag' + +export default gql` + mutation ToggleBookmarkArticle($id: ID!, $enabled: Boolean) { + toggleBookmarkArticle(input: { id: $id, enabled: $enabled }) { + id + bookmarked + } + } +` diff --git a/src/components/GQL/mutations/toggleBookmarkTag.ts b/src/components/GQL/mutations/toggleBookmarkTag.ts new file mode 100644 index 0000000000..27f66a3a99 --- /dev/null +++ b/src/components/GQL/mutations/toggleBookmarkTag.ts @@ -0,0 +1,10 @@ +import gql from 'graphql-tag' + +export default gql` + mutation ToggleBookmarkTag($id: ID!, $enabled: Boolean) { + toggleBookmarkTag(input: { id: $id, enabled: $enabled }) { + id + isFollower + } + } +` diff --git a/src/components/GQL/mutations/toggleFollowTag.ts b/src/components/GQL/mutations/toggleFollowTag.ts deleted file mode 100644 index 9cf4224cae..0000000000 --- a/src/components/GQL/mutations/toggleFollowTag.ts +++ /dev/null @@ -1,10 +0,0 @@ -import gql from 'graphql-tag' - -export default gql` - mutation ToggleFollowTag($id: ID!, $enabled: Boolean) { - toggleFollowTag(input: { id: $id, enabled: $enabled }) { - id - isFollower - } - } -` diff --git a/src/components/GQL/mutations/toggleSubscribeArticle.ts b/src/components/GQL/mutations/toggleSubscribeArticle.ts deleted file mode 100644 index 9f0948275d..0000000000 --- a/src/components/GQL/mutations/toggleSubscribeArticle.ts +++ /dev/null @@ -1,10 +0,0 @@ -import gql from 'graphql-tag' - -export default gql` - mutation ToggleSubscribeArticle($id: ID!, $enabled: Boolean) { - toggleSubscribeArticle(input: { id: $id, enabled: $enabled }) { - id - subscribed - } - } -` diff --git a/src/components/GQL/mutations/updateTagSetting.ts b/src/components/GQL/mutations/updateTagSetting.ts deleted file mode 100644 index d26db45c0e..0000000000 --- a/src/components/GQL/mutations/updateTagSetting.ts +++ /dev/null @@ -1,29 +0,0 @@ -import gql from 'graphql-tag' - -import { Avatar } from '~/components/Avatar' - -import Tag from '../fragments/tag' - -export default gql` - mutation UpdateTagSetting($input: UpdateTagSettingInput!) { - updateTagSetting(input: $input) { - id - editors { - id - ...AvatarUser - } - owner { - id - userName - displayName - status { - state - } - ...AvatarUser - } - ...FollowersTag - } - } - ${Avatar.fragments.user} - ${Tag.followers} -` diff --git a/src/components/GQL/queries/tagArticles.ts b/src/components/GQL/queries/tagArticles.ts index baf1ff6125..c0a0f0fac6 100644 --- a/src/components/GQL/queries/tagArticles.ts +++ b/src/components/GQL/queries/tagArticles.ts @@ -6,20 +6,12 @@ export const TAG_ARTICLES_PUBLIC = gql` query TagArticlesPublic( $id: ID! $after: String - $selected: Boolean $sortBy: TagArticlesSortBy ) { node(input: { id: $id }) { ... on Tag { id - articles( - input: { - first: 20 - after: $after - selected: $selected - sortBy: $sortBy - } - ) { + articles(input: { first: 20, after: $after, sortBy: $sortBy }) { pageInfo { startCursor endCursor diff --git a/src/components/GQL/queries/tagArticlesCount.ts b/src/components/GQL/queries/tagArticlesCount.ts deleted file mode 100644 index 563061da10..0000000000 --- a/src/components/GQL/queries/tagArticlesCount.ts +++ /dev/null @@ -1,15 +0,0 @@ -import gql from 'graphql-tag' - -import tagFragments from '../fragments/tag' - -export default gql` - query TagArticlesCount($id: ID!) { - node(input: { id: $id }) { - ... on Tag { - id - ...ArticleCountTag - } - } - } - ${tagFragments.articleCount} -` diff --git a/src/components/GQL/queries/tagFollowers.ts b/src/components/GQL/queries/tagFollowers.ts deleted file mode 100644 index e1c384d248..0000000000 --- a/src/components/GQL/queries/tagFollowers.ts +++ /dev/null @@ -1,15 +0,0 @@ -import gql from 'graphql-tag' - -import tagFragments from '../fragments/tag' - -export default gql` - query TagFollowers($id: ID!) { - node(input: { id: $id }) { - ... on Tag { - id - ...FollowersTag - } - } - } - ${tagFragments.followers} -` diff --git a/src/components/GQL/queries/tagMaintainers.ts b/src/components/GQL/queries/tagMaintainers.ts deleted file mode 100644 index fe3c872020..0000000000 --- a/src/components/GQL/queries/tagMaintainers.ts +++ /dev/null @@ -1,23 +0,0 @@ -import gql from 'graphql-tag' - -import { UserDigest } from '~/components/UserDigest' - -export default gql` - query TagMaintainers($id: ID!) { - node(input: { id: $id }) { - ... on Tag { - id - owner { - id - ...UserDigestRichUserPublic - } - editors(input: { excludeAdmin: true, excludeOwner: true }) { - id - ...UserDigestRichUserPublic - } - __typename - } - } - } - ${UserDigest.Rich.fragments.user.public} -` diff --git a/src/components/GQL/queries/walletBalance.ts b/src/components/GQL/queries/walletBalance.ts index 292f0edad4..27f7827bc5 100644 --- a/src/components/GQL/queries/walletBalance.ts +++ b/src/components/GQL/queries/walletBalance.ts @@ -14,7 +14,6 @@ export default gql` } liker { total - rateUSD } } } diff --git a/src/components/GQL/updates/index.ts b/src/components/GQL/updates/index.ts index d3cd122567..4aa90f493c 100644 --- a/src/components/GQL/updates/index.ts +++ b/src/components/GQL/updates/index.ts @@ -6,9 +6,6 @@ export * from './circleFollowers' export * from './commentDetail' export * from './draftAssets' export * from './momentDetail' -export * from './tagArticlesCount' -export * from './tagFollowers' -export * from './tagMaintainers' export * from './userCollectionDetail' export * from './userCollections' export * from './userCollectionsArticles' @@ -18,7 +15,6 @@ export * from './userProfile' export * from './userWritings' export * from './viewerFolloweeCount' export * from './viewerFolloweeCount' -export * from './viewerFollowingTagCount' export * from './viewerUnreadFollowing' export * from './viewerUnreadNoticeCount' export * from './viewerWorksTabs' diff --git a/src/components/GQL/updates/tagArticlesCount.ts b/src/components/GQL/updates/tagArticlesCount.ts deleted file mode 100644 index 46382f9c23..0000000000 --- a/src/components/GQL/updates/tagArticlesCount.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { DataProxy } from 'apollo-cache' -import _cloneDeep from 'lodash/cloneDeep' - -import TAG_ARTICLES_COUNT from '~/components/GQL/queries/tagArticlesCount' -import { TagArticlesCountQuery } from '~/gql/graphql' - -export const updateTagArticlesCount = ({ - cache, - id, - count = 1, - type, -}: { - cache: DataProxy - id: string - count?: number - type: 'increment' | 'decrement' -}) => { - try { - if (!id) { - return - } - - const variables = { id } - const cacheData = cache.readQuery({ - query: TAG_ARTICLES_COUNT, - variables, - }) - - const data = _cloneDeep(cacheData) - if (data?.node?.__typename !== 'Tag') { - return - } - - if (type === 'increment') { - data.node.articles.totalCount += count - } else { - data.node.articles.totalCount -= count - } - - cache.writeQuery({ - query: TAG_ARTICLES_COUNT, - variables, - data, - }) - } catch (e) { - console.error(e) - } -} diff --git a/src/components/GQL/updates/tagFollowers.ts b/src/components/GQL/updates/tagFollowers.ts deleted file mode 100644 index 94bfb93025..0000000000 --- a/src/components/GQL/updates/tagFollowers.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { DataProxy } from 'apollo-cache' - -import TAG_FOLLOWERS from '~/components/GQL/queries/tagFollowers' -import { TagFollowersQuery } from '~/gql/graphql' - -export const updateTagFollowers = ({ - cache, - id, - type, - viewer, -}: { - cache: DataProxy - id: string - type: 'follow' | 'unfollow' - viewer: any -}) => { - try { - if (!id) { - return - } - - const variables = { id } - const cacheData = cache.readQuery({ - query: TAG_FOLLOWERS, - variables, - }) - - if (!cacheData || !cacheData.node || cacheData.node.__typename !== 'Tag') { - return - } - - const followers = cacheData.node.followers.edges || [] - if (type === 'follow') { - followers.unshift({ - cursor: window.btoa(`arrayconnection:${followers.length}:0`) || '', - node: { - avatar: viewer.avatar, - id: viewer.id, - liker: { - civicLiker: viewer.liker.civicLiker, - __typename: 'Liker', - }, - info: { - badges: viewer.info.badges, - __typename: 'UserInfo', - }, - __typename: 'User', - }, - __typename: 'UserEdge', - }) - cacheData.node.followers.edges = followers - cacheData.node.followers.totalCount++ - } else { - cacheData.node.followers.edges = followers.filter( - (follower) => follower.node.id !== viewer.id - ) - cacheData.node.followers.totalCount-- - } - - cache.writeQuery({ - query: TAG_FOLLOWERS, - variables, - data: cacheData, - }) - } catch (e) { - console.error(e) - } -} diff --git a/src/components/GQL/updates/tagMaintainers.ts b/src/components/GQL/updates/tagMaintainers.ts deleted file mode 100644 index e388690d52..0000000000 --- a/src/components/GQL/updates/tagMaintainers.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { DataProxy } from 'apollo-cache' -import _omit from 'lodash/omit' - -import TAG_MAINTAINERS from '~/components/GQL/queries/tagMaintainers' -import { TagMaintainersQuery } from '~/gql/graphql' - -type TagMaintainersNodeTagEditor = NonNullable< - NonNullable['editors'] ->[0] - -export const updateTagMaintainers = ({ - cache, - id, - type, - editors, -}: { - cache: DataProxy - id: string - type: 'add' | 'remove' - editors: any[] -}) => { - try { - if (!id) { - return - } - - const variables = { id } - const cacheData = cache.readQuery({ - query: TAG_MAINTAINERS, - variables, - }) - - if (!cacheData || !cacheData.node || cacheData.node.__typename !== 'Tag') { - return - } - - const currEditors = cacheData.node.editors || [] - - switch (type) { - case 'add': { - const newEditors = editors.map( - ({ node }) => _omit(node, ['selected']) as TagMaintainersNodeTagEditor - ) - cacheData.node.editors = [...currEditors, ...newEditors] - break - } - case 'remove': { - const newEditors = currEditors.filter( - (editor) => !editors.includes(editor.id) - ) - cacheData.node.editors = newEditors - break - } - } - - cache.writeQuery({ - query: TAG_MAINTAINERS, - variables, - data: cacheData, - }) - } catch (e) { - console.error(e) - } -} diff --git a/src/components/GQL/updates/viewerFollowingTagCount.ts b/src/components/GQL/updates/viewerFollowingTagCount.ts deleted file mode 100644 index 13851bfb78..0000000000 --- a/src/components/GQL/updates/viewerFollowingTagCount.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { DataProxy } from 'apollo-cache' -import gql from 'graphql-tag' - -import { ViewerFollowingTagCountQuery } from '~/gql/graphql' - -const VIEWER_FOLLOWING_TAG_COUNT = gql` - query ViewerFollowingTagCount { - viewer { - id - following { - tags(input: { first: 0 }) { - totalCount - } - } - } - } -` - -export const updateViewerFollowingTagCount = ({ - cache, - type, -}: { - cache: DataProxy - type: 'increment' | 'decrement' -}) => { - try { - const cacheData = cache.readQuery({ - query: VIEWER_FOLLOWING_TAG_COUNT, - }) - - if (!cacheData || !cacheData.viewer) { - return - } - - if (type === 'increment') { - cacheData.viewer.following.tags.totalCount++ - } else { - cacheData.viewer.following.tags.totalCount-- - } - - cache.writeQuery({ - query: VIEWER_FOLLOWING_TAG_COUNT, - data: cacheData, - }) - } catch (e) { - console.error(e) - } -} diff --git a/src/components/Hook/index.ts b/src/components/Hook/index.ts index 828ad28fb8..0c40be308d 100644 --- a/src/components/Hook/index.ts +++ b/src/components/Hook/index.ts @@ -14,6 +14,7 @@ export * from './useJumpToComment' export * from './useMediaQuery' export * from './useNativeEventListener' export * from './useOutsideClick' +export * from './useReadTimer' export * from './useRoute' export * from './useStep' export * from './useTargetNetwork' diff --git a/src/components/Hook/useReadTimer.ts b/src/components/Hook/useReadTimer.ts new file mode 100644 index 0000000000..67cfd0389a --- /dev/null +++ b/src/components/Hook/useReadTimer.ts @@ -0,0 +1,104 @@ +import _throttle from 'lodash/throttle' +import { useRouter } from 'next/router' +import { useEffect, useRef } from 'react' + +import { analytics } from '~/common/utils' + +type Props = { + articleId: string + container?: React.RefObject +} + +export const useReadTimer = ({ articleId, container }: Props) => { + const router = useRouter() + + //in ms + const interval = 5000 + + const dummy = useRef(0) + const readTimer = useRef(0) + const lastScroll = useRef(Date.now() / 1000) + + useEffect(() => { + const handleScroll = _throttle(() => { + lastScroll.current = Date.now() / 1000 + }, 3000) + + const storeReadTime = () => { + if (articleId && readTimer?.current) + analytics.trackEvent('read_time', { + articleId, + time: readTimer.current, + }) + } + + window.addEventListener('scroll', handleScroll) + window.addEventListener('beforeunload', storeReadTime) + router.events.on('routeChangeStart', storeReadTime) + + return () => { + window.removeEventListener('scroll', handleScroll) + window.removeEventListener('beforeunload', storeReadTime) + router.events.off('routeChangeStart', storeReadTime) + } + }, []) + + // reading timer + useEffect(() => { + const timerId = setInterval( + (function heartbeat() { + const isReading = () => { + // tab hidden + if (document.hidden) { + return false + } + + // content not rendered + if (!container || !container.current) { + return false + } + + // idle for more than 3 minutes + if (Date.now() / 1000 - lastScroll.current > 60 * 3) { + return false + } + + // if overlay is shown + const overlaySelectors = ['reach-portal', '.tippy-popper'] + if (document.querySelector(overlaySelectors.join(','))) { + return false + } + + // if drawer is opened + if (document.querySelector('[id^="Drawer__"].open')) { + return false + } + + // if bottom is above center + const { bottom } = ( + container.current as unknown as Element + ).getBoundingClientRect() + + const isBottom = bottom <= window.innerHeight * 0.8 + return !isBottom + } + + // don't count the first time + if (dummy.current === 0) { + dummy.current = 1 + return heartbeat + } + + if (isReading()) { + readTimer.current = readTimer.current + interval + } + return heartbeat + })(), + interval + ) + + return () => { + clearInterval(timerId) + } + }, []) +} diff --git a/src/components/Icon/styles.module.css b/src/components/Icon/styles.module.css index 062f930480..6d6be1101f 100644 --- a/src/components/Icon/styles.module.css +++ b/src/components/Icon/styles.module.css @@ -42,6 +42,11 @@ height: 1.5rem; } + &.size28 { + width: 1.75rem; + height: 1.75rem; + } + &.size32 { width: 2rem; height: 2rem; diff --git a/src/components/Icon/withIcon.tsx b/src/components/Icon/withIcon.tsx index 03b8c68214..162fe85212 100644 --- a/src/components/Icon/withIcon.tsx +++ b/src/components/Icon/withIcon.tsx @@ -11,6 +11,7 @@ export type IconSize = | 20 | 22 | 24 + | 28 | 32 | 40 | 48 diff --git a/src/components/Layout/Header/MeButton/SideDrawerNav/DrawerContent/MeMenu/index.tsx b/src/components/Layout/Header/MeButton/SideDrawerNav/DrawerContent/MeMenu/index.tsx index e11ae774b4..f4f2ac2c6a 100644 --- a/src/components/Layout/Header/MeButton/SideDrawerNav/DrawerContent/MeMenu/index.tsx +++ b/src/components/Layout/Header/MeButton/SideDrawerNav/DrawerContent/MeMenu/index.tsx @@ -61,7 +61,7 @@ const Top: React.FC = () => { {...menuItemProps} text={} icon={} - href={PATHS.ME_BOOKMARKS} + href={PATHS.ME_BOOKMARKS_ARTICLES} is="link" /> diff --git a/src/components/Layout/SideNav/MeMenu.tsx b/src/components/Layout/SideNav/MeMenu.tsx index 66907f2b16..f13390a273 100644 --- a/src/components/Layout/SideNav/MeMenu.tsx +++ b/src/components/Layout/SideNav/MeMenu.tsx @@ -73,7 +73,7 @@ const MeMenu: React.FC = () => { } icon={} - href={PATHS.ME_BOOKMARKS} + href={PATHS.ME_BOOKMARKS_ARTICLES} is="link" /> diff --git a/src/components/Slides/index.tsx b/src/components/Slides/index.tsx index 541cafc620..e89084fe0f 100644 --- a/src/components/Slides/index.tsx +++ b/src/components/Slides/index.tsx @@ -12,7 +12,7 @@ interface SlidesProps { } interface SlideItemProps { - size?: 'sm' | 'md' + size?: 'xs' | 'sm' | 'md' onClick?: () => any } diff --git a/src/components/Slides/styles.module.css b/src/components/Slides/styles.module.css index d94027868e..e0797c3639 100644 --- a/src/components/Slides/styles.module.css +++ b/src/components/Slides/styles.module.css @@ -48,6 +48,10 @@ background: var(--color-grey-lighter); } +.sizeXs { + width: 15rem; +} + .sizeSm { width: 18rem; } diff --git a/src/components/Tag/ArticleTag/index.tsx b/src/components/Tag/ArticleTag/index.tsx index 4c4e7d95ce..d41a1342f0 100644 --- a/src/components/Tag/ArticleTag/index.tsx +++ b/src/components/Tag/ArticleTag/index.tsx @@ -59,7 +59,6 @@ ArticleTag.fragments = { id content numArticles - numAuthors } `, } diff --git a/src/components/Tag/InlineTag/index.tsx b/src/components/Tag/InlineTag/index.tsx index 8808fd9556..4137d574e6 100644 --- a/src/components/Tag/InlineTag/index.tsx +++ b/src/components/Tag/InlineTag/index.tsx @@ -75,7 +75,6 @@ InlineTag.fragments = { id content numArticles - numAuthors } `, } diff --git a/src/components/Tag/InlineTag/styles.module.css b/src/components/Tag/InlineTag/styles.module.css index 3ff6789424..b6b64f164e 100644 --- a/src/components/Tag/InlineTag/styles.module.css +++ b/src/components/Tag/InlineTag/styles.module.css @@ -15,9 +15,8 @@ & .name { @mixin line-clamp; - @mixin fix-cropped-letters; - line-height: inherit; + line-height: 1.01; color: var(--color-black); } diff --git a/src/components/Tag/ListTag/index.tsx b/src/components/Tag/ListTag/index.tsx index 1fcacdfcdb..1f59a29742 100644 --- a/src/components/Tag/ListTag/index.tsx +++ b/src/components/Tag/ListTag/index.tsx @@ -81,7 +81,6 @@ ListTag.fragments = { id content numArticles - numAuthors } `, } diff --git a/src/components/Tag/PlainTag/index.tsx b/src/components/Tag/PlainTag/index.tsx index 0dc778eb1a..aa1ad9763b 100644 --- a/src/components/Tag/PlainTag/index.tsx +++ b/src/components/Tag/PlainTag/index.tsx @@ -52,7 +52,6 @@ PlainTag.fragments = { id content numArticles - numAuthors } `, } diff --git a/src/components/TagDigest/Bookmark/index.tsx b/src/components/TagDigest/Bookmark/index.tsx new file mode 100644 index 0000000000..8f9568666c --- /dev/null +++ b/src/components/TagDigest/Bookmark/index.tsx @@ -0,0 +1,52 @@ +import gql from 'graphql-tag' +import Link from 'next/link' + +import { TEST_ID } from '~/common/enums' +import { toPath } from '~/common/utils' +import { TagBookmarkButton } from '~/components/Buttons/TagBookmark' +import { TagDigestBookmarkTagFragment } from '~/gql/graphql' + +import styles from './styles.module.css' + +export type TagDigestBookmarkProps = { + tag: TagDigestBookmarkTagFragment + onClick?: () => void +} + +const fragments = { + tag: gql` + fragment TagDigestBookmarkTag on Tag { + id + content + ...TagBookmarkButtonTagPrivate + } + ${TagBookmarkButton.fragments.tag.private} + `, +} + +const Bookmark = ({ tag, onClick }: TagDigestBookmarkProps) => { + const path = toPath({ + page: 'tagDetail', + tag, + }) + + return ( +
+ + + {tag.content} + + +
+ +
+
+ ) +} + +Bookmark.fragments = fragments + +export default Bookmark diff --git a/src/components/TagDigest/Bookmark/styles.module.css b/src/components/TagDigest/Bookmark/styles.module.css new file mode 100644 index 0000000000..6c966321a5 --- /dev/null +++ b/src/components/TagDigest/Bookmark/styles.module.css @@ -0,0 +1,16 @@ +.container { + @mixin flex-center-space-between; + + padding: var(--sp16) 0; + + & .tag { + @mixin line-clamp; + + flex-grow: 1; + line-height: 1.5rem; + + &:hover { + color: var(--color-matters-green); + } + } +} diff --git a/src/components/TagDigest/Buttons/FollowButton/Follow.tsx b/src/components/TagDigest/Buttons/FollowButton/Follow.tsx index 90bec0163c..0e1203f461 100644 --- a/src/components/TagDigest/Buttons/FollowButton/Follow.tsx +++ b/src/components/TagDigest/Buttons/FollowButton/Follow.tsx @@ -7,11 +7,10 @@ import { UNIVERSAL_AUTH_TRIGGER, } from '~/common/enums' import { Button, TextIcon, useMutation, ViewerContext } from '~/components' -import { updateViewerFollowingTagCount } from '~/components/GQL' -import TOGGLE_FOLLOW_TAG from '~/components/GQL/mutations/toggleFollowTag' +import TOGGLE_BOOKMARK_TAG from '~/components/GQL/mutations/toggleBookmarkTag' import { TagDigestFollowButtonPrivateFragment, - ToggleFollowTagMutation, + ToggleBookmarkTagMutation, } from '~/gql/graphql' interface Props { @@ -21,21 +20,18 @@ interface Props { const Follow = ({ tag }: Props) => { const viewer = useContext(ViewerContext) - const [follow] = useMutation(TOGGLE_FOLLOW_TAG, { + const [follow] = useMutation(TOGGLE_BOOKMARK_TAG, { variables: { id: tag.id, enabled: true }, optimisticResponse: !_isNil(tag.id) && !_isNil(tag.isFollower) ? { - toggleFollowTag: { + toggleBookmarkTag: { id: tag.id, isFollower: true, __typename: 'Tag', }, } : undefined, - update: (cache) => { - updateViewerFollowingTagCount({ cache, type: 'increment' }) - }, }) const onClick = () => { diff --git a/src/components/TagDigest/Buttons/FollowButton/Unfollow.tsx b/src/components/TagDigest/Buttons/FollowButton/Unfollow.tsx index b83fc1b095..41dc85a341 100644 --- a/src/components/TagDigest/Buttons/FollowButton/Unfollow.tsx +++ b/src/components/TagDigest/Buttons/FollowButton/Unfollow.tsx @@ -3,11 +3,10 @@ import { useState } from 'react' import { FormattedMessage } from 'react-intl' import { Button, TextIcon, useMutation } from '~/components' -import { updateViewerFollowingTagCount } from '~/components/GQL' -import TOGGLE_FOLLOW_TAG from '~/components/GQL/mutations/toggleFollowTag' +import TOGGLE_BOOKMARK_TAG from '~/components/GQL/mutations/toggleBookmarkTag' import { TagDigestFollowButtonPrivateFragment, - ToggleFollowTagMutation, + ToggleBookmarkTagMutation, } from '~/gql/graphql' interface UnfollowTagProps { @@ -16,22 +15,22 @@ interface UnfollowTagProps { const Unfollow = ({ tag }: UnfollowTagProps) => { const [hover, setHover] = useState(false) - const [unfollow] = useMutation(TOGGLE_FOLLOW_TAG, { - variables: { id: tag.id, enabled: false }, - optimisticResponse: - !_isNil(tag.id) && !_isNil(tag.isFollower) - ? { - toggleFollowTag: { - id: tag.id, - isFollower: false, - __typename: 'Tag', - }, - } - : undefined, - update: (cache) => { - updateViewerFollowingTagCount({ cache, type: 'decrement' }) - }, - }) + const [unfollow] = useMutation( + TOGGLE_BOOKMARK_TAG, + { + variables: { id: tag.id, enabled: false }, + optimisticResponse: + !_isNil(tag.id) && !_isNil(tag.isFollower) + ? { + toggleBookmarkTag: { + id: tag.id, + isFollower: false, + __typename: 'Tag', + }, + } + : undefined, + } + ) return ( - ) -} - -export default Follow diff --git a/src/views/TagDetail/Buttons/FollowButton/Unfollow.tsx b/src/views/TagDetail/Buttons/FollowButton/Unfollow.tsx deleted file mode 100644 index 27f84791f1..0000000000 --- a/src/views/TagDetail/Buttons/FollowButton/Unfollow.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import _isNil from 'lodash/isNil' -import { useContext, useState } from 'react' -import { FormattedMessage } from 'react-intl' - -import { Button, TextIcon, useMutation, ViewerContext } from '~/components' -import { updateTagFollowers } from '~/components/GQL' -import TOGGLE_FOLLOW_TAG from '~/components/GQL/mutations/toggleFollowTag' -import { - FollowButtonTagPrivateFragment, - ToggleFollowTagMutation, -} from '~/gql/graphql' - -interface UnfollowTagProps { - tag: FollowButtonTagPrivateFragment -} - -const Unfollow = ({ tag }: UnfollowTagProps) => { - const viewer = useContext(ViewerContext) - const [hover, setHover] = useState(false) - const [unfollow] = useMutation(TOGGLE_FOLLOW_TAG, { - variables: { id: tag.id, enabled: false }, - optimisticResponse: - !_isNil(tag.id) && !_isNil(tag.isFollower) - ? { - toggleFollowTag: { - id: tag.id, - isFollower: false, - __typename: 'Tag', - }, - } - : undefined, - update: (cache) => { - updateTagFollowers({ - cache, - type: 'unfollow', - id: tag.id, - viewer, - }) - }, - }) - - return ( - - ) -} - -export default Unfollow diff --git a/src/views/TagDetail/Buttons/FollowButton/index.tsx b/src/views/TagDetail/Buttons/FollowButton/index.tsx deleted file mode 100644 index 3a581b255b..0000000000 --- a/src/views/TagDetail/Buttons/FollowButton/index.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import gql from 'graphql-tag' - -import { FollowButtonTagPrivateFragment } from '~/gql/graphql' - -import Follow from './Follow' -import Unfollow from './Unfollow' - -interface FollowButtonProps { - tag: FollowButtonTagPrivateFragment -} - -const fragments = { - tag: { - private: gql` - fragment FollowButtonTagPrivate on Tag { - id - isFollower - } - `, - }, -} - -const FollowButton = ({ tag }: FollowButtonProps) => { - if (tag.isFollower) { - return - } else { - return - } -} - -FollowButton.fragments = fragments - -export default FollowButton diff --git a/src/views/TagDetail/Buttons/index.tsx b/src/views/TagDetail/Buttons/index.tsx deleted file mode 100644 index cd045c6a17..0000000000 --- a/src/views/TagDetail/Buttons/index.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import FollowButton from './FollowButton' - -export const TagDetailButtons = { - FollowButton, -} diff --git a/src/views/TagDetail/Community/Maintainers/index.tsx b/src/views/TagDetail/Community/Maintainers/index.tsx deleted file mode 100644 index ce39b0c1b3..0000000000 --- a/src/views/TagDetail/Community/Maintainers/index.tsx +++ /dev/null @@ -1,125 +0,0 @@ -import { useQuery } from '@apollo/react-hooks' -import { FormattedMessage } from 'react-intl' - -import { ReactComponent as IconSettings } from '@/public/static/icons/24px/settings.svg' -import { - Button, - Icon, - QueryError, - SpinnerBlock, - TagEditorDialog, - TextIcon, - UserDigest, -} from '~/components' -import TAG_MAINTAINERS from '~/components/GQL/queries/tagMaintainers' -import { TagMaintainersQuery } from '~/gql/graphql' - -import styles from '../styles.module.css' - -interface Props { - id: string - isOwner?: boolean -} - -const ManageButton = ({ id }: Props) => { - return ( - - {({ openDialog }) => ( - - )} - - ) -} - -const Maintainers = ({ id, isOwner }: Props) => { - const { data, loading, error } = useQuery( - TAG_MAINTAINERS, - { - variables: { id }, - notifyOnNetworkStatusChange: true, - } - ) - - if (loading) { - return - } - - if (error) { - return - } - - if (data?.node?.__typename !== 'Tag') { - return null - } - - const tag = data.node - const editors = tag.editors || [] - - const isHavingEditors = editors.length > 0 - - return ( - <> - {tag.owner && ( - <> -
-
- -
- {isOwner && ( -
- -
- )} -
-
- -
- - )} - - {isHavingEditors && ( - <> -
-
- - ({editors.length}) -
-
-
    - {editors.map((editor) => ( -
  • - -
  • - ))} -
- - )} - - ) -} - -export default Maintainers diff --git a/src/views/TagDetail/Community/Participants/gql.ts b/src/views/TagDetail/Community/Participants/gql.ts deleted file mode 100644 index 59119e0e9c..0000000000 --- a/src/views/TagDetail/Community/Participants/gql.ts +++ /dev/null @@ -1,29 +0,0 @@ -import gql from 'graphql-tag' - -import { UserDigest } from '~/components/UserDigest' - -export default gql` - query TagParticipants($id: ID!, $after: String) { - node(input: { id: $id }) { - ... on Tag { - id - participants(input: { first: 10, after: $after }) { - totalCount - pageInfo { - startCursor - endCursor - hasNextPage - } - edges { - cursor - node { - ...UserDigestRichUserPublic - } - } - } - __typename - } - } - } - ${UserDigest.Rich.fragments.user.public} -` diff --git a/src/views/TagDetail/Community/Participants/index.tsx b/src/views/TagDetail/Community/Participants/index.tsx deleted file mode 100644 index 3d4309f99a..0000000000 --- a/src/views/TagDetail/Community/Participants/index.tsx +++ /dev/null @@ -1,110 +0,0 @@ -import { NetworkStatus } from 'apollo-client' -import { FormattedMessage } from 'react-intl' - -import { analytics, mergeConnections } from '~/common/utils' -import { - InfiniteScroll, - List, - QueryError, - SpinnerBlock, - usePublicQuery, - UserDigest, -} from '~/components' -import { TagParticipantsQuery } from '~/gql/graphql' - -import styles from '../styles.module.css' -import TAG_PARTICIPANTS from './gql' - -interface Props { - id: string -} - -const Participants = ({ id }: Props) => { - const { data, loading, error, fetchMore, networkStatus } = - usePublicQuery(TAG_PARTICIPANTS, { - variables: { id }, - notifyOnNetworkStatusChange: true, - }) - - // pagination - const connectionPath = 'node.participants' - const { totalCount, edges, pageInfo } = - (data?.node?.__typename === 'Tag' && - data.node.participants && - data.node.participants) || - {} - const isNewLoading = - [NetworkStatus.loading, NetworkStatus.setVariables].indexOf( - networkStatus - ) >= 0 - - // load next page - const loadMore = async () => { - analytics.trackEvent('load_more', { - type: 'tag_detail_community', - location: edges?.length || 0, - }) - - await fetchMore({ - variables: { after: pageInfo?.endCursor }, - updateQuery: (previousResult, { fetchMoreResult }) => - mergeConnections({ - oldData: previousResult, - newData: fetchMoreResult, - path: connectionPath, - }), - }) - } - - if (loading && (!edges || isNewLoading)) { - return - } - - if (error) { - return - } - - if (!edges || edges.length <= 0 || !pageInfo) { - return null - } - - const count = totalCount || 0 - if (count === 0) { - return null - } - - return ( - <> -
-
- - ({count}) -
-
- - - - {(edges || []).map(({ node, cursor }, i) => ( - - - analytics.trackEvent('click_feed', { - type: 'tag_detail_community', - contentType: 'user', - location: i, - id: node.id, - }) - } - /> - - ))} - - - - ) -} - -export default Participants diff --git a/src/views/TagDetail/Community/index.tsx b/src/views/TagDetail/Community/index.tsx deleted file mode 100644 index 17bfa212e1..0000000000 --- a/src/views/TagDetail/Community/index.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import { Layout } from '~/components' - -import Maintainers from './Maintainers' -import Participants from './Participants' - -interface Props { - id: string - - isOwner: boolean -} - -const Community = ({ id, isOwner }: Props) => { - return ( - - - - - ) -} - -export default Community diff --git a/src/views/TagDetail/Community/styles.module.css b/src/views/TagDetail/Community/styles.module.css deleted file mode 100644 index 7056e1ba8a..0000000000 --- a/src/views/TagDetail/Community/styles.module.css +++ /dev/null @@ -1,12 +0,0 @@ -.category { - @mixin flex-center-space-between; - - padding: var(--sp8) 0; - font-size: var(--text15); - font-weight: var(--font-medium); -} - -.count { - margin-left: var(--sp8); - color: var(--color-grey-dark); -} diff --git a/src/views/TagDetail/Cover/index.tsx b/src/views/TagDetail/Cover/index.tsx deleted file mode 100644 index 7ac82e91d0..0000000000 --- a/src/views/TagDetail/Cover/index.tsx +++ /dev/null @@ -1,64 +0,0 @@ -import classNames from 'classnames' -import gql from 'graphql-tag' - -import { ReactComponent as IconHashTag } from '@/public/static/icons/24px/hashtag.svg' -import IMAGE_TAG_COVER from '@/public/static/images/tag-cover.png' -import { Cover } from '~/components' -import { Icon, TextIcon } from '~/components' -import { CoverTagFragment } from '~/gql/graphql' - -import styles from './styles.module.css' - -const TagCover = ({ tag }: { tag: CoverTagFragment }) => { - const titleClasses = classNames({ - [styles.title]: true, - [styles.mask]: !!tag.cover, - }) - - return ( - -
-
- - } - placement="right" - allowUserSelect - > - {tag.content} - - -
-
-
- ) -} - -TagCover.fragments = { - tag: gql` - fragment CoverTag on Tag { - id - cover - content - numArticles - numAuthors - } - fragment DigestTag on Tag { - id - content - numArticles - numAuthors - } - `, -} - -export default TagCover diff --git a/src/views/TagDetail/Cover/styles.module.css b/src/views/TagDetail/Cover/styles.module.css deleted file mode 100644 index 1adddde5ad..0000000000 --- a/src/views/TagDetail/Cover/styles.module.css +++ /dev/null @@ -1,51 +0,0 @@ -.cover { - position: relative; - - & img { - @mixin object-fit-cover; - - background-color: var(--color-matters-green); - } - - &::after { - display: block; - padding-bottom: 46.93%; - content: ''; - - @media (--sm-up) { - padding-bottom: 30.14%; - } - } -} - -.title { - @mixin expand-to-container; - - & .content { - position: absolute; - right: var(--sp16); - bottom: var(--sp24); - left: var(--sp16); - line-height: 1; - } - - &.mask { - background: rgb(0 0 0 / 35%); - } -} - -.tag { - & .name { - @mixin line-clamp; - @mixin fix-cropped-letters; - - line-height: inherit; - } - - display: inline-flex; - line-height: 1.5rem; - - & svg { - margin-right: var(--sp2); - } -} diff --git a/src/views/TagDetail/DropdownActions/index.tsx b/src/views/TagDetail/DropdownActions/index.tsx deleted file mode 100644 index 802faa7224..0000000000 --- a/src/views/TagDetail/DropdownActions/index.tsx +++ /dev/null @@ -1,278 +0,0 @@ -import _isEmpty from 'lodash/isEmpty' -import _pickBy from 'lodash/pickBy' -import { useContext } from 'react' -import { FormattedMessage, useIntl } from 'react-intl' - -import { ReactComponent as IconCircleMinus } from '@/public/static/icons/24px/circle-minus.svg' -import { ReactComponent as IconCirclePlus } from '@/public/static/icons/24px/circle-plus.svg' -import { ReactComponent as IconEdit } from '@/public/static/icons/24px/edit.svg' -import { ReactComponent as IconProfile } from '@/public/static/icons/24px/profile.svg' -import { ReactComponent as IconSettings } from '@/public/static/icons/24px/settings.svg' -import { REFETCH_TAG_DETAIL_ARTICLES } from '~/common/enums' -import { - Button, - Dropdown, - EditTagDialog, - EditTagDialogProps, - Icon, - Menu, - TagEditorDialog, - TagEditorDialogProps, - TagLeaveDialog, - TagLeaveDialogProps, - toast, - useMutation, - ViewerContext, - withDialog, -} from '~/components' -import { - SearchSelectDialog, - SearchSelectDialogProps, -} from '~/components/Dialogs/SearchSelectDialog' -import { SearchSelectNode } from '~/components/Forms/SearchSelectForm' -import { updateTagArticlesCount } from '~/components/GQL' -import ADD_ARTICLES_TAGS from '~/components/GQL/mutations/addArticlesTags' -import { AddArticlesTagsMutation, TagFragmentFragment } from '~/gql/graphql' -interface DropdownActionsProps { - // id: string - isOwner: boolean - isEditor: boolean - isMaintainer: boolean - tag: TagFragmentFragment -} - -interface DialogProps { - openTagAddSelectedArticlesDialog: () => void - openEditTagDialog: () => void - openTagEditorDialog: () => void - openTagLeaveDialog: () => void -} - -interface Controls { - hasEditTag: boolean - hasAddSelectedArticle: boolean - hasManageCommunity: boolean - hasTagLeave: boolean -} - -type BaseDropdownActionsProps = DropdownActionsProps & DialogProps & Controls - -const BaseDropdownActions = ({ - hasEditTag, - hasAddSelectedArticle, - hasManageCommunity, - hasTagLeave, - - openTagAddSelectedArticlesDialog, - openEditTagDialog, - openTagEditorDialog, - openTagLeaveDialog, -}: BaseDropdownActionsProps) => { - const intl = useIntl() - const Content = () => ( - - {hasEditTag && ( - } - icon={} - onClick={openEditTagDialog} - ariaHasPopup="dialog" - /> - )} - {hasAddSelectedArticle && ( - - } - icon={} - onClick={openTagAddSelectedArticlesDialog} - ariaHasPopup="dialog" - /> - )} - {hasManageCommunity && ( - - } - icon={} - onClick={openTagEditorDialog} - ariaHasPopup="dialog" - /> - )} - {hasTagLeave && ( - - } - icon={} - onClick={openTagLeaveDialog} - ariaHasPopup="dialog" - /> - )} - - ) - - return ( - }> - {({ openDropdown, ref }) => ( - - )} - - ) -} - -const DropdownActions = (props: DropdownActionsProps) => { - const viewer = useContext(ViewerContext) - const { tag } = props - - const intl = useIntl() - /** - * Data - */ - const [add, { loading }] = - useMutation(ADD_ARTICLES_TAGS) - const addArticlesToTag = - (selected: boolean) => async (articles: SearchSelectNode[]) => { - const articleIds = articles.map((article) => article.id) - - await add({ - variables: { id: tag.id, articles: articleIds, selected }, - update: (cache, { data }) => { - if (selected) { - const newCount = data?.addArticlesTags?.articles?.totalCount || 0 - const oldCount = tag.articles.totalCount || 0 - updateTagArticlesCount({ - cache, - id: tag.id, - count: newCount - oldCount, - type: 'increment', - }) - } - }, - }) - - toast.success({ - message: intl.formatMessage({ - defaultMessage: 'Tags added', - id: 'UjKkhq', - description: 'src/views/TagDetail/DropdownActions/index.tsx', - }), - }) - - window.dispatchEvent( - new CustomEvent(REFETCH_TAG_DETAIL_ARTICLES, { - detail: { - event: 'add', - differences: articles.length, - }, - }) - ) - } - - const forbid = () => { - toast.error({ - message: ( - - ), - }) - return - } - - const controls = { - hasEditTag: props.isOwner, - hasAddSelectedArticle: props.isMaintainer, - hasManageCommunity: props.isOwner, - hasTagLeave: props.isOwner || props.isEditor, - } - - if (_isEmpty(_pickBy(controls))) { - return null - } - - const WithEditTag = withDialog>( - BaseDropdownActions, - EditTagDialog, - { ...props.tag }, - ({ openDialog }) => { - return { - ...props, - ...controls, - openEditTagDialog: viewer.isFrozen ? forbid : openDialog, - } - } - ) - const WithSearchSelect = withDialog< - Omit - >( - WithEditTag, - SearchSelectDialog, - { - title: ( - - ), - hint: ( - - ), - searchType: 'Article', - onSave: addArticlesToTag(true), - saving: loading, - }, - ({ openDialog }) => ({ - openTagAddSelectedArticlesDialog: viewer.isFrozen ? forbid : openDialog, - }) - ) - const WithTagLeave = withDialog>( - WithSearchSelect, - TagLeaveDialog, - { ...props, id: tag.id }, - ({ openDialog }) => ({ - openTagLeaveDialog: viewer.isFrozen ? forbid : openDialog, - }) - ) - const WithTagEditor = withDialog>( - WithTagLeave, - TagEditorDialog, - { ...props, id: tag.id }, - ({ openDialog }) => ({ - openTagEditorDialog: viewer.isFrozen ? forbid : openDialog, - }) - ) - - return -} - -export default DropdownActions diff --git a/src/views/TagDetail/DropdownActions/styles.module.css b/src/views/TagDetail/DropdownActions/styles.module.css deleted file mode 100644 index b1b02153c9..0000000000 --- a/src/views/TagDetail/DropdownActions/styles.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.container { - margin-left: var(--sp12); -} diff --git a/src/views/TagDetail/Followers/index.tsx b/src/views/TagDetail/Followers/index.tsx deleted file mode 100644 index 44ff57e3f9..0000000000 --- a/src/views/TagDetail/Followers/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -import { FormattedMessage } from 'react-intl' - -import { numAbbr } from '~/common/utils' -import tagFragments from '~/components/GQL/fragments/tag' -import { FollowersTagFragment } from '~/gql/graphql' - -import styles from './styles.module.css' - -interface FollowersProps { - tag: FollowersTagFragment -} - -const Followers = ({ tag }: FollowersProps) => { - const { totalCount } = tag.followers || { - edges: [], - totalCount: 0, - } - - return ( -
-
- {numAbbr(totalCount)} - -   - - -
-
- ) -} - -Followers.fragments = { - tag: tagFragments.followers, -} -export default Followers diff --git a/src/views/TagDetail/Followers/styles.module.css b/src/views/TagDetail/Followers/styles.module.css deleted file mode 100644 index 54802239b0..0000000000 --- a/src/views/TagDetail/Followers/styles.module.css +++ /dev/null @@ -1,15 +0,0 @@ -.container { - @mixin flex-center-start; -} - -.count { - @mixin inline-flex-center-all; - - font-size: var(--text14); - line-height: 1; - color: var(--color-grey-darker); - - & b { - color: var(--color-black); - } -} diff --git a/src/views/TagDetail/Owner/index.tsx b/src/views/TagDetail/Owner/index.tsx deleted file mode 100644 index 220d51b9df..0000000000 --- a/src/views/TagDetail/Owner/index.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { useContext } from 'react' -import { FormattedMessage } from 'react-intl' - -import { ReactComponent as IconAvatarEmpty } from '@/public/static/icons/24px/avatar-empty.svg' -import { - Button, - Icon, - TagAdoptionDialog, - TextIcon, - toast, - UserDigest, - ViewerContext, -} from '~/components' -import { TagFragmentFragment } from '~/gql/graphql' - -import styles from './styles.module.css' - -const Owner = ({ tag }: { tag: TagFragmentFragment }) => { - const viewer = useContext(ViewerContext) - - const forbid = () => { - toast.error({ - message: ( - - ), - }) - } - - if (!tag) { - return null - } - - if (!tag.owner) { - return ( -
-
- } - color="greyDark" - size={15} - spacing={8} - > - - -
-
- - {({ openDialog }) => ( - - )} - -
-
- ) - } - - return ( -
-
- - - - - -
-
{/* editos */}
-
- ) -} - -export default Owner diff --git a/src/views/TagDetail/Owner/styles.module.css b/src/views/TagDetail/Owner/styles.module.css deleted file mode 100644 index 8bb1982fba..0000000000 --- a/src/views/TagDetail/Owner/styles.module.css +++ /dev/null @@ -1,20 +0,0 @@ -.container { - @mixin flex-center-space-between; - - padding: var(--sp8) var(--sp16); - margin-top: var(--sp16); - background: var(--color-grey-lighter); - border-radius: var(--sp8); -} - -.left { - @mixin flex-center-start; - - & > * + * { - margin-left: var(--sp8); - } -} - -.right { - @mixin flex-center-end; -} diff --git a/src/views/TagDetail/RecommendedAuthors/gql.ts b/src/views/TagDetail/RecommendedAuthors/gql.ts new file mode 100644 index 0000000000..5bf0969989 --- /dev/null +++ b/src/views/TagDetail/RecommendedAuthors/gql.ts @@ -0,0 +1,22 @@ +import gql from 'graphql-tag' + +import { UserDigest } from '~/components' + +export const RECOMMENDED_AUTHORS = gql` + query TagDetailRecommendedAuthors($id: ID!) { + node(input: { id: $id }) { + ... on Tag { + id + recommendedAuthors(input: { first: 5 }) { + edges { + cursor + node { + ...UserDigestRichUserPublic + } + } + } + } + } + } + ${UserDigest.Rich.fragments.user.public} +` diff --git a/src/views/TagDetail/RecommendedAuthors/index.tsx b/src/views/TagDetail/RecommendedAuthors/index.tsx new file mode 100644 index 0000000000..b2df587273 --- /dev/null +++ b/src/views/TagDetail/RecommendedAuthors/index.tsx @@ -0,0 +1,110 @@ +import classNames from 'classnames' +import _chunk from 'lodash/chunk' +import _get from 'lodash/get' +import _random from 'lodash/random' +import { FormattedMessage } from 'react-intl' + +import { analytics } from '~/common/utils' +import { List, Slides, usePublicQuery, UserDigest } from '~/components' +import { TagDetailRecommendedAuthorsQuery } from '~/gql/graphql' + +import { RECOMMENDED_AUTHORS } from './gql' +import styles from './styles.module.css' + +interface RecommendedAuthorsProps { + tagId: string + inSidebar?: boolean +} + +const RecommendedAuthorsHeader = () => { + return ( +
+ +
+ ) +} + +const RecommendedAuthors: React.FC = ({ + tagId, + inSidebar, +}) => { + const perColumn = 3 + const { data } = usePublicQuery( + RECOMMENDED_AUTHORS, + { + variables: { id: tagId }, + } + ) + + const { edges } = + (data?.node?.__typename === 'Tag' && data.node.recommendedAuthors) || {} + + const trackRecommendedAuthors = (i: number, id: string) => () => + analytics.trackEvent('click_feed', { + type: 'tag_detail_recommended_authors', + contentType: 'user', + location: i, + id, + }) + + if (!edges || edges.length <= 0) { + return null + } + + const recommendedAuthorsClasses = classNames({ + [styles.recommendedAuthors]: true, + [styles.inSidebar]: inSidebar, + }) + + if (inSidebar) { + return ( +
+ +
+ + {edges.map(({ node, cursor }, i) => ( + + trackRecommendedAuthors(i, node.id)} + hasFollow={false} + hasState={false} + /> + + ))} + +
+
+ ) + } + + return ( +
+ }> + {_chunk(edges, perColumn).map((chunks, i) => ( + + {chunks.map(({ node, cursor }) => ( + trackRecommendedAuthors(i, node.id)} + hasFollow={false} + hasState={false} + /> + ))} + + ))} + +
+ ) +} + +export default RecommendedAuthors diff --git a/src/views/TagDetail/RecommendedAuthors/styles.module.css b/src/views/TagDetail/RecommendedAuthors/styles.module.css new file mode 100644 index 0000000000..8aa5c05b58 --- /dev/null +++ b/src/views/TagDetail/RecommendedAuthors/styles.module.css @@ -0,0 +1,34 @@ +.recommendedAuthors { + padding-bottom: var(--sp20); + margin-top: var(--sp8); + border-bottom: 1px dashed var(--color-grey-light); + + @media (--sm-up) { + padding-bottom: var(--sp24); + margin-top: var(--sp24); + } +} + +.inSidebar { + padding-bottom: 0; + margin-top: 0; + border-bottom: none; +} + +.header { + margin-bottom: var(--sp6); + font-size: var(--text14); + font-weight: var(--font-medium); + line-height: 1.375rem; + color: var(--color-black); + + @media (--sm-up) { + margin-bottom: var(--sp20); + } +} + +.users { + & :global(.list-item + .list-item) { + margin-top: var(--sp20); + } +} diff --git a/src/views/TagDetail/RelatedTags/gql.ts b/src/views/TagDetail/RelatedTags/gql.ts index 4c40aaa88a..d5cf1cd5d9 100644 --- a/src/views/TagDetail/RelatedTags/gql.ts +++ b/src/views/TagDetail/RelatedTags/gql.ts @@ -3,11 +3,11 @@ import gql from 'graphql-tag' import { TagDigest } from '~/components' export const RELATED_TAGS = gql` - query TagDetailRecommended($id: ID!, $random: random_Int_min_0_max_49) { + query TagDetailRecommended($id: ID!) { node(input: { id: $id }) { ... on Tag { id - recommended(input: { first: 10, filter: { random: $random } }) { + recommended(input: { first: 5 }) { edges { cursor node { diff --git a/src/views/TagDetail/RelatedTags/index.tsx b/src/views/TagDetail/RelatedTags/index.tsx index 61d19fc4f9..f9ffb15a41 100644 --- a/src/views/TagDetail/RelatedTags/index.tsx +++ b/src/views/TagDetail/RelatedTags/index.tsx @@ -1,24 +1,12 @@ -import { useQuery } from '@apollo/react-hooks' import classNames from 'classnames' import _chunk from 'lodash/chunk' import _get from 'lodash/get' import _random from 'lodash/random' import { FormattedMessage } from 'react-intl' -import { PATHS } from '~/common/enums' import { analytics } from '~/common/utils' -import { - List, - PageHeader, - ShuffleButton, - Slides, - TagDigest, - usePublicQuery, - ViewAllButton, - ViewMoreCard, -} from '~/components' -import FETCH_RECORD from '~/components/GQL/queries/lastFetchRandom' -import { LastFetchRandomQuery, TagDetailRecommendedQuery } from '~/gql/graphql' +import { ArticleTag, usePublicQuery } from '~/components' +import { TagDetailRecommendedQuery } from '~/gql/graphql' import { RELATED_TAGS } from './gql' import styles from './styles.module.css' @@ -28,49 +16,22 @@ interface RelatedTagsProps { inSidebar?: boolean } -const RelatedTagsHeader = ({ - hasViewAll, - hasShuffle, - onShuffle, -}: { - hasViewAll?: boolean - hasShuffle?: boolean - onShuffle?: () => void -}) => { +const RelatedTagsHeader = () => { return ( - - } - is="h2" - hasBorder={false} - > -
- {hasShuffle && } - {hasViewAll && } -
-
+
+ +
) } const RelatedTags: React.FC = ({ tagId, inSidebar }) => { - const { data: lastFetchRandom, client } = useQuery( - FETCH_RECORD, - { variables: { id: 'local' } } - ) - - const lastRandom = lastFetchRandom?.lastFetchRandom.feedTags - - const { data, refetch } = usePublicQuery( - RELATED_TAGS, - { - variables: { id: tagId, random: lastRandom || 0 }, - } - ) + const { data } = usePublicQuery(RELATED_TAGS, { + variables: { id: tagId }, + }) const { edges } = (data?.node?.__typename === 'Tag' && data.node.recommended) || {} @@ -87,73 +48,23 @@ const RelatedTags: React.FC = ({ tagId, inSidebar }) => { return null } - const shuffle = () => { - const random = _random(0, 49) - refetch({ random }) - - client.writeData({ - id: 'LastFetchRandom:local', - data: { feedAuthors: random }, - }) - } - const relatedTagsClasses = classNames({ [styles.relatedTags]: true, [styles.inSidebar]: inSidebar, }) - if (!inSidebar) { - return ( -
- }> - {_chunk(edges, 5).map((chunks, edgeIndex) => ( - -
- {chunks.map(({ node, cursor }, nodeIndex) => ( - - trackRelatedTags( - (edgeIndex + 1) * (nodeIndex + 1) - 1, - node.id - ) - } - /> - ))} -
-
- ))} -
- -
- - - -
-
- ) - } - return (
- - + +
{edges?.map(({ node, cursor }, i) => ( - - trackRelatedTags(i, node.id)} - /> - + trackRelatedTags(i, node.id)} + /> ))} - +
) } diff --git a/src/views/TagDetail/RelatedTags/styles.module.css b/src/views/TagDetail/RelatedTags/styles.module.css index 8c29e8ba0d..65ef5cf989 100644 --- a/src/views/TagDetail/RelatedTags/styles.module.css +++ b/src/views/TagDetail/RelatedTags/styles.module.css @@ -1,21 +1,33 @@ .relatedTags { - border-top: 1px dashed var(--color-grey-lighter); - border-bottom: 1px dashed var(--color-grey-lighter); - - & :global(.list-item > .card) { - margin: 0 calc(var(--sp8) * -1); - } + padding-bottom: var(--sp24); + margin-top: var(--sp24); + border-bottom: 1px dashed var(--color-grey-light); } .inSidebar { - border-top-width: 0; - border-bottom-width: 0; + padding-bottom: 0; + margin-top: 0; + border-bottom: none; +} + +.header { + margin-bottom: var(--sp18); + font-size: var(--text14); + font-weight: var(--font-medium); + line-height: 1.375rem; + color: var(--color-black); + + @media (--sm-up) { + margin-bottom: var(--sp16); + } } -.right { - @mixin flex-center-all; +.tags { + display: flex; + flex-wrap: wrap; + gap: var(--sp8); - & > * + * { - margin-left: var(--sp16); + @media (--sm-up) { + gap: var(--sp16); } } diff --git a/src/views/TagDetail/gql.ts b/src/views/TagDetail/gql.ts index 7cacd1e440..c58ccc9930 100644 --- a/src/views/TagDetail/gql.ts +++ b/src/views/TagDetail/gql.ts @@ -1,56 +1,31 @@ import gql from 'graphql-tag' -import { UserDigest } from '~/components/UserDigest' - -import ArticlesCount from './ArticlesCount' -import { TagDetailButtons } from './Buttons' -import Followers from './Followers' +import { TagBookmarkButton } from '~/components' const tagFragment = gql` fragment TagFragment on Tag { id content - cover - description numArticles - numAuthors - creator { - id - ...UserDigestMiniUser - } - editors { - id - ...UserDigestMiniUser - } - owner { - id - ...UserDigestMiniUser + selectedArticles: articles(input: { first: 0 }) { + totalCount } - selectedArticles: articles(input: { first: 0, selected: true }) { + ...TagBookmarkButtonTagPrivate + hottestArticles: articles(input: { first: 0, sortBy: byHottestDesc }) { totalCount } - isOfficial - ...FollowersTag - ...ArticleCountTag - ...FollowButtonTagPrivate - recommended(input: {}) { + recommended(input: { first: 10 }) { edges { cursor node { id content - description - cover numArticles - numAuthors } } } } - ${UserDigest.Mini.fragments.user} - ${Followers.fragments.tag} - ${ArticlesCount.fragments.tag} - ${TagDetailButtons.FollowButton.fragments.tag.private} + ${TagBookmarkButton.fragments.tag.private} ` export const TAG_DETAIL_PUBLIC = gql` @@ -85,9 +60,9 @@ export const TAG_DETAIL_PRIVATE = gql` node(input: { id: $id }) { ... on Tag { id - ...FollowButtonTagPrivate + ...TagBookmarkButtonTagPrivate } } } - ${TagDetailButtons.FollowButton.fragments.tag.private} + ${TagBookmarkButton.fragments.tag.private} ` diff --git a/src/views/TagDetail/index.tsx b/src/views/TagDetail/index.tsx index f2c1b2fe93..9b501072ec 100644 --- a/src/views/TagDetail/index.tsx +++ b/src/views/TagDetail/index.tsx @@ -1,26 +1,21 @@ -import dynamic from 'next/dynamic' import { useContext, useEffect, useState } from 'react' -import { FormattedMessage } from 'react-intl' +import { useIntl } from 'react-intl' +import { ReactComponent as IconHashTag } from '@/public/static/icons/24px/hashtag.svg' import IMAGE_TAG_COVER from '@/public/static/images/tag-cover.png' import { ERROR_CODES } from '~/common/enums' -import { - fromGlobalId, - normalizeTag, - stripSpaces, - toGlobalId, - toPath, -} from '~/common/utils' +import { fromGlobalId, normalizeTag, toGlobalId, toPath } from '~/common/utils' import { EmptyLayout, EmptyTag, - Expandable, Head, + Icon, Layout, - SegmentedTabs, SpinnerBlock, + SquareTabs, + TagBookmarkButton, + TextIcon, Throw404, - useFeatures, usePublicQuery, useRoute, ViewerContext, @@ -34,40 +29,27 @@ import { import TagDetailArticles from './Articles' import ArticlesCount from './ArticlesCount' -import { TagDetailButtons } from './Buttons' -import TagCover from './Cover' -import DropdownActions from './DropdownActions' -import Followers from './Followers' import { TAG_DETAIL_BY_SEARCH, TAG_DETAIL_PRIVATE, TAG_DETAIL_PUBLIC, } from './gql' -import Owner from './Owner' +import RecommendedAuthors from './RecommendedAuthors' import RelatedTags from './RelatedTags' import styles from './styles.module.css' -const DynamicCommunity = dynamic(() => import('./Community'), { - ssr: false, - loading: () => , -}) - -const validTagFeedTypes = ['hottest', 'latest', 'selected', 'creators'] as const +const validTagFeedTypes = ['hottest', 'latest'] as const type TagFeedType = (typeof validTagFeedTypes)[number] const TagDetail = ({ tag }: { tag: TagFragmentFragment }) => { const { router } = useRoute() - const viewer = useContext(ViewerContext) - const features = useFeatures() + const intl = useIntl() // feed type const { getQuery, setQuery } = useRoute() const qsType = getQuery('type') as TagFeedType - const hasSelectedFeed = (tag?.selectedArticles.totalCount || 0) > 0 - const [feedType, setFeedType] = useState( - hasSelectedFeed && qsType === 'selected' ? 'selected' : qsType || 'hottest' - ) + const [feedType, setFeedType] = useState(qsType || 'latest') const changeFeed = (newType: TagFeedType) => { setQuery('type', newType) @@ -75,24 +57,15 @@ const TagDetail = ({ tag }: { tag: TagFragmentFragment }) => { } useEffect(() => { - setFeedType( - hasSelectedFeed && qsType === 'selected' - ? 'selected' - : qsType || 'hottest' - ) + setFeedType(qsType || 'latest') }, [qsType]) - const isSelected = feedType === 'selected' const isHottest = feedType === 'hottest' const isLatest = feedType === 'latest' - const isCreators = feedType === 'creators' + const hasArticles = tag.numArticles > 0 + const hasHottestArticles = tag.hottestArticles.totalCount > 0 useEffect(() => { - // if selected feed is empty, switch to hottest feed - if (!hasSelectedFeed && isSelected) { - changeFeed('hottest') - } - // backward compatible with `/tags/:globalId:` const newPath = toPath({ page: 'tagDetail', @@ -104,132 +77,83 @@ const TagDetail = ({ tag }: { tag: TagFragmentFragment }) => { } }, []) - // define permission - const isOwner = tag?.owner?.id === viewer.id - const isEditor = (tag?.editors || []).some((t) => t.id === viewer.id) - const isMaintainer = isOwner || isEditor || viewer.isAdmin // Matty - const title = '#' + normalizeTag(tag.content) const keywords = tag.content.split(/\s+/).filter(Boolean).map(normalizeTag) - const description = stripSpaces(tag.description) const path = toPath({ page: 'tagDetail', tag }) /** * Render */ return ( - }> - - -
- - -
- - } - mode="transparent" - /> - + + + + + } + > - +
+ } + color="black" + size={24} + spacing={4} + weight="medium" + > + {tag.content} + +
- {features.tag_adoption && } - -
-
- - -
- -
- -
+
+
- {tag.description && ( - -

{tag.description}

-
- )} +
- - changeFeed('hottest')} - > - - - - changeFeed('latest')} - > - - - - {hasSelectedFeed && ( - changeFeed('selected')} - > - - - )} - - changeFeed('creators')} - > - - - - - {(isHottest || isLatest || isSelected) && ( - + {hasArticles && hasHottestArticles && ( +
+ + changeFeed('latest')} + title={intl.formatMessage({ + defaultMessage: 'Latest', + id: 'adThp5', + })} + /> + + changeFeed('hottest')} + title={intl.formatMessage({ + defaultMessage: 'Trending', + id: 'll/ufR', + })} + /> + +
)} - {isCreators && } + ) } @@ -283,25 +207,31 @@ const TagDetailContainer = () => { ) // private data - const loadPrivate = (id: string) => { + const loadPrivate = async (id: string) => { if (!viewer.isAuthed || !id) { return } - client.query({ - query: TAG_DETAIL_PRIVATE, - fetchPolicy: 'network-only', - variables: { id }, - }) + try { + await client.query({ + query: TAG_DETAIL_PRIVATE, + fetchPolicy: 'network-only', + variables: { id }, + }) + } catch (error) { + console.error('Error loading private data:', error) + } } const searchedTag = resultBySearch?.data?.search.edges?.[0] .node as TagFragmentFragment - // fetch private data for first page useEffect(() => { const retryTagId = tagId || searchedTag?.id if (retryTagId) { - loadPrivate(retryTagId) + // FIXME: Delayed loading of private data allows private data to guarantee writing to the final result + setTimeout(() => { + loadPrivate(retryTagId) + }, 100) } }, [tagId, resultBySearch?.data, viewer.id]) diff --git a/src/views/TagDetail/styles.module.css b/src/views/TagDetail/styles.module.css index ae618b47fc..a9d181826c 100644 --- a/src/views/TagDetail/styles.module.css +++ b/src/views/TagDetail/styles.module.css @@ -1,15 +1,35 @@ -.info { +.title { + @mixin flex-center-start; + + height: 2.25rem; /* 36px; */ padding: 0 var(--sp16); - margin-bottom: var(--sp8); + margin: var(--sp32) 0; @media (--sm-up) { padding: 0; } +} - & .top { - @mixin flex-center-space-between; +.info { + @mixin border-top-grey-light; + @mixin border-bottom-grey-light; + @mixin flex-center-space-between; - margin-top: var(--sp16); + padding: var(--sp16) 0; + margin: 0 var(--sp16) var(--sp12); + + @media (--sm-up) { + margin: 0 0 var(--sp12); + } +} + +.tabs { + padding: 0 var(--sp16); + margin-top: var(--sp32); + margin-bottom: var(--sp12); + + @media (--sm-up) { + padding: 0; } } diff --git a/src/views/Tags/Feed.tsx b/src/views/Tags/Feed.tsx index 8f763bed67..7d286e01b2 100644 --- a/src/views/Tags/Feed.tsx +++ b/src/views/Tags/Feed.tsx @@ -1,19 +1,17 @@ import _get from 'lodash/get' -import { analytics, mergeConnections, toPath } from '~/common/utils' +import { analytics, mergeConnections } from '~/common/utils' import { EmptyTag, - InfiniteScroll, Layout, QueryError, SpinnerBlock, - TagDigest, + TagList, usePublicQuery, } from '~/components' import { AllTagsHottestQuery } from '~/gql/graphql' import { ALL_TAGS_HOTTEST } from './gql' -import styles from './styles.module.css' export type FeedType = 'recommended' | 'hottest' @@ -65,36 +63,12 @@ const Feed = ({ type }: Props) => { return ( - -
    - {edges.map(({ node: tag }, i) => ( -
  • - - analytics.trackEvent('click_feed', { - type: trackingType, - contentType: 'tag', - location: i, - id: tag.id, - }) - } - /> -
  • - ))} -
-
+ trackingType={isRecommended ? 'all_tags_recommended' : 'all_tags'} + />
) } diff --git a/src/views/Tags/gql.ts b/src/views/Tags/gql.ts index ed4431ca8d..23261429a9 100644 --- a/src/views/Tags/gql.ts +++ b/src/views/Tags/gql.ts @@ -7,7 +7,7 @@ export const ALL_TAGS_HOTTEST = gql` viewer @connection(key: "viewerAllTagsHottest") { id recommendation { - tags(input: { first: 20, after: $after }) { + tags(input: { first: 30, after: $after }) { totalCount pageInfo { startCursor diff --git a/src/views/Tags/styles.module.css b/src/views/Tags/styles.module.css index 7cf203246b..b40985fb44 100644 --- a/src/views/Tags/styles.module.css +++ b/src/views/Tags/styles.module.css @@ -1,31 +1,7 @@ .tags { - /* FIXME: top header overlay by sticky tabs */ + margin-top: var(--sp24); - /* margin-top: 1px; */ -} - -.list { - @media (--lg-up) { - display: grid; - grid-template-columns: repeat(2, 1fr); - - /* margin-top: calc(var(--sp16) * -1); */ - } - - & .listItem { - position: relative; - padding: var(--sp8) 0; - - @media (--lg-up) { - padding: var(--sp16) 0; - - &:nth-child(2n) { - margin-left: var(--sp4); - } - - &:nth-child(2n + 1) { - margin-right: var(--sp24); - } - } + @media (--sm-up) { + margin-top: var(--sp32); } } diff --git a/src/views/User/UserProfile/FollowingDialog/Content/index.tsx b/src/views/User/UserProfile/FollowingDialog/Content/index.tsx index 8441b74c43..d0cb22c13d 100644 --- a/src/views/User/UserProfile/FollowingDialog/Content/index.tsx +++ b/src/views/User/UserProfile/FollowingDialog/Content/index.tsx @@ -4,7 +4,6 @@ import { Dialog, Spacer } from '~/components' import CirclesFeed from '../CirclesFeed' import FeedType, { FollowingFeedType } from '../FeedType' -import TagsFeed from '../TagsFeed' import UsersFeed from '../UsersFeed' const FollowingDialogContent = () => { @@ -15,7 +14,6 @@ const FollowingDialogContent = () => { {feedType === 'circle' && } - {feedType === 'tag' && } {feedType === 'user' && } ) diff --git a/src/views/User/UserProfile/FollowingDialog/FeedType/index.tsx b/src/views/User/UserProfile/FollowingDialog/FeedType/index.tsx index 5b83b21132..039fa04811 100644 --- a/src/views/User/UserProfile/FollowingDialog/FeedType/index.tsx +++ b/src/views/User/UserProfile/FollowingDialog/FeedType/index.tsx @@ -2,8 +2,6 @@ import { Tabs, Translate } from '~/components' export type FollowingFeedType = 'user' | 'circle' | 'tag' -import { FormattedMessage } from 'react-intl' - import styles from './styles.module.css' interface FeedTypeProps { @@ -13,7 +11,6 @@ interface FeedTypeProps { const FeedType = ({ type, setFeedType }: FeedTypeProps) => { const isCircle = type === 'circle' - const isTag = type === 'tag' const isUser = type === 'user' return ( @@ -26,10 +23,6 @@ const FeedType = ({ type, setFeedType }: FeedTypeProps) => { setFeedType('circle')} selected={isCircle}> - - setFeedType('tag')} selected={isTag}> - -
) diff --git a/src/views/User/UserProfile/FollowingDialog/TagsFeed/gql.ts b/src/views/User/UserProfile/FollowingDialog/TagsFeed/gql.ts deleted file mode 100644 index ef5122e0b0..0000000000 --- a/src/views/User/UserProfile/FollowingDialog/TagsFeed/gql.ts +++ /dev/null @@ -1,48 +0,0 @@ -import gql from 'graphql-tag' - -import { TagDigest } from '~/components' - -export const USER_FOLLOWING_TAGS_PUBLIC = gql` - query UserFollowingTagsPublic($userName: String!, $after: String) { - user(input: { userName: $userName }) { - id - info { - profileCover - description - } - status { - state - } - following { - tags(input: { first: 20, after: $after }) { - pageInfo { - startCursor - endCursor - hasNextPage - } - edges { - cursor - node { - ...TagDigestRichTagPublic - ...TagDigestRichTagPrivate - } - } - } - } - } - } - ${TagDigest.Rich.fragments.tag.public} - ${TagDigest.Rich.fragments.tag.private} -` - -export const USER_FOLLOWING_TAGS_PRIVATE = gql` - query UserFollowingTagsPrivate($ids: [ID!]!) { - nodes(input: { ids: $ids }) { - id - ... on Tag { - ...TagDigestRichTagPrivate - } - } - } - ${TagDigest.Rich.fragments.tag.private} -` diff --git a/src/views/User/UserProfile/FollowingDialog/TagsFeed/index.tsx b/src/views/User/UserProfile/FollowingDialog/TagsFeed/index.tsx deleted file mode 100644 index 7fd265be03..0000000000 --- a/src/views/User/UserProfile/FollowingDialog/TagsFeed/index.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import { useContext, useEffect } from 'react' -import { FormattedMessage } from 'react-intl' - -import { analytics, mergeConnections } from '~/common/utils' -import { - EmptyWarning, - InfiniteScroll, - List, - QueryError, - SpinnerBlock, - TagDigest, - usePublicQuery, - useRoute, - ViewerContext, -} from '~/components' -import { UserFollowingTagsPublicQuery } from '~/gql/graphql' - -import { USER_FOLLOWING_TAGS_PRIVATE, USER_FOLLOWING_TAGS_PUBLIC } from './gql' - -const TagsFeed = () => { - const viewer = useContext(ViewerContext) - const { getQuery } = useRoute() - const userName = getQuery('name') - - /** - * Data Fetching - */ - // public data - const { data, loading, error, fetchMore, client } = - usePublicQuery(USER_FOLLOWING_TAGS_PUBLIC, { - variables: { userName }, - }) - - // pagination - const user = data?.user - const connectionPath = 'user.following.tags' - const { edges, pageInfo } = user?.following?.tags || {} - - // private data - const loadPrivate = (publicData?: UserFollowingTagsPublicQuery) => { - if (!viewer.isAuthed || !publicData || !user) { - return - } - - const publicEdges = publicData.user?.following?.tags.edges || [] - const publicIds = publicEdges.map(({ node }) => node.id) - client.query({ - query: USER_FOLLOWING_TAGS_PRIVATE, - fetchPolicy: 'network-only', - variables: { ids: publicIds }, - }) - } - - // fetch private data for first page - useEffect(() => { - loadPrivate(data) - }, [user?.id, viewer.id]) - - // load next page - const loadMore = async () => { - analytics.trackEvent('load_more', { - type: 'followee', - location: edges?.length || 0, - }) - const { data: newData } = await fetchMore({ - variables: { after: pageInfo?.endCursor }, - updateQuery: (previousResult, { fetchMoreResult }) => - mergeConnections({ - oldData: previousResult, - newData: fetchMoreResult, - path: connectionPath, - }), - }) - - loadPrivate(newData) - } - - /** - * Render - */ - if (loading) { - return - } - - if (error) { - return - } - - if ( - !user || - user?.status?.state === 'archived' || - !edges || - edges.length <= 0 || - !pageInfo - ) { - return ( - - } - /> - ) - } - - return ( - - - {edges.map(({ node, cursor }, i) => ( - - - - ))} - - - ) -} - -export default TagsFeed diff --git a/tests/helpers/poms/articleDetail.ts b/tests/helpers/poms/articleDetail.ts index e95cf587d7..1370785ba7 100644 --- a/tests/helpers/poms/articleDetail.ts +++ b/tests/helpers/poms/articleDetail.ts @@ -177,7 +177,7 @@ export class ArticleDetailPage { await Promise.all([ waitForAPIResponse({ page: this.page, - path: 'data.toggleSubscribeArticle.subscribed', + path: 'data.toggleBookmarkArticle.followed', }), this.toolbarBookmarkButton.click(), ])