From 142cf58ebecf8b633fab66c8cb8840718fdbc870 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 12:06:11 +0800 Subject: [PATCH 01/15] chore: basic login --- src/components/Header/UserAccount.tsx | 5 ++--- src/components/Header/styles/user_account.ts | 13 ++++++++----- src/pages/community.tsx | 1 - src/stores/Model/User.ts | 2 +- utils/ssr.js | 8 ++++++-- 5 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/components/Header/UserAccount.tsx b/src/components/Header/UserAccount.tsx index e57032119..2459b25dd 100755 --- a/src/components/Header/UserAccount.tsx +++ b/src/components/Header/UserAccount.tsx @@ -34,17 +34,16 @@ const UserAccount: FC = () => { {account.isLogin ? ( - 使用 Github 登陆: + Github 登陆: {account.user.login} - 主页面板 { const { gqClient, userHasLogin } = ssrFetchPrepare(context, opt) const { community, thread } = ssrParseURL(context.req) - console.log('## parsed thread: ', thread) // query data const sessionState = gqClient.request(P.sessionState) const curCommunity = gqClient.request(P.community, { diff --git a/src/stores/Model/User.ts b/src/stores/Model/User.ts index 797ca87e1..f5c52f79b 100755 --- a/src/stores/Model/User.ts +++ b/src/stores/Model/User.ts @@ -109,7 +109,7 @@ export const User = T.model('User', { workBackgrounds: T.optional(T.array(WorkBackground), []), sex: T.maybeNull(T.string), // social - social: T.optional(UserSocial, {}), + // social: T.optional(UserSocial, {}), fromGithub: T.optional(T.boolean, false), /* fromWeixin: T.optional(T.boolean, false), */ /* subscribedCommunities: T.optional(pagedCommunities, {}), */ diff --git a/utils/ssr.js b/utils/ssr.js index f2af377e2..a17f9eaec 100755 --- a/utils/ssr.js +++ b/utils/ssr.js @@ -42,6 +42,8 @@ export const ssrBaseStates = (resp) => { export const ssrFetchPrepare = (context, opt) => { const token = ssrFetchToken(context, opt) + console.log('# fetched token: ', token) + const gqClient = makeGQClient(token) const userHasLogin = !!token @@ -176,5 +178,7 @@ export const validCommunityFilters = [ 'read', ] -export const parseTheme = (sessionState) => - sessionState.user ? sessionState.user.customization.theme : DEFAULT_THEME +export const parseTheme = (sessionState) => { + // return sessionState.user ? sessionState.user.customization.theme : DEFAULT_THEME + return DEFAULT_THEME +} From 1622b3b2bad8fd3c8f6bcc22d9d13278c0b6eb16 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 15:26:18 +0800 Subject: [PATCH 02/15] chore: communityBrief adjust --- .../Buttons/FollowButton/FollowingBtn.tsx | 5 +- .../Buttons/styles/follow_button/index.ts | 25 ++++++--- src/components/CommunityJoinSign/index.tsx | 56 +++++++++++++++++++ .../CommunityJoinSign/styles/index.ts | 35 ++++++++++++ .../CommunityJoinSign/tests/index.test.ts | 10 ++++ src/components/CommunityStatesPad/index.tsx | 4 +- .../CommunityStatesPad/styles/index.ts | 5 +- .../ExpandIcon/{index.js => index.tsx} | 49 +++++++--------- src/components/ExpandIcon/styles/index.ts | 6 +- src/components/Icons/JoinEye.tsx | 21 +++++++ .../ClassicLayout/CommunityBrief.tsx | 10 +--- .../digest/CommunityDigest/ExpandTexts.tsx | 13 +---- .../styles/classic_layout/community_brief.ts | 2 +- .../CommunityDigest/styles/expand_texts.ts | 15 +---- utils/constant/svg.ts | 1 + 15 files changed, 176 insertions(+), 81 deletions(-) create mode 100755 src/components/CommunityJoinSign/index.tsx create mode 100755 src/components/CommunityJoinSign/styles/index.ts create mode 100755 src/components/CommunityJoinSign/tests/index.test.ts rename src/components/ExpandIcon/{index.js => index.tsx} (58%) create mode 100644 src/components/Icons/JoinEye.tsx diff --git a/src/components/Buttons/FollowButton/FollowingBtn.tsx b/src/components/Buttons/FollowButton/FollowingBtn.tsx index 847ed31ec..40c8df5e1 100644 --- a/src/components/Buttons/FollowButton/FollowingBtn.tsx +++ b/src/components/Buttons/FollowButton/FollowingBtn.tsx @@ -1,7 +1,6 @@ import { FC, memo } from 'react' import { TSIZE_TSM } from '@/spec' -import { ICON } from '@/config' import { LavaLampLoading } from '@/components/dynamic' import Tooltip from '@/components/Tooltip' @@ -9,7 +8,7 @@ import Tooltip from '@/components/Tooltip' import { BtnWrapper, Popinfo, - CheckedIcon, + FollowingIcon, FollowingButton, } from '../styles/follow_button' @@ -40,7 +39,7 @@ const FollowingBtn: FC = ({ size, loading, text, onClick }) => { noBorder > - + {text} diff --git a/src/components/Buttons/styles/follow_button/index.ts b/src/components/Buttons/styles/follow_button/index.ts index f9a01829a..011764ba5 100644 --- a/src/components/Buttons/styles/follow_button/index.ts +++ b/src/components/Buttons/styles/follow_button/index.ts @@ -6,9 +6,11 @@ import animate from '@/utils/animations' import Button from '@/components/Buttons/Button' import Img from '@/Img' +import JoinEyeSVG from '@/icons/JoinEye' + export const BtnWrapper = styled.div` ${css.flex('align-center')}; - padding: 2px 5px; + padding: 2px 4px; ` const BtnIcon = styled(Img)` ${css.size(14)}; @@ -32,23 +34,30 @@ export const LoadingIcon = styled(BtnIcon)<{ light: boolean }>` ${css.size(15)}; animation: ${animate.rotate360} 1s linear infinite; ` -export const CheckedIcon = styled(BtnIcon)` +export const FollowingIcon = styled(JoinEyeSVG)` fill: ${theme('baseColor.green')}; + ${css.size(15)}; + margin-right: 3px; + transform: scaleX(0.9); + margin-top: -1px; + ${BtnWrapper}:hover & { + fill: ${theme('thread.articleTitle')}; + } ` export const FollowedButton = styled(Button)` border-radius: 10px; ` export const FollowingButton = styled(Button)` - color: ${theme('thread.articleTitle')}; - /* color: ${theme('baseColor.green')}; */ + color: ${theme('baseColor.green')}; + font-weight: bold; border: none; - border-radius: 10px; - background: #003745; + border-radius: 8px; + /* background: #034556; */ padding-top: 2px; padding-bottom: 2px; &:hover { - background: #003745; - /* border: 1px solid; */ + color: ${theme('thread.articleTitle')}; + background: #034556; } ` diff --git a/src/components/CommunityJoinSign/index.tsx b/src/components/CommunityJoinSign/index.tsx new file mode 100755 index 000000000..92b2246d9 --- /dev/null +++ b/src/components/CommunityJoinSign/index.tsx @@ -0,0 +1,56 @@ +/* + * CommunityJoinSign + */ + +import { FC, memo } from 'react' + +import { ICON_CMD } from '@/config' +import { buildLog } from '@/utils/logger' + +import FollowButton from '@/components/Buttons/FollowButton' + +import { + Wrapper, + PopContentWrapper, + PopHeader, + PopHeaderIcon, + PopHeaderText, + PopHighlight, +} from './styles' + +/* eslint-disable-next-line */ +const log = buildLog('c:VerifiedSign:index') + +const PopContent = () => { + return ( + + + + 官方认证 + +
+ 我们已通过各种渠道证实该社区为{' '} + communityTitle 官方开通 +
+
+ ) +} + +// type TProps = {} + +const CommunityJoinSign: FC = () => { + const hasFollowed = false + return ( + + + + ) +} + +export default memo(CommunityJoinSign) diff --git a/src/components/CommunityJoinSign/styles/index.ts b/src/components/CommunityJoinSign/styles/index.ts new file mode 100755 index 000000000..825599a48 --- /dev/null +++ b/src/components/CommunityJoinSign/styles/index.ts @@ -0,0 +1,35 @@ +import styled from 'styled-components' + +import Img from '@/Img' +import { theme } from '@/utils/themes' +import css from '@/utils/css' + +export const Wrapper = styled.div<{ hasFollowed: boolean }>` + ${css.flex('align-center')}; + margin-left: ${({ hasFollowed }) => (hasFollowed ? '-8px' : '5px')}; +` +export const PopContentWrapper = styled.div` + text-align: left; + width: 200px; + font-size: 13px !important; + line-height: 1.6; +` +export const PopHeader = styled.div` + ${css.flex('align-center')} + margin-bottom: 10px; +` +export const PopHeaderIcon = styled(Img)` + fill: ${theme('baseColor.green')}; + padding: 0; + margin-right: 4px; + ${css.size(14)}; +` +export const PopHeaderText = styled.div` + color: ${theme('baseColor.green')}; + font-size: 13px; + font-weight: bold; +` +export const PopHighlight = styled.span` + font-size: 14px; + font-weight: bold; +` diff --git a/src/components/CommunityJoinSign/tests/index.test.ts b/src/components/CommunityJoinSign/tests/index.test.ts new file mode 100755 index 000000000..f411665e2 --- /dev/null +++ b/src/components/CommunityJoinSign/tests/index.test.ts @@ -0,0 +1,10 @@ +// import React from 'react' +// import { shallow } from 'enzyme' + +// import VerifiedSign from '../index' + +describe('TODO ', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(true) + }) +}) diff --git a/src/components/CommunityStatesPad/index.tsx b/src/components/CommunityStatesPad/index.tsx index ffaa8483f..a16b97e2c 100755 --- a/src/components/CommunityStatesPad/index.tsx +++ b/src/components/CommunityStatesPad/index.tsx @@ -40,13 +40,13 @@ const CommunityStatesPad: FC = ({ onShowSubscriberList = log, withoutFounding = true, }) => { - const { editorsCount, subscribersCount, viewerHasSubscribed } = community + const { editorsCount, subscribersCount } = community const { isMobile } = usePlatform() const contentsCount = getContentCount(community) return ( - + {!isMobile && 成员} ` ${css.flexColumn('align-end')}; - background-color: ${({ active }) => - active ? theme('banner.numberHoverBg') : ''}; padding: 0 5px; border-radius: 4px; diff --git a/src/components/ExpandIcon/index.js b/src/components/ExpandIcon/index.tsx similarity index 58% rename from src/components/ExpandIcon/index.js rename to src/components/ExpandIcon/index.tsx index 5975a289d..0d308a49c 100755 --- a/src/components/ExpandIcon/index.js +++ b/src/components/ExpandIcon/index.tsx @@ -4,10 +4,10 @@ * */ -import React, { useState } from 'react' -import T from 'prop-types' +import { FC, memo, useState, ReactNode } from 'react' + +import type { TSIZE_SM } from '@/spec' -// import { ICON_CMD } from '@/config' import { isString } from '@/utils/validator' import { buildLog } from '@/utils/logger' import { SIZE } from '@/constant' @@ -19,14 +19,24 @@ import { Wrapper, Icon, Text } from './styles' /* eslint-disable-next-line */ const log = buildLog('c:ExpandIcon:index') -const ExpandIcon = ({ - icon, +type TProps = { + content: ReactNode + text: string + icon?: ReactNode | string + hideOnClick?: boolean + hideTextOnInit?: boolean + size?: TSIZE_SM + type?: 'default' | 'green' +} + +const ExpandIcon: FC = ({ + icon = '', text, content, - hideOnClick, - type, - size, - hideTextOnInit, + hideOnClick = false, + type = 'default', + size = SIZE.MEDIUM, + hideTextOnInit = true, }) => { const [active, setActive] = useState(false) @@ -45,7 +55,7 @@ const ExpandIcon = ({ hideTextOnInit={hideTextOnInit} > {isString(icon) ? ( - + ) : ( {icon} )} @@ -62,21 +72,4 @@ const ExpandIcon = ({ ) } -ExpandIcon.propTypes = { - content: T.node.isRequired, - text: T.string.isRequired, - icon: T.oneOfType([T.string, T.node]).isRequired, - hideOnClick: T.oneOf([true, false]), - type: T.oneOf(['default', 'green']), - size: T.oneOf([SIZE.SMALL, SIZE.MEDIUM]), - hideTextOnInit: T.oneOf([true, false]), -} - -ExpandIcon.defaultProps = { - hideOnClick: false, - type: 'default', - size: SIZE.MEDIUM, - hideTextOnInit: true, -} - -export default React.memo(ExpandIcon) +export default memo(ExpandIcon) diff --git a/src/components/ExpandIcon/styles/index.ts b/src/components/ExpandIcon/styles/index.ts index 8aaea90f2..ad2861ac1 100755 --- a/src/components/ExpandIcon/styles/index.ts +++ b/src/components/ExpandIcon/styles/index.ts @@ -21,8 +21,8 @@ type TIcon = { type TText = { active: boolean - type: string - size: string + type?: string + size?: string hideTextOnInit: boolean } @@ -58,7 +58,7 @@ export const Icon = styled(Img)` active ? getActiveIconSize(size) : getNormalIconSize(size)}; ${Wrapper}:hover & { - fill: ${theme('thread.articleTitle')}; + /* fill: ${theme('thread.articleTitle')}; */ width: ${({ active, size }) => active ? getActiveIconSize(size) : getNormalIconSize(size)}; height: ${({ active, size }) => diff --git a/src/components/Icons/JoinEye.tsx b/src/components/Icons/JoinEye.tsx new file mode 100644 index 000000000..ccaaad4b3 --- /dev/null +++ b/src/components/Icons/JoinEye.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const JoinEye = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(JoinEye) diff --git a/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx b/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx index 0d5682df9..9d0f50703 100644 --- a/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx +++ b/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx @@ -1,5 +1,4 @@ import { FC, memo } from 'react' -import dynamic from 'next/dynamic' import { contains } from 'ramda' import type { TCommunity } from '@/spec' @@ -9,6 +8,7 @@ import { HCN, NON_FILL_COMMUNITY } from '@/constant' import ExpandTexts from '../ExpandTexts' import SocialList from '../SocialList' +import CommunityJoinSign from '@/components/CommunityJoinSign' import { Wrapper, Logo, @@ -20,12 +20,6 @@ import { LogoHolder, } from '../styles/classic_layout/community_brief' -export const VerifiedSign = dynamic(() => import('@/components/VerifiedSign'), { - /* eslint-disable react/display-name */ - loading: () =>
, - ssr: false, -}) - const CommunityLogoHolder = `${ICON_CMD}/community_logo_holder.svg` type TProps = { @@ -51,7 +45,7 @@ const CommunityBrief: FC = ({ community, descExpand }) => { <TitleText>{community.title}</TitleText> - <VerifiedSign /> + {community.raw !== HCN && <CommunityJoinSign />} {/* {community.desc} */} diff --git a/src/containers/digest/CommunityDigest/ExpandTexts.tsx b/src/containers/digest/CommunityDigest/ExpandTexts.tsx index 6975ae881..b98d85c51 100644 --- a/src/containers/digest/CommunityDigest/ExpandTexts.tsx +++ b/src/containers/digest/CommunityDigest/ExpandTexts.tsx @@ -1,14 +1,7 @@ import { FC, memo } from 'react' -import { ICON } from '@/config' - -import { - Wrapper, - Normal, - Desc, - IconWrapper, - MoreIcon, -} from './styles/expand_texts' +import IconButton from '@/components/Buttons/IconButton' +import { Wrapper, Normal, Desc, IconWrapper } from './styles/expand_texts' import { toggleDescExpand } from './logic' const placeholder = '可能是最性感的开发者社区.' @@ -24,7 +17,7 @@ const ExpandTexts: FC = ({ descExpand, desc = placeholder }) => { {desc} - + diff --git a/src/containers/digest/CommunityDigest/styles/classic_layout/community_brief.ts b/src/containers/digest/CommunityDigest/styles/classic_layout/community_brief.ts index 65bb23fab..486335335 100644 --- a/src/containers/digest/CommunityDigest/styles/classic_layout/community_brief.ts +++ b/src/containers/digest/CommunityDigest/styles/classic_layout/community_brief.ts @@ -50,7 +50,7 @@ export const TitleWrapper = styled.div` ${css.flex('align-center')}; ` export const Title = styled.div<{ descExpand: boolean }>` - ${css.flex('align-baseline')}; + ${css.flex('align-center')}; font-size: ${({ descExpand }) => (descExpand ? '21px' : '18px')}; color: ${theme('banner.title')}; ` diff --git a/src/containers/digest/CommunityDigest/styles/expand_texts.ts b/src/containers/digest/CommunityDigest/styles/expand_texts.ts index 843fe722a..2065c65ff 100644 --- a/src/containers/digest/CommunityDigest/styles/expand_texts.ts +++ b/src/containers/digest/CommunityDigest/styles/expand_texts.ts @@ -1,6 +1,6 @@ import styled from 'styled-components' -import Img from '@/Img' +// import Img from '@/Img' import { theme } from '@/utils/themes' import css from '@/utils/css' @@ -36,16 +36,3 @@ export const Desc = styled.div` export const IconWrapper = styled.div` margin-left: 8px; ` -export const MoreIcon = styled(Img)` - fill: #2c8e8b; - ${css.size(16)}; - cursor: pointer; - opacity: 0.8; - margin-bottom: -2px; - - &:hover { - fill: #2c8e8b; - opacity: 1; - } - transition: all 0.25s; -` diff --git a/utils/constant/svg.ts b/utils/constant/svg.ts index e8083f804..9f81cf4aa 100755 --- a/utils/constant/svg.ts +++ b/utils/constant/svg.ts @@ -19,6 +19,7 @@ const SVG = { // utils MORE: 'more', MOREL: 'more-l', + JOIN_EYE: 'JoinEye', } export default SVG From c31ac184adc45eafef860edf8c5dcb521e9739d9 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 16:13:04 +0800 Subject: [PATCH 03/15] refactor(followButton): adjust styles && offset prop --- .../Buttons/FollowButton/FollowingBtn.tsx | 10 ++++++- src/components/Buttons/FollowButton/index.tsx | 27 ++++++++++--------- .../Buttons/styles/follow_button/index.ts | 3 ++- src/components/CommunityJoinSign/index.tsx | 1 - .../content/ExploreContent/SubscribeBtn.tsx | 1 - .../PostLayout/OriginalCommunity.tsx | 8 +++++- .../unit/ArticleFooter/AuthorInfo/index.tsx | 8 +++++- src/containers/user/UserLister/UserList.js | 1 - 8 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/components/Buttons/FollowButton/FollowingBtn.tsx b/src/components/Buttons/FollowButton/FollowingBtn.tsx index 40c8df5e1..7a7316bdf 100644 --- a/src/components/Buttons/FollowButton/FollowingBtn.tsx +++ b/src/components/Buttons/FollowButton/FollowingBtn.tsx @@ -15,11 +15,18 @@ import { type TProps = { size: TSIZE_TSM loading: boolean + followingOffset: number text: string onClick: () => void } -const FollowingBtn: FC = ({ size, loading, text, onClick }) => { +const FollowingBtn: FC = ({ + size, + loading, + followingOffset, + text, + onClick, +}) => { return ( <> {loading ? ( @@ -33,6 +40,7 @@ const FollowingBtn: FC = ({ size, loading, text, onClick }) => { > void onUndoFollow?: (userId: TID) => void } @@ -29,38 +30,40 @@ type TProps = { const FollowButton: FC = ({ userId, size = SIZE.SMALL, - fakeLoading = false, + simuLoading = true, loading = false, hasFollowed = false, followText = '关 注', followingText = '已关注', + followingOffset = 0, onFollow = log, onUndoFollow = log, }) => { - const [simuLoading, setSimuLoading] = useState(false) - const isLoading = fakeLoading ? simuLoading : loading + const [fakeLoading, setFakeLoading] = useState(false) + const isLoading = simuLoading ? fakeLoading : loading const handleFollow = useCallback(() => { - if (fakeLoading) { - setSimuLoading(true) - setTimeout(() => setSimuLoading(false), 1500) + if (simuLoading) { + setFakeLoading(true) + setTimeout(() => setFakeLoading(false), 1500) } onFollow(userId) - }, [fakeLoading, onFollow, userId]) + }, [simuLoading, onFollow, userId]) const handleUndoFollow = useCallback(() => { - if (fakeLoading) { - setSimuLoading(true) - setTimeout(() => setSimuLoading(false), 1500) + if (simuLoading) { + setFakeLoading(true) + setTimeout(() => setFakeLoading(false), 1500) } onUndoFollow(userId) - }, [fakeLoading, onUndoFollow, userId]) + }, [simuLoading, onUndoFollow, userId]) return ( <> {hasFollowed ? ( ` color: ${theme('baseColor.green')}; font-weight: bold; border: none; border-radius: 8px; + margin-left: ${({ followingOffset }) => `${followingOffset}px` || 0}; /* background: #034556; */ padding-top: 2px; padding-bottom: 2px; diff --git a/src/components/CommunityJoinSign/index.tsx b/src/components/CommunityJoinSign/index.tsx index 92b2246d9..ffb6c812a 100755 --- a/src/components/CommunityJoinSign/index.tsx +++ b/src/components/CommunityJoinSign/index.tsx @@ -47,7 +47,6 @@ const CommunityJoinSign: FC = () => { followingText="已加入" size="tiny" hasFollowed={hasFollowed} - fakeLoading /> ) diff --git a/src/containers/content/ExploreContent/SubscribeBtn.tsx b/src/containers/content/ExploreContent/SubscribeBtn.tsx index 0537e9337..87a80b81a 100755 --- a/src/containers/content/ExploreContent/SubscribeBtn.tsx +++ b/src/containers/content/ExploreContent/SubscribeBtn.tsx @@ -35,7 +35,6 @@ const SubscribeBtn: FC = ({ hasFollowed={community.viewerHasSubscribed} onFollow={() => subscribe(community.id)} onUndoFollow={() => unSubscribe(community.id)} - fakeLoading /> ) } diff --git a/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx b/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx index 6e607f622..1b2b13113 100644 --- a/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx +++ b/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx @@ -16,12 +16,18 @@ type TProps = { } const OriginalCommunity: FC = ({ community }) => { + const hasFollowed = true + return ( {community.title} {community.subscribersCount} 人加入 - + ) } diff --git a/src/containers/unit/ArticleFooter/AuthorInfo/index.tsx b/src/containers/unit/ArticleFooter/AuthorInfo/index.tsx index 7a80781ba..e6c7ceba3 100644 --- a/src/containers/unit/ArticleFooter/AuthorInfo/index.tsx +++ b/src/containers/unit/ArticleFooter/AuthorInfo/index.tsx @@ -40,6 +40,7 @@ const AuthorInfo: FC = ({ testid = 'author-info', author }) => { string > + const hasFollowed = false return ( @@ -55,7 +56,12 @@ const AuthorInfo: FC = ({ testid = 'author-info', author }) => { src={author.avatar} fallback={} /> - + ) diff --git a/src/containers/user/UserLister/UserList.js b/src/containers/user/UserLister/UserList.js index e8c642693..85d958f4c 100755 --- a/src/containers/user/UserLister/UserList.js +++ b/src/containers/user/UserLister/UserList.js @@ -51,7 +51,6 @@ const UsersTable = ({ entries, accountId }) => ( userId={user.id} onFollow={onFollow} onUndoFollow={undoFollow} - fakeLoading /> ) : (
(本尊)
From 877c86af559088191239bdadf70dc822d34e7808 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 17:30:08 +0800 Subject: [PATCH 04/15] refactor(clean-up): unused store & containers --- .../PostLayout/OriginalCommunity.tsx | 4 +- .../post_layout/original_community.ts | 7 +- src/containers/editor/PostEditor/Editor.js | 48 ---- .../editor/PostEditor/EditorFooter.js | 64 ----- src/containers/editor/PostEditor/Header.js | 66 ----- .../editor/PostEditor/MarkDownHelper.js | 105 -------- src/containers/editor/PostEditor/Preview.js | 28 -- src/containers/editor/PostEditor/RadarNote.js | 72 ------ src/containers/editor/PostEditor/index.js | 129 ---------- src/containers/editor/PostEditor/logic.js | 239 ------------------ src/containers/editor/PostEditor/schema.ts | 97 ------- src/containers/editor/PostEditor/store.js | 140 ---------- .../editor/PostEditor/styles/editor.ts | 43 ---- .../editor/PostEditor/styles/editor_footer.ts | 43 ---- .../editor/PostEditor/styles/header.ts | 57 ----- .../editor/PostEditor/styles/index.ts | 57 ----- .../PostEditor/styles/markdown_helper.ts | 11 - .../editor/PostEditor/styles/preview.ts | 26 -- .../editor/PostEditor/styles/radar_note.ts | 48 ---- .../editor/PostEditor/test_mentions.js | 37 --- .../editor/PostEditor/tests/index.test.ts | 10 - .../editor/PostEditor/tests/store.test.ts | 10 - .../tool/Drawer/Content/renderContent.tsx | 12 +- src/containers/tool/Drawer/dynamics.tsx | 13 +- src/stores/RootStore/index.ts | 9 +- src/stores/RootStore/index2.ts | 7 - src/stores/index.ts | 3 +- 27 files changed, 19 insertions(+), 1366 deletions(-) delete mode 100755 src/containers/editor/PostEditor/Editor.js delete mode 100755 src/containers/editor/PostEditor/EditorFooter.js delete mode 100755 src/containers/editor/PostEditor/Header.js delete mode 100755 src/containers/editor/PostEditor/MarkDownHelper.js delete mode 100755 src/containers/editor/PostEditor/Preview.js delete mode 100755 src/containers/editor/PostEditor/RadarNote.js delete mode 100755 src/containers/editor/PostEditor/index.js delete mode 100755 src/containers/editor/PostEditor/logic.js delete mode 100755 src/containers/editor/PostEditor/schema.ts delete mode 100755 src/containers/editor/PostEditor/store.js delete mode 100755 src/containers/editor/PostEditor/styles/editor.ts delete mode 100755 src/containers/editor/PostEditor/styles/editor_footer.ts delete mode 100755 src/containers/editor/PostEditor/styles/header.ts delete mode 100755 src/containers/editor/PostEditor/styles/index.ts delete mode 100755 src/containers/editor/PostEditor/styles/markdown_helper.ts delete mode 100755 src/containers/editor/PostEditor/styles/preview.ts delete mode 100755 src/containers/editor/PostEditor/styles/radar_note.ts delete mode 100755 src/containers/editor/PostEditor/test_mentions.js delete mode 100755 src/containers/editor/PostEditor/tests/index.test.ts delete mode 100755 src/containers/editor/PostEditor/tests/store.test.ts diff --git a/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx b/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx index 1b2b13113..90626e71d 100644 --- a/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx +++ b/src/containers/digest/ArticleDigest/DesktopView/PostLayout/OriginalCommunity.tsx @@ -1,11 +1,13 @@ import { FC, memo } from 'react' import type { TCommunity } from '@/spec' +import { HCN } from '@/constant' import FollowButton from '@/components/Buttons/FollowButton' import { Wrapper, + HomeLogo, Icon, Name, JoinDesc, @@ -20,7 +22,7 @@ const OriginalCommunity: FC = ({ community }) => { return ( - + {community.raw === HCN ? : } {community.title} {community.subscribersCount} 人加入 { - const { title, body } = editData - - return ( - - inputOnChange('copyRight')} - onLinkAddrChange={() => inputOnChange('linkAddr')} - onPreview={() => changeView('PREVIEW_VIEW')} - /> - inputOnChange('title')} - /> -
- TODO: - - - -
- ) -} - -export default React.memo(Editor) diff --git a/src/containers/editor/PostEditor/EditorFooter.js b/src/containers/editor/PostEditor/EditorFooter.js deleted file mode 100755 index 7e0e208ad..000000000 --- a/src/containers/editor/PostEditor/EditorFooter.js +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react' -import { pluck } from 'ramda' - -import { ICON_CMD } from '@/config' - -import DocUploader from '@/containers/tool/DocUploader' -import Maybe from '@/components/Maybe' - -import { - Wrapper, - Item, - ItemTitle, - ItemIcon, - Divider, -} from './styles/editor_footer' - -import { insertCode, onUploadImageDone } from './logic' - -const CodeInputer = ({ divider }) => ( - <> - - - - - - 代码 - - -) - -const PicUploader = ({ divider }) => ( - <> - - - - - - - 上传图片 - - - -) - -const EditorFooter = ({ isEdit, editData }) => ( - - - - - -) - -export default React.memo(EditorFooter) - -/* - - - 投票 - - - - 设置 - - */ diff --git a/src/containers/editor/PostEditor/Header.js b/src/containers/editor/PostEditor/Header.js deleted file mode 100755 index 673719327..000000000 --- a/src/containers/editor/PostEditor/Header.js +++ /dev/null @@ -1,66 +0,0 @@ -import React from 'react' -import { isEmpty } from 'ramda' - -import AvatarsRow from '@/components/AvatarsRow' -import { ICON_CMD } from '@/config' - -import { - Wrapper, - UsageText, - RefUsersWrapper, - AtSignIcon, - RefUserList, - MarkdownIcon, - MarkDownHint, - BackToEditHint, -} from './styles/header' - -import { changeView } from './logic' - -const DoingText = ({ isEdit }) => { - return isEdit ? <>更新 : <>发布 -} - -const Header = ({ isEdit, curView, referUsers }) => { - switch (curView) { - case 'MARKDOWN_HELP_VIEW': - return ( - - Github Flavor Markdown - changeView('CREATE_VIEW')}> - - 返回编辑 - - - ) - - default: - return ( - - - - 帖子 - {!isEmpty(referUsers) && ( - - - - - - - )} - - changeView('MARKDOWN_HELP_VIEW')}> - - markdown 语法速查 - - - ) - } -} - -export default React.memo(Header) diff --git a/src/containers/editor/PostEditor/MarkDownHelper.js b/src/containers/editor/PostEditor/MarkDownHelper.js deleted file mode 100755 index 13c5ee868..000000000 --- a/src/containers/editor/PostEditor/MarkDownHelper.js +++ /dev/null @@ -1,105 +0,0 @@ -import React from 'react' -import { Remarkable } from 'remarkable' -import remarkableemoj from 'remarkable-emoji' -import mentions from 'remarkable-mentions' -import Prism from 'mastani-codehighlight' - -import { MENTION_USER_ADDR } from '@/config' -import MarkDownStyle from '@/containers/layout/ThemePalette/MarkDownStyle' - -import { Wrapper } from './styles/markdown_helper' - -const md = new Remarkable() -md.use(mentions({ url: MENTION_USER_ADDR })) -md.use(remarkableemoj) - -const MarkDownInfo = () => { - const IntroMD = `\`说明\`: 显示效果与下方实现代码一一对应 -# 这是一级标题 -\`\`\`text -# 这是一级标题 -\`\`\` -## 这是二级标题 -\`\`\`text -## 这是二级标题 -\`\`\` - -### 这是三级标题 -\`\`\`text -### 这是三级标题 -\`\`\` - -#### 这是四级标题 -\`\`\`text -#### 这是四级标题 -\`\`\` - -##### 这是五级标题 -\`\`\`text -##### 这是五级标题 -\`\`\` - -###### 这是六级标题 -\`\`\`text -###### 这是六级标题 -\`\`\` - -编程语言代码高亮: - \`\`\`js -console.log('hello mastani') - \`\`\` - -\`\`\`text -'''js -console.log('hello mastani') -''' -注意这里是反斜杠(\`), 如果是其他编程语言将'js'替换即可。 -\`\`\` - -> 这是引用 -\`\`\`text -> 这是引用 -\`\`\` - -At 某个用户: @mydearxym - -\`\`\`text -At 某个用户: @mydearxym -\`\`\` - -插入链接: [coderplanets.com](https://coderplanets.com) - -\`\`\`text -插入链接: [coderplanets.com](https://coderplanets.com) -\`\`\` - -## Emoji 参考 -` - return ( -
- ) -} - -/* eslint-enable react/no-danger */ -class MarkDownHelper extends React.Component { - componentDidMount() { - Prism.highlightAll() - } - - render() { - return ( - - - - - - ) - } -} - -export default React.memo(MarkDownHelper) diff --git a/src/containers/editor/PostEditor/Preview.js b/src/containers/editor/PostEditor/Preview.js deleted file mode 100755 index db296507a..000000000 --- a/src/containers/editor/PostEditor/Preview.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Editor based on Draft - */ - -import React from 'react' - -import Button from '@/components/Buttons/Button' -import MarkDownRender from '@/components/MarkDownRender' -import { Wrapper, Header, BackToEditBtn, PreviewHeader } from './styles/preview' - -/* eslint-disable react/no-danger */ -const Preview = ({ onBack, editData: { title, body }, contentDomId }) => ( - -
- - - -
- {title} - - -
-) -/* eslint-enable react/no-danger */ - -export default React.memo(Preview) diff --git a/src/containers/editor/PostEditor/RadarNote.js b/src/containers/editor/PostEditor/RadarNote.js deleted file mode 100755 index 76178060c..000000000 --- a/src/containers/editor/PostEditor/RadarNote.js +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react' - -import { ISSUE_ADDR } from '@/config' - -import { cutRest } from '@/utils/helper' -import { - Wrapper, - Title, - IconsWrapper, - Site, - SiteInfo, - SiteTitle, - SiteLink, - SiteIcon, - Footer, -} from './styles/radar_note' - -const whiteList = [ - { - title: '湾区日报', - link: 'https://wanqu.co/', - logo: - 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/radar_source/wanqu.png', - }, - { - title: 'solidot', - link: 'https://www.solidot.org/', - logo: - 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/radar_source/solidot.png', - }, - { - title: 'techcrunch', - link: 'https://techcrunch.cn/', - logo: - 'https://cps-oss.oss-cn-shanghai.aliyuncs.com/icons/radar_source/techcrunch.png', - }, -] - -const RadarNote = () => ( - - 感谢参与。目前为保证质量,只支持如下站点源转载信息: - - {whiteList.map((item) => ( - - - - {item.title} - - {cutRest(item.link, 18)} - - - - ))} - -
-
如果你有更好的新闻源或意见,欢迎参与社区讨论:
- - {cutRest(`${ISSUE_ADDR}/339`, 100)} - -
-
-) - -export default React.memo(RadarNote) diff --git a/src/containers/editor/PostEditor/index.js b/src/containers/editor/PostEditor/index.js deleted file mode 100755 index 17bc3efe1..000000000 --- a/src/containers/editor/PostEditor/index.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * PostEditor - * - */ - -import React from 'react' -/* import T from 'prop-types' */ -import dynamic from 'next/dynamic' - -import { buildLog } from '@/utils/logger' -import { pluggedIn } from '@/utils/mobx' - -import ArticleEditFooter from '@/components/ArticleEditFooter' -import { ArticleContentLoading } from '@/components/Loading' -import Modal from '@/components/Modal' - -import Editor from './Editor' -import Preview from './Preview' -import Header from './Header' -import RadarNote from './RadarNote' - -import { Wrapper, ViewerWrapper } from './styles' - -import { - useInit, - changeView, - onPublish, - cancelPublish, - onRadarNoteCLose, -} from './logic' - -export const MarkDownHelper = dynamic(() => import('./MarkDownHelper'), { - /* eslint-disable react/display-name */ - loading: () => , - ssr: false, -}) - -/* eslint-disable-next-line */ -const log = buildLog('C:PostEditor') - -// const View = ({ curView, thread, copyRight, title, body, linkAddr }) => { -const View = ({ - curView, - thread, - isEdit, - editData, - mentionList, - contentDomId, -}) => { - if (curView === 'CREATE_VIEW' || curView === 'PREVIEW_VIEW') { - return ( - - - - - - changeView('CREATE_VIEW')} - /> - - - ) - } - return -} - -const PostEditorContainer = ({ postEditor: store, attachment }) => { - useInit(store, attachment) - - const { - copyRight, - thread, - curView, - publishing, - isEdit, - editData, - mentionListData, - referUsersData, - contentDomId, - showRadarNote, - } = store - - log('editData in views: ', editData) - - return ( - - - - -
- - - - ) -} - -export default pluggedIn(PostEditorContainer) diff --git a/src/containers/editor/PostEditor/logic.js b/src/containers/editor/PostEditor/logic.js deleted file mode 100755 index 08c9e3de0..000000000 --- a/src/containers/editor/PostEditor/logic.js +++ /dev/null @@ -1,239 +0,0 @@ -import { map, contains, repeat, isEmpty, slice, trim } from 'ramda' -import { useEffect } from 'react' - -import { EVENT, ERR, THREAD } from '@/constant' -import { - asyncSuit, - buildLog, - send, - countWords, - extractAttachments, - extractMentions, - updateEditing, - closeDrawer, - cast, - parseDomain, - errRescue, - BStore, -} from '@/utils' - -import { S, updatablePostFields } from './schema' - -/* eslint-disable-next-line */ -const log = buildLog('L:PostEditor') - -const { SR71, $solver, asyncRes, asyncErr } = asyncSuit -const sr71$ = new SR71() - -let store = null -let sub$ = null -let saveDraftTimmer = null - -export const changeView = (curView) => store.mark({ curView }) - -const getDigest = (body) => { - /* eslint-disable no-undef */ - const digestContainer = document.getElementById(store.contentDomId) - - /* eslint-enable no-undef */ - const innerImagesLength = extractAttachments(body).length - let digest = slice(0, 65, trim(digestContainer.innerText)) - - if (innerImagesLength > 0 && innerImagesLength <= 2) { - const imgDigest = `${repeat('[图片]', innerImagesLength)}` - digest = isEmpty(digest) ? imgDigest : `${digest}..${imgDigest}` - } else if (innerImagesLength > 2) { - const imgDigest = `${repeat('[图片]', 2)} x ${innerImagesLength}` - digest = isEmpty(digest) ? imgDigest : `${digest}..${imgDigest}` - } - - return digest -} - -export const onRadarNoteCLose = () => store.mark({ showRadarNote: false }) - -export const onPublish = () => { - if (!store.validator('general')) return false - - const { body } = store.editData - const { isEdit } = store - publishing() - - const digest = getDigest(body) - const length = countWords(body) - - const variables = { - ...store.editData, - communityId: store.viewing.community.id, - digest, - length, - mentionUsers: map((user) => ({ id: user.id }), store.referUsersData), - } - if (!isEmpty(store.labelsData.tags)) { - variables.tags = store.labelsData.tags - } - - log('onPublish labelsData: ', store.labelsData.tags) - log('onPublish variables: ', variables) - - if (isEdit) { - const args = cast(updatablePostFields, variables) - return sr71$.mutate(S.updatePost, args) - } - sr71$.mutate(S.createPost, variables) -} - -export const cancelPublish = () => { - cancelLoading() - // store.reset() - closeDrawer() -} - -export const onUploadImageDone = (url) => - send(EVENT.DRAFT_INSERT_SNIPPET, { data: `![](${url})` }) - -export const insertCode = () => { - const communityRaw = store.curCommunity.raw - const data = `\`\`\`${communityRaw}\n\n\`\`\`` - - send(EVENT.DRAFT_INSERT_SNIPPET, { data }) -} - -export const onMentionSearch = (name) => { - if (name?.length >= 2) { - sr71$.query(S.searchUsers, { name }) - } else { - store.mark({ mentionList: [] }) - } -} - -export const onMention = (user) => store.addReferUser(user) - -const openAttachment = (att) => { - if (!att) return false - // const { type } = att - // if (type === TYPE.DRAWER.POST_EDIT) loadPost(att.id) - store.updateEditing(att) - store.mark({ isEdit: true }) -} - -const doneCleanUp = () => { - closeDrawer() - store.reset() - cancelLoading() -} - -export const inputOnChange = (part, e) => updateEditing(store, part, e) -export const bodyInputOnChange = (content) => { - // draft.js will mis trigger onChange event with empty string. - // currently this is a bug: in edit can't update to empty. - if (!store) return false - if (store.isEdit && content === '') return false - store.mark({ extractMentions: extractMentions(content) }) - - updateEditing(store, 'body', content) -} - -const saveDraftIfNeed = (content) => { - if (isEmpty(content)) return false - const curDraftContent = BStore.get('recentDraft') - - if (curDraftContent !== content) BStore.set('recentDraft', content) -} - -const clearDraft = () => BStore.set('recentDraft', '') - -const publishing = (maybe = true) => store.mark({ publishing: maybe }) -const cancelLoading = () => store.mark({ publishing: false }) - -// ############################### -// Data & Error handlers -// ############################### - -const DataSolver = [ - { - match: asyncRes('createPost'), - action: () => { - store.toast('success', { - title: '帖子已发布', - msg: 'have a good day :)', - position: 'topCenter', - }) - - doneCleanUp() - clearDraft() - send(EVENT.REFRESH_POSTS) - }, - }, - { - match: asyncRes('updatePost'), - action: () => { - store.toast('success', { - title: '已更新', - msg: '.', - position: 'topCenter', - }) - - doneCleanUp() - send(EVENT.REFRESH_POSTS) - }, - }, - { - match: asyncRes('searchUsers'), - action: ({ searchUsers: { entries } }) => store.updateMentionList(entries), - }, -] - -const ErrSolver = [ - { - match: asyncErr(ERR.GRAPHQL), - action: () => cancelLoading(), - }, - { - match: asyncErr(ERR.TIMEOUT), - action: ({ details }) => { - cancelLoading() - errRescue({ type: ERR.TIMEOUT, details, path: 'PostEditor' }) - }, - }, - { - match: asyncErr(ERR.NETWORK), - action: () => { - cancelLoading() - errRescue({ type: ERR.NETWORK, path: 'PostEditor' }) - }, - }, -] - -const initDraftTimmer = () => { - // only save draft in create mode - if (store.isEdit) return false - if (saveDraftTimmer) clearInterval(saveDraftTimmer) - - saveDraftTimmer = setInterval( - () => saveDraftIfNeed(store.editPost.body), - 3000, - ) -} - -// ############################### -// init & uninit -// ############################### -export const useInit = (_store, attachment) => { - useEffect(() => { - // log('effect init') - store = _store - sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) - openAttachment(attachment) - initDraftTimmer() - - return () => { - // log('effect uninit') - if (saveDraftTimmer) clearInterval(saveDraftTimmer) - - store.mark({ editPost: {}, isEdit: false }) - sr71$.stop() - sub$.unsubscribe() - } - }, [_store, attachment]) -} diff --git a/src/containers/editor/PostEditor/schema.ts b/src/containers/editor/PostEditor/schema.ts deleted file mode 100755 index b3eb10a7b..000000000 --- a/src/containers/editor/PostEditor/schema.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { gql } from '@urql/core' -import { F } from '@/schemas' - -const createPost = gql` - mutation createPost( - $title: String! - $body: String! - $digest: String! - $length: Int! - $linkAddr: String - $copyRight: String - $communityId: ID! - $tags: [Ids] - $mentionUsers: [Ids] - ) { - createPost( - title: $title - body: $body - digest: $digest - length: $length - linkAddr: $linkAddr - copyRight: $copyRight - communityId: $communityId - tags: $tags - mentionUsers: $mentionUsers - ) { - id - title - body - } - } -` - -const updatePost = gql` - mutation( - $id: ID! - $title: String - $body: String - $digest: String - $copyRight: String - $linkAddr: String - $tags: [Ids] - ) { - updatePost( - id: $id - title: $title - body: $body - digest: $digest - copyRight: $copyRight - linkAddr: $linkAddr - tags: $tags - ) { - id - title - body - copyRight - } - } -` - -const post = gql` - query($id: ID!) { - post(id: $id) { - articleTags { - ${F.tag} - } - } - } -` - -const searchUsers = gql` - query($name: String!) { - searchUsers(name: $name) { - entries { - ${F.author} - } - } - } -` - -export const updatablePostFields = [ - 'id', - 'title', - 'digest', - 'body', - 'copyRight', - 'linkAddr', - 'tags', - // TODO: 'mentionUsers', -] - -export const S = { - createPost, - updatePost, - post, - searchUsers, -} diff --git a/src/containers/editor/PostEditor/store.js b/src/containers/editor/PostEditor/store.js deleted file mode 100755 index 686b646d0..000000000 --- a/src/containers/editor/PostEditor/store.js +++ /dev/null @@ -1,140 +0,0 @@ -/* - * PostEditor store - * - */ - -import { types as T, getParent } from 'mobx-state-tree' -import { - merge, - map, - uniq, - concat, - clone, - findIndex, - filter, - contains, -} from 'ramda' - -import { markStates, toJS } from '@/utils/mobx' -import { changeset } from '@/utils/validator' -import { Post, Mention } from '@/model' - -const PostEditor = T.model('PostEditor', { - editPost: T.optional(Post, {}), - - mentionList: T.optional(T.array(Mention), []), - // current "@user" in valid array format - referUsers: T.optional(T.array(Mention), []), - // current "@user" in string list - extractMentions: T.optional(T.array(T.string), []), - - curView: T.optional( - T.enumeration('curView', [ - 'MARKDOWN_HELP_VIEW', - 'EDIT_VIEW', - 'CREATE_VIEW', - 'PREVIEW_VIEW', - ]), - 'CREATE_VIEW', - ), - contentDomId: T.optional(T.string, 'post_editor_content_id'), - - publishing: T.optional(T.boolean, false), - // TODO: rename to isEditMode - isEdit: T.optional(T.boolean, false), - /* show radar note if radar source not supported */ - showRadarNote: T.optional(T.boolean, false), -}) - .views((self) => ({ - get root() { - return getParent(self) - }, - get curRoute() { - return self.root.curRoute - }, - get viewing() { - return toJS(self.root.viewing) - }, - get editData() { - return toJS(self.editPost) - }, - get curCommunity() { - return toJS(self.root.viewing.community) - }, - get thread() { - return self.root.viewing.activeThread - }, - get activeThread() { - return self.root.viewing.activeThread - }, - get labelsData() { - return self.root.labeler.labelsData - }, - get mentionListData() { - return toJS(self.mentionList) - }, - get referUsersData() { - const referUsers = toJS(self.referUsers) - const extractMentions = toJS(self.extractMentions) - return filter((user) => contains(user.name, extractMentions), referUsers) - }, - })) - .actions((self) => ({ - toast(type, options) { - self.root.toast(type, options) - }, - changesetErr(options) { - self.root.changesetErr(options) - }, - validator(type) { - switch (type) { - case 'general': { - const result = changeset(self.editData) - .exist({ title: '文章标题或内容' }, self.changesetErr) - .exist({ body: '文章标题或内容' }, self.changesetErr) - // .exist({ linkAddr: '原链接地址' }, self.changesetErr) - .startsWith( - { linkAddr: '原链接地址' }, - 'https://', - self.changesetErr, - self.editData.copyRight !== 'original', - ) - .done() - - return result.passed - } - default: { - return false - } - } - }, - updateEditing(sobj) { - const editPost = merge(self.editData, { ...sobj }) - return self.mark({ editPost }) - }, - reset() { - self.mark({ isEdit: false, mentionList: [] }) - self.editPost = { title: '', body: '' } - }, - updateMentionList(mentionArray) { - const curMentionList = clone(self.mentionList) - const uniqList = uniq(concat(curMentionList, mentionArray)) - const mentionList = map((m) => ({ ...m, name: m.nickname }), uniqList) - self.mentionList = mentionList - }, - addReferUser(user) { - const index = findIndex((u) => u.id === String(user.id), self.referUsers) - if (index === -1) { - self.referUsers.push({ - id: String(user.id), - name: user.name, - avatar: user.avatar, - }) - } - }, - mark(sobj) { - markStates(sobj, self) - }, - })) - -export default PostEditor diff --git a/src/containers/editor/PostEditor/styles/editor.ts b/src/containers/editor/PostEditor/styles/editor.ts deleted file mode 100755 index 5ce820867..000000000 --- a/src/containers/editor/PostEditor/styles/editor.ts +++ /dev/null @@ -1,43 +0,0 @@ -import styled from 'styled-components' -import Input from '@/components/Input' - -import { theme } from '@/utils/themes' -import css from '@/utils/css' - -export const Wrapper = styled.div` - ${css.flexColumn()}; - - padding: 20px; - background-color: ${theme('editor.contentBg')}; - min-height: 400px; - margin-top: 5px; - margin-left: 4%; - margin-right: 4%; - border-radius: 5px; -` -export const TitleInput = styled(Input)` - border-color: ${theme('editor.border')}; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.borderNormal')}; - - text-align: center; - height: 45px; - font-size: 1.6em; - color: ${theme('editor.title')}; - background: ${theme('editor.headerBg')}; - align-self: center; - width: 85%; - &:hover { - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.borderActive')}; - } - &:focus { - box-shadow: none; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.borderActive')}; - } -` -export const FooterWrapper = styled.div` - ${css.flex('justify-center')}; - margin-top: 25px; -` diff --git a/src/containers/editor/PostEditor/styles/editor_footer.ts b/src/containers/editor/PostEditor/styles/editor_footer.ts deleted file mode 100755 index 8af46f0fa..000000000 --- a/src/containers/editor/PostEditor/styles/editor_footer.ts +++ /dev/null @@ -1,43 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme } from '@/utils/themes' -import css from '@/utils/css' -import animate from '@/utils/animations' -// -export const Wrapper = styled.div` - ${css.flex('align-both')}; - flex-wrap: wrap; -` -export const Item = styled.div` - ${css.flex()}; - color: ${theme('editor.footer')}; - &:hover { - color: #51abb2; - animation: ${animate.pulse} 0.4s linear; - } -` -export const Divider = styled(Img)` - fill: ${theme('editor.footer')}; - ${css.size(10)}; - margin-left: 4px; - margin-right: 4px; -` -export const ItemTitle = styled.div` - cursor: pointer; - font-size: 1rem; - ${Item}:hover & { - color: ${theme('editor.footerHover')}; - } -` -export const ItemIcon = styled(Img)` - fill: ${theme('editor.content')}; - width: 17px; - height: 17px; - margin-right: 3px; - margin-top: 2px; - - ${Item}:hover & { - fill: ${theme('editor.footerHover')}; - } -` diff --git a/src/containers/editor/PostEditor/styles/header.ts b/src/containers/editor/PostEditor/styles/header.ts deleted file mode 100755 index 66847008a..000000000 --- a/src/containers/editor/PostEditor/styles/header.ts +++ /dev/null @@ -1,57 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme } from '@/utils/themes' -import css from '@/utils/css' - -export const Wrapper = styled.div` - ${css.flex()}; - margin-left: 35px; - margin-right: 35px; - padding-top: 15px; - margin-bottom: 10px; -` - -export const UsageText = styled.div` - ${css.flexGrow('align-center')}; - color: ${theme('editor.content')}; - font-size: 1.3em; -` - -export const AtSignIcon = styled(Img)` - fill: ${theme('editor.content')}; - ${css.size(15)}; - margin-left: 5px; - margin-right: 3px; -` - -export const RefUsersWrapper = styled.div` - ${css.flex('align-center')}; -` -export const RefUserList = styled.div` - margin-top: -10px; -` -export const MarkDownHint = styled.div` - ${css.flex()}; - color: ${theme('editor.placeholder')}; - &:hover { - color: ${theme('editor.content')}; - cursor: pointer; - } - transition: color 0.3s; -` -export const MarkdownIcon = styled(Img)` - fill: #51abb2; - width: 20px; - height: 18px; - margin-right: 5px; - - ${MarkDownHint}:hover & { - fill: #618c92; - } -` -export const BackToEditHint = styled.div` - ${css.flex()}; - color: ${theme('editor.title')}; - cursor: pointer; -` diff --git a/src/containers/editor/PostEditor/styles/index.ts b/src/containers/editor/PostEditor/styles/index.ts deleted file mode 100755 index a2ca921f2..000000000 --- a/src/containers/editor/PostEditor/styles/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import styled from 'styled-components' - -import type { TActive } from '@/spec' -import Input from '@/components/Input' -import { theme } from '@/utils/themes' -import css from '@/utils/css' - -export const Wrapper = styled.div`` -export const ViewerWrapper = styled.div` - display: ${({ active }) => (active ? 'block' : 'none')}; -` -export const Header = styled.div` - ${css.flex()}; - margin-left: 35px; - margin-right: 35px; - padding-top: 15px; - margin-bottom: 10px; -` - -export const SourceLink = styled.div` - ${css.flex('justify-center')}; - width: 60%; -` -export const LinkInput = styled(Input)` - border: 1px solid; - border-color: ${theme('editor.border')}; - height: 20px; - line-height: 20px; - width: 50%; - font-size: 0.9em; - margin-top: -1px; - background: ${theme('editor.headerBg')}; - padding-left: 2px; - color: ${theme('editor.title')}; - - &:hover { - color: ${theme('editor.title')}; - border-color: ${theme('editor.headerBg')}; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.border')}; - } - &:focus { - color: ${theme('editor.title')}; - border-color: ${theme('editor.headerBg')}; - box-shadow: none; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.placeholder')}; - } -` -export const LinkLabel = styled.div` - font-size: 0.9em; - color: ${theme('editor.placeholder')}; - ${SourceLink}:hover & { - color: ${theme('editor.title')}; - } - transition: color 0.3s; -` diff --git a/src/containers/editor/PostEditor/styles/markdown_helper.ts b/src/containers/editor/PostEditor/styles/markdown_helper.ts deleted file mode 100755 index c650f2750..000000000 --- a/src/containers/editor/PostEditor/styles/markdown_helper.ts +++ /dev/null @@ -1,11 +0,0 @@ -import styled from 'styled-components' - -import { theme } from '@/utils/themes' - -export const Wrapper = styled.div` - background: ${theme('drawer.markdownHelperBg')}; - padding: 20px; - margin-left: 4%; - margin-right: 4%; -` -export const holder = 1 diff --git a/src/containers/editor/PostEditor/styles/preview.ts b/src/containers/editor/PostEditor/styles/preview.ts deleted file mode 100755 index f0bbe93a9..000000000 --- a/src/containers/editor/PostEditor/styles/preview.ts +++ /dev/null @@ -1,26 +0,0 @@ -import styled from 'styled-components' - -// BodyWrapper, BodyHeader, BackToEditBtn, PreviewHeader -import { theme } from '@/utils/themes' -import css from '@/utils/css' - -export { Wrapper } from './editor' - -export const Header = styled.div` - ${css.flex('justify-end')}; - margin-bottom: 10px; -` -export const PreviewHeader = styled.div` - color: ${theme('drawer.title')}; - margin-bottom: 15px; - padding-bottom: 10px; - text-align: center; - font-size: 1.5em; - align-self: center; - border-bottom: 1px solid; - border-bottom-color: ${theme('drawer.divider')}; - width: 80%; - min-height: 1.5em; -` - -export const BackToEditBtn = styled.div`` diff --git a/src/containers/editor/PostEditor/styles/radar_note.ts b/src/containers/editor/PostEditor/styles/radar_note.ts deleted file mode 100755 index fa0541a18..000000000 --- a/src/containers/editor/PostEditor/styles/radar_note.ts +++ /dev/null @@ -1,48 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme } from '@/utils/themes' -import css from '@/utils/css' - -export const Wrapper = styled.div` - ${css.flexColumn()}; - padding: 20px; - padding-top: 30px; -` -export const Title = styled.div` - font-size: 1rem; - color: ${theme('thread.articleTitle')}; -` -export const IconsWrapper = styled.div` - ${css.flex('justify-around')}; - margin-top: 20px; - background: ${theme('bodyBg')}; - padding: 20px 12px; -` -export const Site = styled.div` - ${css.flex('')}; -` -export const SiteIcon = styled(Img)` - ${css.size(40)}; - margin-right: 10px; -` - -export const SiteInfo = styled.div` - ${css.flexColumn()}; -` -export const SiteTitle = styled.div` - color: ${theme('thread.articleTitle')}; -` -export const SiteLink = styled.a` - text-decoration: underline; - color: ${theme('thread.articleDigest')}; - transition: color 0.3s; - &:hover { - text-decoration: underline; - color: ${theme('banner.title')}; - } -` -export const Footer = styled.div` - color: ${theme('thread.articleDigest')}; - margin-top: 80px; -` diff --git a/src/containers/editor/PostEditor/test_mentions.js b/src/containers/editor/PostEditor/test_mentions.js deleted file mode 100755 index 057a24b18..000000000 --- a/src/containers/editor/PostEditor/test_mentions.js +++ /dev/null @@ -1,37 +0,0 @@ -const mentions = [ - { - id: '0', - nickname: 'Matthew-Russell', - avatar: - 'https://pbs.twimg.com/profile_images/517863945/mattsailing_400x400.jpg', - }, - { - id: '1', - nickname: 'Julian-Krispel-Samsel', - avatar: 'https://avatars2.githubusercontent.com/u/1188186?v=3&s=400', - }, - { - id: '2', - nickname: 'Jyoti-Puri', - avatar: 'https://avatars0.githubusercontent.com/u/2182307?v=3&s=400', - }, - { - id: '3', - nickname: 'Max-Stoiber', - avatar: - 'https://pbs.twimg.com/profile_images/763033229993574400/6frGyDyA_400x400.jpg', - }, - { - id: '4', - nickname: 'Nik-Graf', - avatar: 'https://avatars0.githubusercontent.com/u/223045?v=3&s=400', - }, - { - id: '5', - nickname: 'Pascal-Brandt', - avatar: - 'https://pbs.twimg.com/profile_images/688487813025640448/E6O6I011_400x400.png', - }, -] - -export default mentions diff --git a/src/containers/editor/PostEditor/tests/index.test.ts b/src/containers/editor/PostEditor/tests/index.test.ts deleted file mode 100755 index 6753001c6..000000000 --- a/src/containers/editor/PostEditor/tests/index.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import React from 'react' -// import { shallow } from 'enzyme' - -// import PostEditor from '../index' - -describe('TODO ', () => { - it('Expect to have unit tests specified', () => { - expect(true).toEqual(true) - }) -}) diff --git a/src/containers/editor/PostEditor/tests/store.test.ts b/src/containers/editor/PostEditor/tests/store.test.ts deleted file mode 100755 index 02234f743..000000000 --- a/src/containers/editor/PostEditor/tests/store.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * PostEditor store test - * - */ - -// import PostEditor from '../index' - -it('TODO: store test PostEditor', () => { - expect(1 + 1).toBe(2) -}) diff --git a/src/containers/tool/Drawer/Content/renderContent.tsx b/src/containers/tool/Drawer/Content/renderContent.tsx index bb91cad66..8e34a91bc 100644 --- a/src/containers/tool/Drawer/Content/renderContent.tsx +++ b/src/containers/tool/Drawer/Content/renderContent.tsx @@ -9,8 +9,6 @@ import { MailsViewer, // editors AccountEditor, - PostEditor, - RepoEditor, // utils C11NSettingPanel, } from '../dynamics' @@ -22,14 +20,8 @@ const renderContent = (type: string, attUser: TUser, mmType?) => { case TYPE.DRAWER.ACCOUNT_EDIT: return - case TYPE.DRAWER.POST_CREATE: - return - - case TYPE.DRAWER.POST_EDIT: - return - - case TYPE.DRAWER.REPO_CREATE: - return + // case TYPE.DRAWER.REPO_CREATE: + // return case TYPE.DRAWER.MAILS_VIEW: return diff --git a/src/containers/tool/Drawer/dynamics.tsx b/src/containers/tool/Drawer/dynamics.tsx index ba94cdb0d..7dfbcd354 100755 --- a/src/containers/tool/Drawer/dynamics.tsx +++ b/src/containers/tool/Drawer/dynamics.tsx @@ -41,15 +41,10 @@ export const AccountEditor = dynamic( editorConfig, ) -export const PostEditor = dynamic( - () => import('@/containers/editor/PostEditor'), - editorConfig, -) - -export const RepoEditor = dynamic( - () => import('@/containers/editor/RepoEditor'), - editorConfig, -) +// export const RepoEditor = dynamic( +// () => import('@/containers/editor/RepoEditor'), +// editorConfig, +// ) // utils export const C11NSettingPanel = dynamic( diff --git a/src/stores/RootStore/index.ts b/src/stores/RootStore/index.ts index e9885c3db..a39db729b 100755 --- a/src/stores/RootStore/index.ts +++ b/src/stores/RootStore/index.ts @@ -44,7 +44,7 @@ import { // footer FooterStore, // viewers - RepoViewerStore, + // RepoViewerStore, CommentsStore, MailsViewerStore, @@ -52,8 +52,7 @@ import { DoraemonStore, DrawerStore, SidebarStore, - PostEditorStore, - RepoEditorStore, + // RepoEditorStore, AccountEditorStore, MailBoxStore, DocUploaderStore, @@ -121,8 +120,7 @@ const rootStore = T.model({ sidebar: T.optional(SidebarStore, { menuItems: [] }), drawer: T.optional(DrawerStore, { visible: false }), doraemon: T.optional(DoraemonStore, {}), - postEditor: T.optional(PostEditorStore, {}), - repoEditor: T.optional(RepoEditorStore, {}), + // repoEditor: T.optional(RepoEditorStore, {}), accountEditor: T.optional(AccountEditorStore, {}), mailBox: T.optional(MailBoxStore, {}), docUploader: T.optional(DocUploaderStore, {}), @@ -162,7 +160,6 @@ const rootStore = T.model({ cashier: T.optional(CashierStore, {}), // viewers (for drawer usage) - repoViewer: T.optional(RepoViewerStore, {}), mailsViewer: T.optional(MailsViewerStore, {}), // user page diff --git a/src/stores/RootStore/index2.ts b/src/stores/RootStore/index2.ts index 886491a6c..1c224bd3e 100755 --- a/src/stores/RootStore/index2.ts +++ b/src/stores/RootStore/index2.ts @@ -45,7 +45,6 @@ import { // footer FooterStore, // viewers - RepoViewerStore, CommentsStore, MailsViewerStore, @@ -53,8 +52,6 @@ import { DoraemonStore, DrawerStore, SidebarStore, - PostEditorStore, - RepoEditorStore, AccountEditorStore, MailBoxStore, DocUploaderStore, @@ -144,7 +141,6 @@ import { // // toolbox // import DocUploaderStore from '@/containers/tool/DocUploader/store' -// import PostEditorStore from '@/containers/editor/PostEditor/store' // import RepoEditorStore from '@/containers/editor/RepoEditor/store' // import CommentsStore from '@/containers/unit/Comments/store' // import AccountEditorStore from '@/containers/editor/AccountEditor/store' @@ -210,8 +206,6 @@ const rootStore = T.model({ drawer: T.optional(DrawerStore, { visible: false }), // gzip + 16kb // NOTE: 危险 doraemon: T.optional(DoraemonStore, {}), - postEditor: T.optional(PostEditorStore, {}), - repoEditor: T.optional(RepoEditorStore, {}), accountEditor: T.optional(AccountEditorStore, {}), mailBox: T.optional(MailBoxStore, {}), docUploader: T.optional(DocUploaderStore, {}), @@ -234,7 +228,6 @@ const rootStore = T.model({ girlVerifier: T.optional(GirlVerifierStore, {}), cashier: T.optional(CashierStore, {}), // viewers (for drawer usage) - repoViewer: T.optional(RepoViewerStore, {}), mailsViewer: T.optional(MailsViewerStore, {}), // user page userPublished: T.optional(UserPublishedStore, {}), diff --git a/src/stores/index.ts b/src/stores/index.ts index 886d6c65f..f2c3e0652 100755 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -55,8 +55,7 @@ export { default as TagsBarStore } from '@/containers/unit/TagsBar/store' // toolbox export { default as DocUploaderStore } from '@/containers/tool/DocUploader/store' -export { default as PostEditorStore } from '@/containers/editor/PostEditor/store' -export { default as RepoEditorStore } from '@/containers/editor/RepoEditor/store' +// export { default as RepoEditorStore } from '@/containers/editor/RepoEditor/store' export { default as CommentsStore } from '@/containers/unit/Comments/store' export { default as AccountEditorStore } from '@/containers/editor/AccountEditor/store' From 48e5bf8185281f90671be860d52a54d5d1522483 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 17:56:22 +0800 Subject: [PATCH 05/15] refactor(footer): move joinUS to footer item --- src/containers/unit/ArticleFooter/index.tsx | 3 +-- .../unit/Footer/DesktopView/ArticleLayout.tsx | 20 +++++----------- .../Footer/DesktopView/CommunityLayout.tsx | 23 ++++++------------- .../Footer/DesktopView/CoolGuideLayout.tsx | 20 +++++----------- .../Footer/DesktopView/WorksArticleLayout.tsx | 20 +++++----------- .../styles/desktop_view/article_layout.ts | 13 ++++++++++- .../styles/desktop_view/community_layout.ts | 2 ++ .../styles/desktop_view/cool_guide_layout.ts | 2 ++ .../desktop_view/works_article_layout.ts | 2 ++ 9 files changed, 44 insertions(+), 61 deletions(-) diff --git a/src/containers/unit/ArticleFooter/index.tsx b/src/containers/unit/ArticleFooter/index.tsx index 8c5819e3a..de1bb95e4 100755 --- a/src/containers/unit/ArticleFooter/index.tsx +++ b/src/containers/unit/ArticleFooter/index.tsx @@ -9,7 +9,6 @@ import { FC, useState } from 'react' import type { TCopyright } from '@/spec' import { buildLog } from '@/utils/logger' -import { joinUS } from '@/utils/helper' import { pluggedIn } from '@/utils/mobx' import CommunityTagSetter from '@/containers/tool/CommunityTagSetter' @@ -50,7 +49,7 @@ const ArticleFooterContainer: FC = ({ const [copyright, setCopyright] = useState('cc') return ( - joinUS()}> + diff --git a/src/containers/unit/Footer/DesktopView/ArticleLayout.tsx b/src/containers/unit/Footer/DesktopView/ArticleLayout.tsx index 1355111ab..b7bf91b7b 100755 --- a/src/containers/unit/Footer/DesktopView/ArticleLayout.tsx +++ b/src/containers/unit/Footer/DesktopView/ArticleLayout.tsx @@ -1,8 +1,9 @@ import { FC, memo } from 'react' import type { TArticle, TC11NLayout, TMetric } from '@/spec' -import { ISSUE_ADDR, API_SERVER_ADDR } from '@/config' +import { ISSUE_ADDR, GITHUB, API_SERVER_ADDR } from '@/config' import { METRIC } from '@/constant' +import { joinUS } from '@/utils/helper' import TopInfo from './TopInfo' import BottomInfo from './BottomInfo' @@ -13,6 +14,7 @@ import { MainInfos, BaseInfo, Item, + NoLinkItem, } from '../styles/desktop_view/article_layout' type TProps = { @@ -38,19 +40,9 @@ const BriefView: FC = ({ metric, article, layout }) => { > 创建社区 - - 加入我们 - - - OpenSource + joinUS()}>加入群聊 + + Github = ({ metric, layout }) => { > 创建社区 - - 加入我们 - - - OpenSource + joinUS()}>加入群聊 + + Github { @@ -31,19 +33,9 @@ const CoolGuideLayout: FC = () => { > 创建社区 - - 加入我们 - - - OpenSource + joinUS()}>加入群聊 + + Github = ({ viewingArticle }) => { > 创建社区 - - 加入我们 - - - OpenSource + joinUS()}>加入群聊 + + Github ` ${css.flexColumn('align-end')}; diff --git a/src/containers/unit/Footer/styles/desktop_view/cool_guide_layout.ts b/src/containers/unit/Footer/styles/desktop_view/cool_guide_layout.ts index 05500b132..09225aead 100755 --- a/src/containers/unit/Footer/styles/desktop_view/cool_guide_layout.ts +++ b/src/containers/unit/Footer/styles/desktop_view/cool_guide_layout.ts @@ -4,6 +4,8 @@ import { METRIC } from '@/constant' import { theme } from '@/utils/themes' import css from '@/utils/css' +export { NoLinkItem } from './article_layout' + export const Wrapper = styled.div` ${css.flexColumn('align-start')}; width: 100%; diff --git a/src/containers/unit/Footer/styles/desktop_view/works_article_layout.ts b/src/containers/unit/Footer/styles/desktop_view/works_article_layout.ts index e7911b556..6d9c412c2 100755 --- a/src/containers/unit/Footer/styles/desktop_view/works_article_layout.ts +++ b/src/containers/unit/Footer/styles/desktop_view/works_article_layout.ts @@ -4,6 +4,8 @@ import { METRIC } from '@/constant' import { theme } from '@/utils/themes' import css from '@/utils/css' +export { NoLinkItem } from './article_layout' + export const Wrapper = styled.div` ${css.flexColumn('align-end')}; width: 100%; From e381962249fa857f8384b4e495963779268ed169 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 22:46:38 +0800 Subject: [PATCH 06/15] refactor(upvote): re-org post action workflow --- src/components/Upvote/ArticleLayout.tsx | 5 +-- src/components/Upvote/BlogListLayout.tsx | 4 ++- src/components/Upvote/CommentLayout.tsx | 6 ++-- src/components/Upvote/DefaultLayout.tsx | 4 ++- src/components/Upvote/PostListLayout.tsx | 4 ++- src/components/Upvote/UpvoteBtn.tsx | 11 +++--- src/components/Upvote/WorksArticleLayout.tsx | 3 ++ src/components/Upvote/WorksCardLayout.tsx | 6 ++-- src/components/Upvote/index.tsx | 1 + .../RightSticker/DefaultSticker.tsx | 9 +++-- .../ArticleSticker/RightSticker/index.tsx | 3 +- src/containers/tool/ArticleSticker/logic.ts | 26 +++++++++++++- src/containers/tool/ArticleSticker/schema.ts | 34 +++++++++++++++---- src/containers/tool/ArticleSticker/store.ts | 10 +++++- src/containers/tool/CollectionFolder/logic.ts | 3 +- src/spec/article.ts | 1 + src/stores/ViewingStore/index.ts | 17 ++++++++++ utils/async/methods.js | 5 +-- 18 files changed, 119 insertions(+), 33 deletions(-) diff --git a/src/components/Upvote/ArticleLayout.tsx b/src/components/Upvote/ArticleLayout.tsx index 5b4d9e8ce..1e00dcbf0 100644 --- a/src/components/Upvote/ArticleLayout.tsx +++ b/src/components/Upvote/ArticleLayout.tsx @@ -21,14 +21,14 @@ type TProps = { testid?: string count?: number viewerHasUpvoted?: boolean - alias?: string // 觉得很赞(default), 觉得很酷(works), 学到了(blog), 感兴趣(meetup), 有意思(Radar) + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ testid = 'upvote', count = 0, viewerHasUpvoted = false, - alias = '觉得很赞', + onAction = log, }) => { return ( @@ -36,6 +36,7 @@ const Upvote: FC = ({ diff --git a/src/components/Upvote/BlogListLayout.tsx b/src/components/Upvote/BlogListLayout.tsx index 28ade841a..b80d18d00 100644 --- a/src/components/Upvote/BlogListLayout.tsx +++ b/src/components/Upvote/BlogListLayout.tsx @@ -20,17 +20,19 @@ type TProps = { testid?: string count?: number viewerHasUpvoted?: boolean + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ testid = 'upvote', count = 0, viewerHasUpvoted = false, + onAction = log, }) => { return ( - + diff --git a/src/components/Upvote/CommentLayout.tsx b/src/components/Upvote/CommentLayout.tsx index 7729b8169..d19114897 100644 --- a/src/components/Upvote/CommentLayout.tsx +++ b/src/components/Upvote/CommentLayout.tsx @@ -20,19 +20,19 @@ type TProps = { testid?: string count?: number viewerHasUpvoted?: boolean - alias?: string // 觉得很赞(default), 觉得很酷(works), 学到了(blog), 感兴趣(meetup), 有意思(Radar) + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ testid = 'upvote', count = 0, viewerHasUpvoted = false, - alias = '觉得很赞', + onAction = log, }) => { return ( - + diff --git a/src/components/Upvote/DefaultLayout.tsx b/src/components/Upvote/DefaultLayout.tsx index 920b64caa..27718548f 100644 --- a/src/components/Upvote/DefaultLayout.tsx +++ b/src/components/Upvote/DefaultLayout.tsx @@ -26,6 +26,7 @@ type TProps = { viewerHasUpvoted?: boolean alias?: string // 觉得很赞(default), 觉得很酷(works), 学到了(blog), 感兴趣(meetup), 有意思(Radar) avatarList?: TUser[] + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ @@ -34,13 +35,14 @@ const Upvote: FC = ({ viewerHasUpvoted = false, avatarsRowLimit = 3, alias = '觉得很赞', + onAction = log, avatarList, }) => { const noOne = count === 0 return ( - + {!noOne && } diff --git a/src/components/Upvote/PostListLayout.tsx b/src/components/Upvote/PostListLayout.tsx index a5f21af02..2348a91e8 100644 --- a/src/components/Upvote/PostListLayout.tsx +++ b/src/components/Upvote/PostListLayout.tsx @@ -20,17 +20,19 @@ type TProps = { testid?: string count?: number viewerHasUpvoted?: boolean + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ testid = 'upvote', count = 0, viewerHasUpvoted = false, + onAction = log, }) => { return ( - + diff --git a/src/components/Upvote/UpvoteBtn.tsx b/src/components/Upvote/UpvoteBtn.tsx index a2067a893..702cc0b35 100644 --- a/src/components/Upvote/UpvoteBtn.tsx +++ b/src/components/Upvote/UpvoteBtn.tsx @@ -6,7 +6,7 @@ import { FC, memo, useState, useCallback } from 'react' -import type { TUser, TUpvoteLayout } from '@/spec' +import type { TUpvoteLayout } from '@/spec' import { buildLog } from '@/utils/logger' import { @@ -23,22 +23,21 @@ import { const log = buildLog('c:Upvote:index') type TProps = { - testid?: string type?: TUpvoteLayout - num?: number viewerHasUpvoted?: boolean - alias?: string - avatarList?: TUser[] + onAction: (viewerHasUpvoted: boolean) => void } const UpvoteBtn: FC = ({ type = 'default', viewerHasUpvoted = false, + onAction, }) => { const [showAnimation, setShowAnimation] = useState(false) const [num, setNum] = useState(0) const handleClick = useCallback(() => { + onAction(!viewerHasUpvoted) if (viewerHasUpvoted) return setNum(num + 1) @@ -47,7 +46,7 @@ const UpvoteBtn: FC = ({ setTimeout(() => setShowAnimation(false), 950) } - }, [showAnimation, viewerHasUpvoted, num]) + }, [showAnimation, viewerHasUpvoted, num, onAction]) return ( diff --git a/src/components/Upvote/WorksArticleLayout.tsx b/src/components/Upvote/WorksArticleLayout.tsx index a2d3959d0..34fcbd4ec 100644 --- a/src/components/Upvote/WorksArticleLayout.tsx +++ b/src/components/Upvote/WorksArticleLayout.tsx @@ -34,6 +34,7 @@ type TProps = { avatarsRowLimit?: number alias?: string // 觉得很赞(default), 觉得很酷(works), 学到了(blog), 感兴趣(meetup), 有意思(Radar) avatarList?: TUser[] + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ @@ -43,6 +44,7 @@ const Upvote: FC = ({ avatarsRowLimit = 3, alias = '觉得很酷', avatarList, + onAction = log, }) => { const noOne = count === 0 @@ -52,6 +54,7 @@ const Upvote: FC = ({ diff --git a/src/components/Upvote/WorksCardLayout.tsx b/src/components/Upvote/WorksCardLayout.tsx index 65b521c8a..403f4f599 100644 --- a/src/components/Upvote/WorksCardLayout.tsx +++ b/src/components/Upvote/WorksCardLayout.tsx @@ -20,19 +20,19 @@ type TProps = { testid?: string count?: number viewerHasUpvoted?: boolean - alias?: string // 觉得很赞(default), 觉得很酷(works), 学到了(blog), 感兴趣(meetup), 有意思(Radar) + onAction?: (viewerHasUpvoted: boolean) => void } const Upvote: FC = ({ testid = 'upvote', count = 0, viewerHasUpvoted = false, - alias = '觉得很赞', + onAction = log, }) => { return ( - + diff --git a/src/components/Upvote/index.tsx b/src/components/Upvote/index.tsx index c002c2b96..176ebc2b5 100755 --- a/src/components/Upvote/index.tsx +++ b/src/components/Upvote/index.tsx @@ -29,6 +29,7 @@ type TProps = { viewerHasUpvoted?: boolean alias?: string // 觉得很赞(default), 觉得很酷(works), 学到了(blog), 感兴趣(meetup), 有意思(Radar) avatarList?: TUser[] + onAction?: (did: boolean) => void } const Upvote: FC = ({ type = UPVOTE_LAYOUT.DEFAULT, ...restProps }) => { diff --git a/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx b/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx index 69b8b8463..f8024f3fd 100644 --- a/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx +++ b/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx @@ -7,7 +7,7 @@ import IconButton from '@/components/Buttons/IconButton' import Upvote from '@/components/Upvote' import { Wrapper } from '../styles/right_sticker/default_sticker' -import { collectArticle } from '../logic' +import { collectArticle, handleUpvote } from '../logic' type TProps = { show: boolean @@ -17,7 +17,12 @@ type TProps = { const ArticleSticker: FC = ({ show, article }) => { return ( - + handleUpvote(did)} + /> { }) } +export const handleUpvote = (viewerHasUpvoted: boolean): void => { + store.updateUpvote(viewerHasUpvoted) + const { id, meta } = store.viewingArticle + + const upvoteSchema = S[`upvote${titleCase(meta.thread)}`] + const undoUpvoteSchema = S[`undoUpvote${titleCase(meta.thread)}`] + viewerHasUpvoted + ? sr71$.mutate(upvoteSchema, { id }) + : sr71$.mutate(undoUpvoteSchema, { id }) +} + export const loadPagedCommentsParticipants = (): void => { const { viewingArticle: article } = store @@ -43,6 +54,11 @@ export const loadPagedCommentsParticipants = (): void => { sr71$.query(S.pagedCommentsParticipants, args) } +// update the real upvoteCount after upvote action +const handleUovoteAfter = ({ upvotesCount }) => { + store.updateUpvoteCount(upvotesCount) +} + const DataSolver = [ { match: asyncRes('pagedCommentsParticipants'), @@ -50,6 +66,14 @@ const DataSolver = [ store.mark({ pagedCommentsParticipants }) }, }, + { + match: asyncRes('upvotePost'), + action: ({ upvotePost }) => handleUovoteAfter(upvotePost), + }, + { + match: asyncRes('undoUpvotePost'), + action: ({ undoUpvotePost }) => handleUovoteAfter(undoUpvotePost), + }, ] const ErrSolver = [] diff --git a/src/containers/tool/ArticleSticker/schema.ts b/src/containers/tool/ArticleSticker/schema.ts index 9316e0bae..068119506 100644 --- a/src/containers/tool/ArticleSticker/schema.ts +++ b/src/containers/tool/ArticleSticker/schema.ts @@ -2,19 +2,39 @@ import { gql } from '@urql/core' import { F } from '@/schemas' const pagedCommentsParticipants = gql` -query($id: ID!, $thread: Thread, $filter: PagedFilter!) { - pagedCommentsParticipants(id: $id, thread: $thread, filter: $filter) { - entries { - ${F.author} + query($id: ID!, $thread: Thread, $filter: PagedFilter!) { + pagedCommentsParticipants(id: $id, thread: $thread, filter: $filter) { + entries { + ${F.author} + } + ${F.pagedCounts} + + } + } +` + +const upvotePost = gql` + mutation ($id: ID!) { + upvotePost(id: $id) { + id + upvotesCount + } + } +` + +const undoUpvotePost = gql` + mutation ($id: ID!) { + undoUpvotePost(id: $id) { + id + upvotesCount } - ${F.pagedCounts} - } -} ` const schema = { pagedCommentsParticipants, + upvotePost, + undoUpvotePost, } export default schema diff --git a/src/containers/tool/ArticleSticker/store.ts b/src/containers/tool/ArticleSticker/store.ts index b100ccd61..27c24d48b 100755 --- a/src/containers/tool/ArticleSticker/store.ts +++ b/src/containers/tool/ArticleSticker/store.ts @@ -25,7 +25,7 @@ const ArticleSticker = T.model('ArticleSticker', { .views((self) => ({ get viewingArticle(): TArticle { const root = getParent(self) as TRootStore - return root.viewing.viewingArticle + return toJS(root.viewing.viewingArticle) }, get activeThread(): TThread { const root = getParent(self) as TRootStore @@ -73,6 +73,14 @@ const ArticleSticker = T.model('ArticleSticker', { }, })) .actions((self) => ({ + updateUpvote(viewerHasUpvoted: boolean): void { + const root = getParent(self) as TRootStore + return root.viewing.updateUpvote(viewerHasUpvoted) + }, + updateUpvoteCount(count: number): void { + const root = getParent(self) as TRootStore + return root.viewing.updateUpvoteCount(count) + }, mark(sobj: Record): void { markStates(sobj, self) }, diff --git a/src/containers/tool/CollectionFolder/logic.ts b/src/containers/tool/CollectionFolder/logic.ts index 4591c825c..8bc9893fa 100755 --- a/src/containers/tool/CollectionFolder/logic.ts +++ b/src/containers/tool/CollectionFolder/logic.ts @@ -205,7 +205,8 @@ const ErrSolver = [ { match: asyncErr(ERR.GRAPHQL), action: ({ details }) => { - store.changesetErr({ title: '已经存在了', msg: details[0].detail }) + console.log('collection folder TODO') + // store.changesetErr({ title: '已经存在了', msg: details[0].detail }) markLoading(false) }, }, diff --git a/src/spec/article.ts b/src/spec/article.ts index 5a881b857..fdc30bffa 100644 --- a/src/spec/article.ts +++ b/src/spec/article.ts @@ -38,6 +38,7 @@ type TBaseArticle = { insertedAt?: string updatedAt?: string viewerHasViewed?: boolean + viewerHasUpvoted?: boolean commentsCount?: number articleTags?: TTag[] meta?: TArticleMeta diff --git a/src/stores/ViewingStore/index.ts b/src/stores/ViewingStore/index.ts index fd7f967e3..4faddb43f 100755 --- a/src/stores/ViewingStore/index.ts +++ b/src/stores/ViewingStore/index.ts @@ -66,6 +66,23 @@ const ViewingStore = T.model('ViewingStore', { const { mark, viewingThread } = self as TStore mark({ [viewingThread]: {}, viewingThread: null }) }, + updateUpvote(viewerHasUpvoted: boolean): void { + const { currentThread } = self as TStore + + if (viewerHasUpvoted) { + self[currentThread].upvotesCount += 1 + self[currentThread].viewerHasUpvoted = true + } else { + self[currentThread].upvotesCount -= 1 + self[currentThread].viewerHasUpvoted = false + } + }, + updateUpvoteCount(count: number): void { + const { currentThread } = self as TStore + if (self[currentThread].upvotesCount !== count) { + self[currentThread].upvotesCount = count + } + }, updateViewingIfNeed(type, sobj): void { const { updateViewingUser } = self as TStore diff --git a/utils/async/methods.js b/utils/async/methods.js index 05d28598e..b6ee56093 100755 --- a/utils/async/methods.js +++ b/utils/async/methods.js @@ -23,13 +23,14 @@ const doQuery = (query, variables) => { const doMutate = (mutation, variables) => { return gqClient - .mutate(mutation, variables) + .mutation(mutation, variables) .toPromise() .then((res) => { + if (res.error) return formatGraphErrors(res.error) + return res.data // once login user has mutation to server // then clear all the cache store in Apollo client. // client.clearStore() - return res.data }) .catch(formatGraphErrors) } From 8d1af3ae074ae537846b66db3a5ad9746074c1cd Mon Sep 17 00:00:00 2001 From: mydearxym Date: Tue, 5 Oct 2021 23:01:32 +0800 Subject: [PATCH 07/15] refactor(upvote): re-org general schema-thread logic --- src/containers/tool/ArticleSticker/logic.ts | 10 +++--- src/containers/tool/ArticleSticker/schema.ts | 37 +++++++++++--------- 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/containers/tool/ArticleSticker/logic.ts b/src/containers/tool/ArticleSticker/logic.ts index 4cefc2da9..0d36d5c30 100755 --- a/src/containers/tool/ArticleSticker/logic.ts +++ b/src/containers/tool/ArticleSticker/logic.ts @@ -2,7 +2,7 @@ import { useEffect } from 'react' // import { } from 'ramda' import { EVENT } from '@/constant' -import { send, titleCase } from '@/utils/helper' +import { send } from '@/utils/helper' import { buildLog } from '@/utils/logger' import asyncSuit from '@/utils/async' @@ -35,11 +35,9 @@ export const handleUpvote = (viewerHasUpvoted: boolean): void => { store.updateUpvote(viewerHasUpvoted) const { id, meta } = store.viewingArticle - const upvoteSchema = S[`upvote${titleCase(meta.thread)}`] - const undoUpvoteSchema = S[`undoUpvote${titleCase(meta.thread)}`] viewerHasUpvoted - ? sr71$.mutate(upvoteSchema, { id }) - : sr71$.mutate(undoUpvoteSchema, { id }) + ? sr71$.mutate(S.getUpvoteSchema(meta.thread), { id }) + : sr71$.mutate(S.getUndoUpvoteSchema(meta.thread), { id }) } export const loadPagedCommentsParticipants = (): void => { @@ -50,7 +48,7 @@ export const loadPagedCommentsParticipants = (): void => { thread: article.meta.thread, filter: { page: 1, size: 20 }, } - console.log('query args: ', args) + log('load comments query args: ', args) sr71$.query(S.pagedCommentsParticipants, args) } diff --git a/src/containers/tool/ArticleSticker/schema.ts b/src/containers/tool/ArticleSticker/schema.ts index 068119506..6f9ba22c5 100644 --- a/src/containers/tool/ArticleSticker/schema.ts +++ b/src/containers/tool/ArticleSticker/schema.ts @@ -1,5 +1,6 @@ import { gql } from '@urql/core' import { F } from '@/schemas' +import { titleCase } from '@/utils/helper' const pagedCommentsParticipants = gql` query($id: ID!, $thread: Thread, $filter: PagedFilter!) { @@ -13,28 +14,32 @@ const pagedCommentsParticipants = gql` } ` -const upvotePost = gql` - mutation ($id: ID!) { - upvotePost(id: $id) { - id - upvotesCount +const getUpvoteSchema = (thread) => { + return gql` + mutation ($id: ID!) { + upvote${titleCase(thread)}(id: $id) { + id + upvotesCount + } } - } -` + ` +} -const undoUpvotePost = gql` - mutation ($id: ID!) { - undoUpvotePost(id: $id) { - id - upvotesCount +const getUndoUpvoteSchema = (thread) => { + return gql` + mutation ($id: ID!) { + undoUpvote${titleCase(thread)}(id: $id) { + id + upvotesCount + } } - } -` + ` +} const schema = { pagedCommentsParticipants, - upvotePost, - undoUpvotePost, + getUpvoteSchema, + getUndoUpvoteSchema, } export default schema From 8b242bded388ef88856c68331dc40939359e16e1 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 7 Oct 2021 14:38:15 +0800 Subject: [PATCH 08/15] refactor(upvote): ux enhance, wip --- src/components/Upvote/CommentLayout.tsx | 2 +- .../ArticleDigest/DesktopView/FixedHeader.tsx | 8 ++- .../post_layout/original_community.ts | 5 +- src/containers/layout/GlobalLayout/index.tsx | 5 +- src/containers/layout/GlobalLayout/logic.ts | 11 +++ src/containers/layout/GlobalLayout/store.ts | 4 ++ .../RightSticker/DefaultSticker.tsx | 2 +- src/containers/tool/ArticleSticker/logic.ts | 4 +- src/containers/tool/ArticleSticker/store.ts | 4 ++ .../Comment/DesktopView/DefaultLayout.tsx | 9 ++- src/containers/unit/Comments/logic.ts | 72 +++++++++++-------- src/containers/unit/Comments/schema.ts | 50 +++++-------- src/containers/unit/Comments/store.ts | 32 +++++++-- .../styles/comment/desktop_view/index.ts | 3 +- src/schemas/fragments/base.ts | 1 + src/spec/article.ts | 1 + src/stores/Model/Comment.ts | 1 + utils/constant/event.ts | 1 + utils/helper.ts | 12 ++-- 19 files changed, 140 insertions(+), 87 deletions(-) diff --git a/src/components/Upvote/CommentLayout.tsx b/src/components/Upvote/CommentLayout.tsx index d19114897..79797ccaa 100644 --- a/src/components/Upvote/CommentLayout.tsx +++ b/src/components/Upvote/CommentLayout.tsx @@ -35,7 +35,7 @@ const Upvote: FC = ({ - + ) diff --git a/src/containers/digest/ArticleDigest/DesktopView/FixedHeader.tsx b/src/containers/digest/ArticleDigest/DesktopView/FixedHeader.tsx index f92891604..e7d1710c2 100644 --- a/src/containers/digest/ArticleDigest/DesktopView/FixedHeader.tsx +++ b/src/containers/digest/ArticleDigest/DesktopView/FixedHeader.tsx @@ -50,7 +50,7 @@ const FixedHeader: FC = ({ metric = METRIC.ARTICLE, testid = 'article-fixed-header', }) => { - const { upvotesCount, meta } = article + const { upvotesCount, meta, viewerHasUpvoted } = article const thread = meta.thread.toLowerCase() as TThread return ( @@ -60,7 +60,11 @@ const FixedHeader: FC = ({ - + diff --git a/src/containers/digest/ArticleDigest/styles/desktop_view/post_layout/original_community.ts b/src/containers/digest/ArticleDigest/styles/desktop_view/post_layout/original_community.ts index b138d90b5..fa67ff458 100644 --- a/src/containers/digest/ArticleDigest/styles/desktop_view/post_layout/original_community.ts +++ b/src/containers/digest/ArticleDigest/styles/desktop_view/post_layout/original_community.ts @@ -7,9 +7,7 @@ import SiteLogo from '@/icons/CPLogo' export const Wrapper = styled.nav` ${css.flexColumn('align-both')}; - margin-top: 1px; - /* margin-left: 8px; - + /* ${css.media.laptopL` margin-left: -40px; `} */ @@ -30,5 +28,6 @@ export const Name = styled.div` export const JoinDesc = styled.div` color: ${theme('thread.articleDigest')}; font-size: 12px; + margin-top: 1px; margin-bottom: 10px; ` diff --git a/src/containers/layout/GlobalLayout/index.tsx b/src/containers/layout/GlobalLayout/index.tsx index 74c820430..d5cecbd64 100755 --- a/src/containers/layout/GlobalLayout/index.tsx +++ b/src/containers/layout/GlobalLayout/index.tsx @@ -26,7 +26,7 @@ import SEO from './SEO' import { CustomScroller, Sidebar, Footer, ModeLine } from './dynamic' import { Wrapper, InnerWrapper, BodyWrapper, ContentWrapper } from './styles' -import { onPageScrollDirhange, childrenWithProps } from './logic' +import { useInit, onPageScrollDirhange, childrenWithProps } from './logic' const Addon = dynamic(() => import('./Addon'), { ssr: false, @@ -52,7 +52,8 @@ const GlobalLayoutContainer: FC = ({ }) => { const { isMobile } = usePlatform() // load debug graph - // useInit(store, { isMobile }) + console.log('## G useInit') + useInit(store, { isMobile }) const { sidebarPin, c11n, curCommunity } = store const { bannerLayout } = c11n diff --git a/src/containers/layout/GlobalLayout/logic.ts b/src/containers/layout/GlobalLayout/logic.ts index 07f343783..1d91f4ddb 100755 --- a/src/containers/layout/GlobalLayout/logic.ts +++ b/src/containers/layout/GlobalLayout/logic.ts @@ -1,6 +1,8 @@ import React, { ReactNode, useEffect } from 'react' +import PubSub from 'pubsub-js' import type { TScrollDirection } from '@/spec' +import { EVENT } from '@/constant' import { buildLog } from '@/utils/logger' import type { TStore } from './store' @@ -67,6 +69,8 @@ export const childrenWithProps = ( }) } +const handleAuthWarning = (option): void => store.authWarning(option) + // ############################### // init & uninit // ############################### @@ -83,5 +87,12 @@ export const useInit = (_store: TStore, extra): void => { const { online, isMobile } = extra store.mark({ online, isMobile }) + + PubSub.unsubscribe(EVENT.AUTH_WARNING) + PubSub.subscribe(EVENT.AUTH_WARNING, (e, opt) => handleAuthWarning(opt)) + + return () => { + PubSub.unsubscribe(EVENT.AUTH_WARNING) + } }, [_store, extra]) } diff --git a/src/containers/layout/GlobalLayout/store.ts b/src/containers/layout/GlobalLayout/store.ts index 1e83ac8fd..86a9277c4 100755 --- a/src/containers/layout/GlobalLayout/store.ts +++ b/src/containers/layout/GlobalLayout/store.ts @@ -43,6 +43,10 @@ const GlobalLayout = T.model('GlobalLayoutStore', { }, })) .actions((self) => ({ + authWarning(options): void { + const root = getParent(self) as TRootStore + root.authWarning(options) + }, openDoraemon(): void { const root = getParent(self) as TRootStore root.openDoraemon() diff --git a/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx b/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx index f8024f3fd..8bcde7838 100644 --- a/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx +++ b/src/containers/tool/ArticleSticker/RightSticker/DefaultSticker.tsx @@ -21,7 +21,7 @@ const ArticleSticker: FC = ({ show, article }) => { count={article.upvotesCount} type="article" viewerHasUpvoted={article.viewerHasUpvoted} - onAction={(did) => handleUpvote(did)} + onAction={handleUpvote} /> { } export const handleUpvote = (viewerHasUpvoted: boolean): void => { + if (!store.isLogin) return authWarn({ hideToast: true }) + store.updateUpvote(viewerHasUpvoted) const { id, meta } = store.viewingArticle diff --git a/src/containers/tool/ArticleSticker/store.ts b/src/containers/tool/ArticleSticker/store.ts index 27c24d48b..a6da1bcee 100755 --- a/src/containers/tool/ArticleSticker/store.ts +++ b/src/containers/tool/ArticleSticker/store.ts @@ -23,6 +23,10 @@ const ArticleSticker = T.model('ArticleSticker', { isLeftStickerLocked: T.optional(T.boolean, false), }) .views((self) => ({ + get isLogin(): boolean { + const root = getParent(self) as TRootStore + return root.account.isLogin + }, get viewingArticle(): TArticle { const root = getParent(self) as TRootStore return toJS(root.viewing.viewingArticle) diff --git a/src/containers/unit/Comments/Comment/DesktopView/DefaultLayout.tsx b/src/containers/unit/Comments/Comment/DesktopView/DefaultLayout.tsx index 203ea4823..2fa8dfb90 100644 --- a/src/containers/unit/Comments/Comment/DesktopView/DefaultLayout.tsx +++ b/src/containers/unit/Comments/Comment/DesktopView/DefaultLayout.tsx @@ -28,7 +28,7 @@ import { BadgePopContent, IndentLine, } from '../../styles/comment/desktop_view' -import { foldComment } from '../../logic' +import { foldComment, handleUpvote } from '../../logic' const getSelection = () => { const selectText = Global.getSelection().toString() @@ -59,7 +59,12 @@ const DefaultLayout: FC = ({ data, tobeDeleteId, isReply = false }) => { - + handleUpvote(data, did)} + /> {isArticleAuthorUpvoted && ( 作者顶过} diff --git a/src/containers/unit/Comments/logic.ts b/src/containers/unit/Comments/logic.ts index 2a24bb088..e58644b74 100755 --- a/src/containers/unit/Comments/logic.ts +++ b/src/containers/unit/Comments/logic.ts @@ -1,12 +1,18 @@ import { useEffect } from 'react' import { curry, isEmpty, reject, equals } from 'ramda' -import type { TUser, TID } from '@/spec' +import type { TUser, TComment, TID } from '@/spec' import { EVENT, ERR } from '@/constant' import asyncSuit from '@/utils/async' import BStore from '@/utils/bstore' -import { send, countWords, extractMentions, errRescue } from '@/utils/helper' +import { + send, + countWords, + extractMentions, + errRescue, + authWarn, +} from '@/utils/helper' import { buildLog } from '@/utils/logger' import { scrollIntoEle } from '@/utils/dom' @@ -37,7 +43,7 @@ export const loadComments = (): void => { mode, filter: { page: 1, size: 20 }, } - console.log('query args: ', args) + log('query args: ', args) store.mark({ loading: true }) sr71$.query(S.pagedComments, args) } @@ -77,7 +83,7 @@ export const previewReply = (data): void => { } export const openInputBox = (): void => { - if (!store.isLogin) return store.authWarning({ hideToast: true }) + if (!store.isLogin) return authWarn({ hideToast: true }) initDraftTimmer() store.mark({ @@ -149,7 +155,7 @@ export const openUpdateEditor = (data): void => }) export const openReplyEditor = (data): void => { - if (!store.isLogin) return store.authWarning({}) + if (!store.isLogin) return authWarn({ hideToast: true }) initDraftTimmer() store.mark({ @@ -194,18 +200,29 @@ export const onModeChange = (mode: TMode): void => { * @param {comment.id} string * @returns */ -export const toggleLikeComment = (comment): void => { - if (!store.isLogin) return store.authWarning({}) - log('likeComment: ', comment) +export const handleUpvote = ( + comment: TComment, + viewerHasUpvoted: boolean, +): void => { + if (!store.isLogin) return authWarn({ hideToast: true }) + const { id, upvotesCount } = comment + + console.log('viewerHasUpvoted: ', comment) - if (comment.viewerHasLiked) { - return sr71$.mutate(S.undoLikeComment, { - id: comment.id, + if (viewerHasUpvoted) { + store.updateUpvote(comment, { + upvotesCount: upvotesCount + 1, + viewerHasUpvoted: !viewerHasUpvoted, + }) + sr71$.mutate(S.upvoteComment, { id }) + } else { + store.updateUpvote(comment, { + upvotesCount: upvotesCount - 1, + viewerHasUpvoted: !viewerHasUpvoted, }) + + sr71$.mutate(S.undoUpvoteComment, { id }) } - return sr71$.mutate(S.likeComment, { - id: comment.id, - }) } export const onUploadImageDone = (url: string): void => @@ -288,6 +305,7 @@ const DataSolver = [ match: asyncRes('pagedComments'), action: ({ pagedComments }) => { cancelLoading() + log('# pagedComments --> ', pagedComments) store.mark({ pagedComments, loading: false }) }, }, @@ -336,24 +354,18 @@ const DataSolver = [ }, }, { - match: asyncRes('likeComment'), - action: ({ likeComment }) => - store.updateOneComment(likeComment.id, likeComment), - }, - { - match: asyncRes('undoLikeComment'), - action: ({ undoLikeComment }) => - store.updateOneComment(undoLikeComment.id, undoLikeComment), - }, - { - match: asyncRes('dislikeComment'), - action: ({ dislikeComment }) => - store.updateOneComment(dislikeComment.id, dislikeComment), + match: asyncRes('upvoteComment'), + action: ({ upvoteComment }) => { + const { upvotesCount, viewerHasUpvoted } = upvoteComment + store.updateUpvote(upvoteComment, { upvotesCount, viewerHasUpvoted }) + }, }, { - match: asyncRes('undoDislikeComment'), - action: ({ undoDislikeComment }) => - store.updateOneComment(undoDislikeComment.id, undoDislikeComment), + match: asyncRes('undoUpvoteComment'), + action: ({ undoUpvoteComment }) => { + const { upvotesCount, viewerHasUpvoted } = undoUpvoteComment + store.updateUpvote(undoUpvoteComment, { upvotesCount, viewerHasUpvoted }) + }, }, { match: asyncRes('deleteComment'), diff --git a/src/containers/unit/Comments/schema.ts b/src/containers/unit/Comments/schema.ts index da33a6ac8..3d6ad77b0 100755 --- a/src/containers/unit/Comments/schema.ts +++ b/src/containers/unit/Comments/schema.ts @@ -41,7 +41,7 @@ const createComment = gql` ` const updateComment = gql` - mutation($thread: CmsThread!, $id: ID!, $body: String!) { + mutation ($thread: CmsThread!, $id: ID!, $body: String!) { updateComment(thread: $thread, id: $id, body: $body) { id body @@ -70,46 +70,30 @@ const replyComment = gql` } ` const deleteComment = gql` - mutation($thread: CmsThread, $id: ID!) { + mutation ($thread: CmsThread, $id: ID!) { deleteComment(thread: $thread, id: $id) { id } } ` -const likeComment = gql` - mutation($thread: CmsThread, $id: ID!) { - likeComment(thread: $thread, id: $id) { +const upvoteComment = gql` + mutation ($id: ID!) { + upvoteComment(id: $id) { id - viewerHasLiked - likesCount + upvotesCount + viewerHasUpvoted + replyToId } } ` -const undoLikeComment = gql` - mutation($thread: CmsThread, $id: ID!) { - undoLikeComment(thread: $thread, id: $id) { +const undoUpvoteComment = gql` + mutation ($id: ID!) { + undoUpvoteComment(id: $id) { id - viewerHasLiked - likesCount - } - } -` -const dislikeComment = gql` - mutation($thread: CmsThread, $id: ID!) { - dislikeComment(thread: $thread, id: $id) { - id - viewerHasDisliked - dislikesCount - } - } -` -const undoDislikeComment = gql` - mutation($thread: CmsThread, $id: ID!) { - undoDislikeComment(thread: $thread, id: $id) { - id - viewerHasDisliked - dislikesCount + upvotesCount + viewerHasUpvoted + replyToId } } ` @@ -129,10 +113,8 @@ const schema = { updateComment, replyComment, deleteComment, - likeComment, - undoLikeComment, - dislikeComment, - undoDislikeComment, + upvoteComment, + undoUpvoteComment, searchUsers, } diff --git a/src/containers/unit/Comments/store.ts b/src/containers/unit/Comments/store.ts index 0f9193055..255af5b81 100755 --- a/src/containers/unit/Comments/store.ts +++ b/src/containers/unit/Comments/store.ts @@ -27,8 +27,9 @@ import type { TRoute, TID, TPagedComments, + TComment, } from '@/spec' -import { TYPE } from '@/constant' +// import { TYPE } from '@/constant' import { markStates, toJS } from '@/utils/mobx' import { changeset } from '@/utils/validator' import { Comment, PagedComments, emptyPagi, Mention } from '@/model' @@ -164,10 +165,6 @@ const CommentsStore = T.model('CommentsStore', { }, })) .actions((self) => ({ - authWarning(options): void { - const root = getParent(self) as TRootStore - root.authWarning(options) - }, changesetErr(options): void { const root = getParent(self) as TRootStore root.changesetErr(options) @@ -225,6 +222,31 @@ const CommentsStore = T.model('CommentsStore', { // @ts-ignore self.pagedComments.entries[index] = merge(entries[index], comment) }, + updateUpvote(comment: TComment, info): void { + const { id, replyToId } = comment + const slf = self as TStore + const { entries } = slf.pagedCommentsData + + if (self.mode === MODE.REPLIES && replyToId) { + const parentIndex = findIndex(propEq('id', replyToId), entries) + if (parentIndex < 0) return + const parentComment = entries[parentIndex] + const replyIndex = findIndex(propEq('id', id), parentComment.replies) + if (replyIndex < 0) return + const replyComment = parentComment.replies[replyIndex] + self.pagedComments.entries[parentIndex].replies[replyIndex] = { + ...replyComment, + ...info, + } + } else { + // timeline & replies parent comment + const index = findIndex(propEq('id', id), entries) + + if (index < 0) return + // @ts-ignore + self.pagedComments.entries[index] = { ...entries[index], ...info } + } + }, mark(sobj: Record): void { markStates(sobj, self) }, diff --git a/src/containers/unit/Comments/styles/comment/desktop_view/index.ts b/src/containers/unit/Comments/styles/comment/desktop_view/index.ts index 47dbba42d..629abc82b 100644 --- a/src/containers/unit/Comments/styles/comment/desktop_view/index.ts +++ b/src/containers/unit/Comments/styles/comment/desktop_view/index.ts @@ -13,8 +13,7 @@ type TWrapper = { export const Wrapper = styled.div` position: relative; ${css.flex()}; - margin-left: 2px; - margin-right: 5px; + margin-left: 1px; padding-top: ${({ isPinned }) => (isPinned ? '24px' : '20px')}; position: relative; background: transparent; diff --git a/src/schemas/fragments/base.ts b/src/schemas/fragments/base.ts index 0eb949235..61d0ea94b 100755 --- a/src/schemas/fragments/base.ts +++ b/src/schemas/fragments/base.ts @@ -213,6 +213,7 @@ const commentFields = ` isArticleAuthor viewerHasUpvoted repliesCount + replyToId insertedAt updatedAt ` diff --git a/src/spec/article.ts b/src/spec/article.ts index fdc30bffa..c97d76c0d 100644 --- a/src/spec/article.ts +++ b/src/spec/article.ts @@ -122,6 +122,7 @@ export type TComment = { repliesCount?: number replies?: TComment[] replyTo?: TComment + replyToId?: TID upvotesCount?: number viewerHasUpvoted?: boolean isArticleAuthor?: boolean diff --git a/src/stores/Model/Comment.ts b/src/stores/Model/Comment.ts index 02a63ecc5..8703a1862 100755 --- a/src/stores/Model/Comment.ts +++ b/src/stores/Model/Comment.ts @@ -46,6 +46,7 @@ const commentBaseFields = () => { meta: T.optional(CommentMeta, {}), repliesCount: T.optional(T.number, 0), + replyToId: T.maybeNull(T.string), viewerHasUpvoted: T.maybeNull(T.boolean), ...timestampFields(), diff --git a/utils/constant/event.ts b/utils/constant/event.ts index cdc68b6c9..aea4f7cd7 100755 --- a/utils/constant/event.ts +++ b/utils/constant/event.ts @@ -6,6 +6,7 @@ const EVENT = { // error ERR_RESCUE: 'ERR_RESCUE', + AUTH_WARNING: 'AUTH_WARNING', LOGOUT: 'LOGOUT', // drawer DRAWER: { diff --git a/utils/helper.ts b/utils/helper.ts index 0e71c7b5c..9a1b64d61 100755 --- a/utils/helper.ts +++ b/utils/helper.ts @@ -58,10 +58,12 @@ export const sortByIndex = (source: TSORTABLE_ITEMS): TSORTABLE_ITEMS => sort((a, b) => a.index - b.index, source) /* eslint-disable */ -const log = (...args) => (data) => { - console.log.apply(null, args.concat([data])) - return data -} +const log = + (...args) => + (data) => { + console.log.apply(null, args.concat([data])) + return data + } /* eslint-enable */ // reference: https://blog.carbonfive.com/2017/12/20/easy-pipeline-debugging-with-curried-console-log/ @@ -190,6 +192,8 @@ export const setTag = (): void => { send(EVENT.SET_TAG, {}) } +export const authWarn = (option): void => send(EVENT.AUTH_WARNING, option) + /** * send preview article singal to Drawer */ From 03081487df7da29809b5bc4ad356e753ccf6a92b Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 7 Oct 2021 17:22:59 +0800 Subject: [PATCH 09/15] refactor(comment): emotion wip --- .../EmotionSelector/SelectedEmotions.tsx | 15 ++++++++--- src/components/EmotionSelector/UsersPanel.tsx | 14 +++++++--- src/components/EmotionSelector/index.tsx | 9 +++++-- .../unit/Comments/Comment/Footer.tsx | 26 ++++++++++++------- src/containers/unit/Comments/logic.ts | 23 ++++++++++------ src/spec/index.ts | 2 +- 6 files changed, 63 insertions(+), 26 deletions(-) diff --git a/src/components/EmotionSelector/SelectedEmotions.tsx b/src/components/EmotionSelector/SelectedEmotions.tsx index 2cccea3ac..1281df945 100644 --- a/src/components/EmotionSelector/SelectedEmotions.tsx +++ b/src/components/EmotionSelector/SelectedEmotions.tsx @@ -6,7 +6,7 @@ import { FC, memo, Fragment } from 'react' import { buildLog } from '@/utils/logger' import { keys } from 'ramda' -import type { TEmotion, TSimpleUser } from '@/spec' +import type { TEmotion, TSimpleUser, TEmotionType } from '@/spec' import { titleCase } from '@/utils/helper' import UsersPanel from './UsersPanel' @@ -21,18 +21,27 @@ const getEmotionName = (item): string => { type TProps = { emotions: TEmotion[] + onAction?: (name: TEmotionType, hasEmotioned: boolean) => void } -const SelectedEmotions: FC = ({ emotions }) => { +const SelectedEmotions: FC = ({ emotions, onAction }) => { return ( {emotions.map((item) => { const eName = getEmotionName(item) as string const count = item[`${eName}Count`] as number const users = item[`latest${titleCase(eName)}Users`] as TSimpleUser[] + const hasEmotioned = item[`viewerHas${titleCase(eName)}ed`] as boolean return ( - + ) })} diff --git a/src/components/EmotionSelector/UsersPanel.tsx b/src/components/EmotionSelector/UsersPanel.tsx index 24ec3e9e2..a05e66335 100644 --- a/src/components/EmotionSelector/UsersPanel.tsx +++ b/src/components/EmotionSelector/UsersPanel.tsx @@ -5,7 +5,7 @@ import { FC, memo } from 'react' import { buildLog } from '@/utils/logger' -import type { TSimpleUser } from '@/spec' +import type { TSimpleUser, TEmotionType } from '@/spec' import { ICON } from '@/config' import Tooltip from '@/components/Tooltip' @@ -28,9 +28,17 @@ type TProps = { name: string count: number users: TSimpleUser[] + hasEmotioned: boolean + onAction?: (name: TEmotionType, hasEmotioned: boolean) => void } -const UsersPanel: FC = ({ name, count, users }) => { +const UsersPanel: FC = ({ + name, + count, + users, + hasEmotioned, + onAction, +}) => { const showUnit = users.length > count const emotionIcon = ( @@ -55,7 +63,7 @@ const UsersPanel: FC = ({ name, count, users }) => { } noPadding > - + onAction(name as TEmotionType, hasEmotioned)}> {emotionIcon} diff --git a/src/components/EmotionSelector/index.tsx b/src/components/EmotionSelector/index.tsx index 6637a6f8c..0e8f4aea6 100755 --- a/src/components/EmotionSelector/index.tsx +++ b/src/components/EmotionSelector/index.tsx @@ -5,7 +5,7 @@ import { FC, memo } from 'react' import { values, reject, includes } from 'ramda' -import type { TEmotion } from '@/spec' +import type { TEmotion, TEmotionType } from '@/spec' import { buildLog } from '@/utils/logger' import { titleCase } from '@/utils/helper' import { EMOTION } from '@/constant' @@ -37,15 +37,20 @@ const emotionsCoverter = (selectedEmotions: TEmotion): TEmotion[] => { type TProps = { testid?: string emotions: TEmotion + onAction?: (name: TEmotionType, hasEmotioned: boolean) => void } const EmotionSelector: FC = ({ testid = 'emotion-selector', + onAction = log, emotions, }) => { return ( - + } trigger="click" noPadding> diff --git a/src/containers/unit/Comments/Comment/Footer.tsx b/src/containers/unit/Comments/Comment/Footer.tsx index 61a1b7a24..e6250f5df 100755 --- a/src/containers/unit/Comments/Comment/Footer.tsx +++ b/src/containers/unit/Comments/Comment/Footer.tsx @@ -1,6 +1,6 @@ import { FC, memo } from 'react' -import type { TAccount, TComment } from '@/spec' +import type { TComment } from '@/spec' import DotDivider from '@/components/DotDivider' import { SpaceGrow } from '@/components/Common' @@ -9,18 +9,26 @@ import EmotionSelector from '@/components/EmotionSelector' import Actions from './Actions' import { Wrapper } from '../styles/comment/footer' +import { handleEmotion } from '../logic' type TProps = { data: TComment } -const Footer: FC = ({ data }) => ( - - - - - - -) +const Footer: FC = ({ data }) => { + return ( + + + handleEmotion(data, name, hasEmotioned) + } + /> + + + + + ) +} export default memo(Footer) diff --git a/src/containers/unit/Comments/logic.ts b/src/containers/unit/Comments/logic.ts index e58644b74..0a49cba24 100755 --- a/src/containers/unit/Comments/logic.ts +++ b/src/containers/unit/Comments/logic.ts @@ -1,7 +1,7 @@ import { useEffect } from 'react' import { curry, isEmpty, reject, equals } from 'ramda' -import type { TUser, TComment, TID } from '@/spec' +import type { TUser, TComment, TID, TEmotionType } from '@/spec' import { EVENT, ERR } from '@/constant' import asyncSuit from '@/utils/async' @@ -194,11 +194,20 @@ export const onModeChange = (mode: TMode): void => { } /** - * toggle like action - * - * @param {object} comment - * @param {comment.id} string - * @returns + * toggle emotion action + */ +export const handleEmotion = ( + comment: TComment, + name: TEmotionType, + viewerHasEmotioned: boolean, +): void => { + console.log('handleEmotion comment: ', comment.id) + console.log('handleEmotion name: ', name) + console.log('handleEmotion viewerHasEmotioned: ', viewerHasEmotioned) +} + +/** + * toggle upvote action */ export const handleUpvote = ( comment: TComment, @@ -207,8 +216,6 @@ export const handleUpvote = ( if (!store.isLogin) return authWarn({ hideToast: true }) const { id, upvotesCount } = comment - console.log('viewerHasUpvoted: ', comment) - if (viewerHasUpvoted) { store.updateUpvote(comment, { upvotesCount: upvotesCount + 1, diff --git a/src/spec/index.ts b/src/spec/index.ts index 335a54680..91bc721ed 100644 --- a/src/spec/index.ts +++ b/src/spec/index.ts @@ -96,7 +96,7 @@ export type { export type { TAccountStore, TViewingStore } from './store' -export type { TEmotion } from './emotion' +export type { TEmotion, TEmotionType } from './emotion' export type TRoute = { communityPath?: string From a6a95f1f8771395a0092bafcd4cc3b082c04668d Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 7 Oct 2021 17:51:27 +0800 Subject: [PATCH 10/15] refactor(comment): emotion selector re-org --- .../EmotionSelector/SelectedEmotions.tsx | 51 ------------- .../SelectedEmotions/EmotionIcon.tsx | 16 ++++ .../SelectedEmotions/EmotionUnit.tsx | 56 ++++++++++++++ .../SelectedEmotions/UsersPanel.tsx | 43 +++++++++++ .../SelectedEmotions/helper.ts | 9 +++ .../SelectedEmotions/index.tsx | 32 ++++++++ src/components/EmotionSelector/UsersPanel.tsx | 76 ------------------- 7 files changed, 156 insertions(+), 127 deletions(-) delete mode 100644 src/components/EmotionSelector/SelectedEmotions.tsx create mode 100644 src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx create mode 100644 src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx create mode 100644 src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx create mode 100644 src/components/EmotionSelector/SelectedEmotions/helper.ts create mode 100644 src/components/EmotionSelector/SelectedEmotions/index.tsx delete mode 100644 src/components/EmotionSelector/UsersPanel.tsx diff --git a/src/components/EmotionSelector/SelectedEmotions.tsx b/src/components/EmotionSelector/SelectedEmotions.tsx deleted file mode 100644 index 1281df945..000000000 --- a/src/components/EmotionSelector/SelectedEmotions.tsx +++ /dev/null @@ -1,51 +0,0 @@ -/* - * EmojiSelector - */ - -import { FC, memo, Fragment } from 'react' -import { buildLog } from '@/utils/logger' -import { keys } from 'ramda' - -import type { TEmotion, TSimpleUser, TEmotionType } from '@/spec' -import { titleCase } from '@/utils/helper' - -import UsersPanel from './UsersPanel' - -/* eslint-disable-next-line */ -const log = buildLog('c:SelectedEmotions:index') - -const getEmotionName = (item): string => { - const eCountKey = keys(item)[0] as string - return eCountKey.split('Count')[0] -} - -type TProps = { - emotions: TEmotion[] - onAction?: (name: TEmotionType, hasEmotioned: boolean) => void -} - -const SelectedEmotions: FC = ({ emotions, onAction }) => { - return ( - - {emotions.map((item) => { - const eName = getEmotionName(item) as string - const count = item[`${eName}Count`] as number - const users = item[`latest${titleCase(eName)}Users`] as TSimpleUser[] - const hasEmotioned = item[`viewerHas${titleCase(eName)}ed`] as boolean - - return ( - - ) - })} - - ) -} - -export default memo(SelectedEmotions) diff --git a/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx b/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx new file mode 100644 index 000000000..91d0c3372 --- /dev/null +++ b/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx @@ -0,0 +1,16 @@ +import { FC, memo } from 'react' +import { ICON } from '@/config' + +import type { TEmotionType } from '@/spec' + +import { EIcon } from '../styles/users_panel' + +type TProps = { + name: TEmotionType +} + +const EmotionIcon: FC = ({ name }) => { + return +} + +export default memo(EmotionIcon) diff --git a/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx b/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx new file mode 100644 index 000000000..af2ee8405 --- /dev/null +++ b/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx @@ -0,0 +1,56 @@ +/* + * EmojiSelector + */ + +import { FC, memo } from 'react' +import { buildLog } from '@/utils/logger' + +import type { TEmotion, TSimpleUser, TEmotionType } from '@/spec' + +import { titleCase } from '@/utils/helper' +import Tooltip from '@/components/Tooltip' +import AnimatedCount from '@/components/AnimatedCount' + +import EmotionIcon from './EmotionIcon' +import UsersPanel from './UsersPanel' +import { getEmotionName } from './helper' + +import { Wrapper, Count } from '../styles/users_panel' + +/* eslint-disable-next-line */ +const log = buildLog('c:EmotionUnit:index') + +type TProps = { + item: TEmotion + onAction?: (name: TEmotionType, hasEmotioned: boolean) => void +} + +const EmotionUnit: FC = ({ item, onAction }) => { + const name = getEmotionName(item) + const count = item[`${name}Count`] as number + const users = item[`latest${titleCase(name)}Users`] as TSimpleUser[] + const hasEmotioned = item[`viewerHas${titleCase(name)}ed`] as boolean + + return ( + + } + noPadding + > + onAction(name as TEmotionType, hasEmotioned)}> + + + + + + + ) +} + +export default memo(EmotionUnit) diff --git a/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx b/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx new file mode 100644 index 000000000..05af9a143 --- /dev/null +++ b/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx @@ -0,0 +1,43 @@ +/* + * EmojiSelector + */ + +import { FC, memo } from 'react' +import { buildLog } from '@/utils/logger' + +import type { TSimpleUser, TEmotionType } from '@/spec' + +import EmotionIcon from './EmotionIcon' + +import { PopHint, PopUsers, Units, Username } from '../styles/users_panel' + +/* eslint-disable-next-line */ +const log = buildLog('c:UsersPanel:index') + +type TProps = { + name: TEmotionType + count: number + users: TSimpleUser[] + hasEmotioned: boolean +} + +const UsersPanel: FC = ({ name, count, users, hasEmotioned }) => { + const showUnit = users.length > count + + return ( + + + {users.slice(0, 5).map((u, index) => ( + + {u.nickname} + {users.length - 1 !== index ? ',' : ''} + + ))} + {showUnit && 等 {count} 人} + {' '} + + + ) +} + +export default memo(UsersPanel) diff --git a/src/components/EmotionSelector/SelectedEmotions/helper.ts b/src/components/EmotionSelector/SelectedEmotions/helper.ts new file mode 100644 index 000000000..f397ed084 --- /dev/null +++ b/src/components/EmotionSelector/SelectedEmotions/helper.ts @@ -0,0 +1,9 @@ +import { keys } from 'ramda' +import type { TEmotion, TEmotionType } from '@/spec' + +export const getEmotionName = (item: TEmotion): TEmotionType => { + const eCountKey = keys(item)[0] as string + return eCountKey.split('Count')[0] as TEmotionType +} + +export const holder = 1 diff --git a/src/components/EmotionSelector/SelectedEmotions/index.tsx b/src/components/EmotionSelector/SelectedEmotions/index.tsx new file mode 100644 index 000000000..f3e80d8f9 --- /dev/null +++ b/src/components/EmotionSelector/SelectedEmotions/index.tsx @@ -0,0 +1,32 @@ +/* + * EmojiSelector + */ + +import { FC, memo, Fragment } from 'react' +import { buildLog } from '@/utils/logger' + +import type { TEmotion, TEmotionType } from '@/spec' + +import EmotionUnit from './EmotionUnit' +import { getEmotionName } from './helper' +/* eslint-disable-next-line */ +const log = buildLog('c:SelectedEmotions:index') + +type TProps = { + emotions: TEmotion[] + onAction?: (name: TEmotionType, hasEmotioned: boolean) => void +} + +const SelectedEmotions: FC = ({ emotions, onAction }) => { + return ( + + {emotions.map((item) => { + const name = getEmotionName(item) as string + + return + })} + + ) +} + +export default memo(SelectedEmotions) diff --git a/src/components/EmotionSelector/UsersPanel.tsx b/src/components/EmotionSelector/UsersPanel.tsx deleted file mode 100644 index a05e66335..000000000 --- a/src/components/EmotionSelector/UsersPanel.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * EmojiSelector - */ - -import { FC, memo } from 'react' -import { buildLog } from '@/utils/logger' - -import type { TSimpleUser, TEmotionType } from '@/spec' -import { ICON } from '@/config' - -import Tooltip from '@/components/Tooltip' -import AnimatedCount from '@/components/AnimatedCount' - -import { - Wrapper, - EIcon, - PopHint, - PopUsers, - Count, - Units, - Username, -} from './styles/users_panel' - -/* eslint-disable-next-line */ -const log = buildLog('c:UsersPanel:index') - -type TProps = { - name: string - count: number - users: TSimpleUser[] - hasEmotioned: boolean - onAction?: (name: TEmotionType, hasEmotioned: boolean) => void -} - -const UsersPanel: FC = ({ - name, - count, - users, - hasEmotioned, - onAction, -}) => { - const showUnit = users.length > count - - const emotionIcon = ( - - ) - - return ( - - - {users.slice(0, 5).map((u, index) => ( - - {u.nickname} - {users.length - 1 !== index ? ',' : ''} - - ))} - {showUnit && 等 {count} 人} - {' '} - {emotionIcon} - - } - noPadding - > - onAction(name as TEmotionType, hasEmotioned)}> - {emotionIcon} - - - - - - ) -} - -export default memo(UsersPanel) From fd3c50d8f0481bf6b1a8131789ac3eb844820d89 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 7 Oct 2021 17:58:42 +0800 Subject: [PATCH 11/15] refactor(comment): emotion selector styles re-org --- .../SelectedEmotions/EmotionIcon.tsx | 3 +- .../SelectedEmotions/EmotionUnit.tsx | 2 +- .../SelectedEmotions/UsersPanel.tsx | 15 +++-- .../styles/selected_emotions/emotion_icon.ts | 15 +++++ .../styles/selected_emotions/emotion_unit.ts | 25 +++++++++ .../styles/selected_emotions/users_panel.ts | 25 +++++++++ .../EmotionSelector/styles/users_panel.ts | 55 ------------------- 7 files changed, 77 insertions(+), 63 deletions(-) create mode 100644 src/components/EmotionSelector/styles/selected_emotions/emotion_icon.ts create mode 100644 src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts create mode 100644 src/components/EmotionSelector/styles/selected_emotions/users_panel.ts delete mode 100644 src/components/EmotionSelector/styles/users_panel.ts diff --git a/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx b/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx index 91d0c3372..b73f47741 100644 --- a/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx +++ b/src/components/EmotionSelector/SelectedEmotions/EmotionIcon.tsx @@ -2,8 +2,7 @@ import { FC, memo } from 'react' import { ICON } from '@/config' import type { TEmotionType } from '@/spec' - -import { EIcon } from '../styles/users_panel' +import { EIcon } from '../styles/selected_emotions/emotion_icon' type TProps = { name: TEmotionType diff --git a/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx b/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx index af2ee8405..2d6cb742c 100644 --- a/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx +++ b/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx @@ -15,7 +15,7 @@ import EmotionIcon from './EmotionIcon' import UsersPanel from './UsersPanel' import { getEmotionName } from './helper' -import { Wrapper, Count } from '../styles/users_panel' +import { Wrapper, Count } from '../styles/selected_emotions/emotion_unit' /* eslint-disable-next-line */ const log = buildLog('c:EmotionUnit:index') diff --git a/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx b/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx index 05af9a143..7144b1c9b 100644 --- a/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx +++ b/src/components/EmotionSelector/SelectedEmotions/UsersPanel.tsx @@ -9,7 +9,12 @@ import type { TSimpleUser, TEmotionType } from '@/spec' import EmotionIcon from './EmotionIcon' -import { PopHint, PopUsers, Units, Username } from '../styles/users_panel' +import { + Wrapper, + UsersWrapper, + Units, + Username, +} from '../styles/selected_emotions/users_panel' /* eslint-disable-next-line */ const log = buildLog('c:UsersPanel:index') @@ -25,8 +30,8 @@ const UsersPanel: FC = ({ name, count, users, hasEmotioned }) => { const showUnit = users.length > count return ( - - + + {users.slice(0, 5).map((u, index) => ( {u.nickname} @@ -34,9 +39,9 @@ const UsersPanel: FC = ({ name, count, users, hasEmotioned }) => { ))} {showUnit && 等 {count} 人} - {' '} + {' '} - + ) } diff --git a/src/components/EmotionSelector/styles/selected_emotions/emotion_icon.ts b/src/components/EmotionSelector/styles/selected_emotions/emotion_icon.ts new file mode 100644 index 000000000..f5323a097 --- /dev/null +++ b/src/components/EmotionSelector/styles/selected_emotions/emotion_icon.ts @@ -0,0 +1,15 @@ +import styled from 'styled-components' + +import Img from '@/Img' +import css from '@/utils/css' + +export const EIcon = styled(Img)<{ name: string }>` + margin-top: ${({ name }) => (name === 'downvote' ? '2px' : 0)}; + ${({ name }) => + name === 'confused' || name === 'popcorn' ? css.size(15) : css.size(14)}; + margin-right: 6px; + + filter: saturate(0.6); + opacity: 0.9; +` +export const holder = 1 diff --git a/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts b/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts new file mode 100644 index 000000000..2e2e7efbd --- /dev/null +++ b/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts @@ -0,0 +1,25 @@ +import styled from 'styled-components' + +import css from '@/utils/css' + +export const Wrapper = styled.div` + ${css.flex('align-center')}; + cursor: pointer; + margin-right: 14px; + margin-right: 5px; + padding: 0 5px; + border-radius: 5px; + margin-left: -5px; + + &:hover { + background: #023c4a; + } +` + +export const Count = styled.div` + opacity: 0.8; + + ${Wrapper}:hover & { + color: #00a59b; + } +` diff --git a/src/components/EmotionSelector/styles/selected_emotions/users_panel.ts b/src/components/EmotionSelector/styles/selected_emotions/users_panel.ts new file mode 100644 index 000000000..d17c6018e --- /dev/null +++ b/src/components/EmotionSelector/styles/selected_emotions/users_panel.ts @@ -0,0 +1,25 @@ +import styled from 'styled-components' + +import { theme } from '@/utils/themes' +import css from '@/utils/css' + +export const Wrapper = styled.div` + ${css.flex('align-center')}; + padding: 3px 5px; + padding-left: 10px; +` +export const UsersWrapper = styled.div` + ${css.flex('align-center')}; + font-size: 13px; +` +export const Username = styled.div` + color: ${theme('thread.articleTitle')}; + font-size: 13px; + margin-right: 5px; +` +export const Units = styled.div` + color: ${theme('thread.articleDigest')}; + margin-left: 3px; + margin-right: 3px; + font-size: 13px; +` diff --git a/src/components/EmotionSelector/styles/users_panel.ts b/src/components/EmotionSelector/styles/users_panel.ts deleted file mode 100644 index a927dd8dd..000000000 --- a/src/components/EmotionSelector/styles/users_panel.ts +++ /dev/null @@ -1,55 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme } from '@/utils/themes' -import css from '@/utils/css' - -export const Wrapper = styled.div` - ${css.flex('align-center')}; - cursor: pointer; - margin-right: 14px; - margin-right: 5px; - padding: 0 5px; - border-radius: 5px; - margin-left: -5px; - - &:hover { - background: #023c4a; - } -` -export const EIcon = styled(Img)<{ name: string }>` - margin-top: ${({ name }) => (name === 'downvote' ? '2px' : 0)}; - ${({ name }) => - name === 'confused' || name === 'popcorn' ? css.size(15) : css.size(14)}; - margin-right: 6px; - - filter: saturate(0.6); - opacity: 0.9; -` -export const Count = styled.div` - opacity: 0.8; - - ${Wrapper}:hover & { - color: #00a59b; - } -` -export const PopHint = styled.div` - ${css.flex('align-center')}; - padding: 3px 5px; - padding-left: 10px; -` -export const PopUsers = styled.div` - ${css.flex('align-center')}; - font-size: 13px; -` -export const Username = styled.div` - color: ${theme('thread.articleTitle')}; - font-size: 13px; - margin-right: 5px; -` -export const Units = styled.div` - color: ${theme('thread.articleDigest')}; - margin-left: 3px; - margin-right: 3px; - font-size: 13px; -` From 66959f66588959c0fdd8e19c827b19ffc1ddb163 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 7 Oct 2021 22:01:23 +0800 Subject: [PATCH 12/15] refactor(emotion): basic action & panel style --- src/components/EmotionSelector/Panel.tsx | 36 +++++++++++++---- .../SelectedEmotions/EmotionUnit.tsx | 9 +++-- .../SelectedEmotions/helper.ts | 9 ----- .../SelectedEmotions/index.tsx | 2 +- src/components/EmotionSelector/helper.ts | 40 +++++++++++++++++++ src/components/EmotionSelector/index.tsx | 31 ++++---------- .../EmotionSelector/styles/panel.ts | 23 ++++++----- .../styles/selected_emotions/emotion_unit.ts | 4 +- src/containers/unit/Comments/logic.ts | 28 ++++++++++++- src/containers/unit/Comments/schema.ts | 35 +++++++++++++++- utils/constant/emotion.ts | 14 +++---- 11 files changed, 169 insertions(+), 62 deletions(-) delete mode 100644 src/components/EmotionSelector/SelectedEmotions/helper.ts create mode 100644 src/components/EmotionSelector/helper.ts diff --git a/src/components/EmotionSelector/Panel.tsx b/src/components/EmotionSelector/Panel.tsx index fdd7372c0..13d1c810e 100644 --- a/src/components/EmotionSelector/Panel.tsx +++ b/src/components/EmotionSelector/Panel.tsx @@ -1,8 +1,12 @@ import { FC, memo } from 'react' import { values } from 'ramda' +import type { TEmotion, TEmotionType } from '@/spec' + import { EMOTION } from '@/constant' import { ICON } from '@/config' + +import { isViewerEmotioned } from './helper' import { Wrapper, Item, EIcon, Name } from './styles/panel' const Trans = { @@ -14,15 +18,33 @@ const Trans = { pill: '药丸', } -const EmojiPanel: FC = () => { +type TProps = { + emotions: TEmotion[] + onAction?: (name: TEmotionType, hasEmotioned: boolean) => void +} + +const EmojiPanel: FC = ({ emotions, onAction }) => { return ( - {values(EMOTION).map((item) => ( - - - {Trans[item]} - - ))} + {values(EMOTION).map((name) => { + const viewerHasEmotioned = isViewerEmotioned(emotions, name) + + return ( + onAction(name, viewerHasEmotioned)} + > + + {Trans[name]} + + ) + })} ) } diff --git a/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx b/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx index 2d6cb742c..d1ada86e5 100644 --- a/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx +++ b/src/components/EmotionSelector/SelectedEmotions/EmotionUnit.tsx @@ -13,7 +13,7 @@ import AnimatedCount from '@/components/AnimatedCount' import EmotionIcon from './EmotionIcon' import UsersPanel from './UsersPanel' -import { getEmotionName } from './helper' +import { getEmotionName } from '../helper' import { Wrapper, Count } from '../styles/selected_emotions/emotion_unit' @@ -43,10 +43,13 @@ const EmotionUnit: FC = ({ item, onAction }) => { } noPadding > - onAction(name as TEmotionType, hasEmotioned)}> + onAction(name as TEmotionType, hasEmotioned)} + > - + diff --git a/src/components/EmotionSelector/SelectedEmotions/helper.ts b/src/components/EmotionSelector/SelectedEmotions/helper.ts deleted file mode 100644 index f397ed084..000000000 --- a/src/components/EmotionSelector/SelectedEmotions/helper.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { keys } from 'ramda' -import type { TEmotion, TEmotionType } from '@/spec' - -export const getEmotionName = (item: TEmotion): TEmotionType => { - const eCountKey = keys(item)[0] as string - return eCountKey.split('Count')[0] as TEmotionType -} - -export const holder = 1 diff --git a/src/components/EmotionSelector/SelectedEmotions/index.tsx b/src/components/EmotionSelector/SelectedEmotions/index.tsx index f3e80d8f9..9c7b9463e 100644 --- a/src/components/EmotionSelector/SelectedEmotions/index.tsx +++ b/src/components/EmotionSelector/SelectedEmotions/index.tsx @@ -7,8 +7,8 @@ import { buildLog } from '@/utils/logger' import type { TEmotion, TEmotionType } from '@/spec' +import { getEmotionName } from '../helper' import EmotionUnit from './EmotionUnit' -import { getEmotionName } from './helper' /* eslint-disable-next-line */ const log = buildLog('c:SelectedEmotions:index') diff --git a/src/components/EmotionSelector/helper.ts b/src/components/EmotionSelector/helper.ts new file mode 100644 index 000000000..ec33fa0a4 --- /dev/null +++ b/src/components/EmotionSelector/helper.ts @@ -0,0 +1,40 @@ +import { includes, reject, keys, values } from 'ramda' + +import { EMOTION } from '@/constant' +import type { TEmotion, TEmotionType } from '@/spec' +import { titleCase } from '@/utils/helper' + +export const getEmotionName = (item: TEmotion): TEmotionType => { + const eCountKey = keys(item)[0] as string + return eCountKey.split('Count')[0] as TEmotionType +} + +export const emotionsCoverter = (selectedEmotions: TEmotion): TEmotion[] => { + const converted = [] + values(EMOTION).forEach((emotion) => + converted.push({ + [`${emotion}Count`]: selectedEmotions[`${emotion}Count`], + [`latest${titleCase(emotion)}Users`]: + selectedEmotions[`latest${titleCase(emotion)}Users`], + [`viewerHas${titleCase(emotion)}ed`]: + selectedEmotions[`viewerHas${titleCase(emotion)}ed`], + }), + ) + + return reject((e) => includes(0, values(e)), converted) +} + +export const isViewerEmotioned = ( + emotions: TEmotion[], + name: TEmotionType, +): boolean => { + for (let i = 0; i < emotions.length; i += 1) { + const emotionUnit = emotions[i] + + if (emotionUnit[`viewerHas${titleCase(name)}ed`]) { + return true + } + } + + return false +} diff --git a/src/components/EmotionSelector/index.tsx b/src/components/EmotionSelector/index.tsx index 0e8f4aea6..308d6b409 100755 --- a/src/components/EmotionSelector/index.tsx +++ b/src/components/EmotionSelector/index.tsx @@ -3,15 +3,13 @@ */ import { FC, memo } from 'react' -import { values, reject, includes } from 'ramda' import type { TEmotion, TEmotionType } from '@/spec' import { buildLog } from '@/utils/logger' -import { titleCase } from '@/utils/helper' -import { EMOTION } from '@/constant' import IconButton from '@/components/Buttons/IconButton' import Tooltip from '@/components/Tooltip' +import { emotionsCoverter } from './helper' import SelectedEmotions from './SelectedEmotions' import Panel from './Panel' import { Wrapper } from './styles' @@ -19,21 +17,6 @@ import { Wrapper } from './styles' /* eslint-disable-next-line */ const log = buildLog('c:EmotionSelector:index') -const emotionsCoverter = (selectedEmotions: TEmotion): TEmotion[] => { - const converted = [] - values(EMOTION).forEach((emotion) => - converted.push({ - [`${emotion}Count`]: selectedEmotions[`${emotion}Count`], - [`latest${titleCase(emotion)}Users`]: - selectedEmotions[`latest${titleCase(emotion)}Users`], - [`viewerHas${titleCase(emotion)}ed`]: - selectedEmotions[`viewerHas${titleCase(emotion)}ed`], - }), - ) - - return reject((e) => includes(0, values(e)), converted) -} - type TProps = { testid?: string emotions: TEmotion @@ -45,13 +28,15 @@ const EmotionSelector: FC = ({ onAction = log, emotions, }) => { + const validEmotions = emotionsCoverter(emotions) return ( - - } trigger="click" noPadding> + + } + trigger="click" + noPadding + > diff --git a/src/components/EmotionSelector/styles/panel.ts b/src/components/EmotionSelector/styles/panel.ts index 55c6c9764..92eed7ef6 100644 --- a/src/components/EmotionSelector/styles/panel.ts +++ b/src/components/EmotionSelector/styles/panel.ts @@ -1,5 +1,7 @@ import styled from 'styled-components' +import { includes } from 'ramda' +import type { TActive } from '@/spec' import Img from '@/Img' import css from '@/utils/css' import { theme } from '@/utils/themes' @@ -14,13 +16,15 @@ export const Item = styled.div<{ name: string }>` ${css.flexColumn('align-center', 'justify-center')}; margin-right: ${({ name }) => (name === 'pill' ? 0 : '15px')}; ` -export const EIcon = styled(Img)<{ name: string }>` - margin-top: ${({ name }) => (name === 'downvote' ? '2px' : 0)}; - ${({ name }) => - name === 'confused' || name === 'popcorn' ? css.size(21) : css.size(20)}; +type TEIcon = { name: string } & TActive +export const EIcon = styled(Img)` + margin-top: ${({ name }) => + includes(name, ['downvote', 'beer']) ? '2px' : 0}; + margin-bottom: ${({ name }) => (name === 'heart' ? '1px' : 0)}; + ${({ name }) => (name === 'confused' ? css.size(21) : css.size(20))}; - filter: saturate(0.6); - opacity: 0.9; + filter: ${({ $active }) => ($active ? 'saturate(1)' : 'saturate(0.6)')}; + opacity: ${({ $active }) => ($active ? 1 : 0.9)}; z-index: 1; ${Item}:hover & { @@ -29,13 +33,14 @@ export const EIcon = styled(Img)<{ name: string }>` opacity: 1; } ` -export const Name = styled.div` +export const Name = styled.div` font-size: 11px; margin-top: 5px; - color: ${theme('thread.articleDigest')}; + color: ${({ $active }) => + $active ? '#12999B' : theme('thread.articleTitle')}; ${Item}:hover & { cursor: pointer; - color: ${theme('thread.articleTitle')}; + color: #12999b; } ` diff --git a/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts b/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts index 2e2e7efbd..aa6ed3884 100644 --- a/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts +++ b/src/components/EmotionSelector/styles/selected_emotions/emotion_unit.ts @@ -1,8 +1,9 @@ import styled from 'styled-components' +import type { TActive } from '@/spec' import css from '@/utils/css' -export const Wrapper = styled.div` +export const Wrapper = styled.div` ${css.flex('align-center')}; cursor: pointer; margin-right: 14px; @@ -10,6 +11,7 @@ export const Wrapper = styled.div` padding: 0 5px; border-radius: 5px; margin-left: -5px; + background: ${({ $active }) => ($active ? '#00333D' : 'transparent')}; &:hover { background: #023c4a; diff --git a/src/containers/unit/Comments/logic.ts b/src/containers/unit/Comments/logic.ts index 0a49cba24..14f71edd8 100755 --- a/src/containers/unit/Comments/logic.ts +++ b/src/containers/unit/Comments/logic.ts @@ -201,9 +201,21 @@ export const handleEmotion = ( name: TEmotionType, viewerHasEmotioned: boolean, ): void => { - console.log('handleEmotion comment: ', comment.id) + if (!store.isLogin) return authWarn({ hideToast: true }) + + const { id } = comment + console.log('handleEmotion comment: ', id) console.log('handleEmotion name: ', name) console.log('handleEmotion viewerHasEmotioned: ', viewerHasEmotioned) + const emotion = name.toUpperCase() + + if (viewerHasEmotioned) { + // instantFresh + sr71$.mutate(S.undoEmotionToComment, { id, emotion }) + } else { + // instantFresh + sr71$.mutate(S.emotionToComment, { id, emotion }) + } } /** @@ -374,6 +386,20 @@ const DataSolver = [ store.updateUpvote(undoUpvoteComment, { upvotesCount, viewerHasUpvoted }) }, }, + { + match: asyncRes('emotionToComment'), + action: ({ emotionToComment }) => { + console.log('emotionToComment -> ', emotionToComment) + // store.updateUpvote(undoUpvoteComment, { upvotesCount, viewerHasUpvoted }) + }, + }, + { + match: asyncRes('undoEmotionToComment'), + action: ({ undoEmotionToComment }) => { + console.log('undoEmotionToComment -> ', undoEmotionToComment) + // store.updateUpvote(undoUpvoteComment, { upvotesCount, viewerHasUpvoted }) + }, + }, { match: asyncRes('deleteComment'), action: ({ deleteComment }) => { diff --git a/src/containers/unit/Comments/schema.ts b/src/containers/unit/Comments/schema.ts index 3d6ad77b0..d24960c09 100755 --- a/src/containers/unit/Comments/schema.ts +++ b/src/containers/unit/Comments/schema.ts @@ -97,6 +97,37 @@ const undoUpvoteComment = gql` } } ` +const emotionToComment = gql` + mutation ($id: ID!, $emotion: CommentEmotion!) { + emotionToComment(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } +` +const undoEmotionToComment = gql` + mutation ($id: ID!, $emotion: CommentEmotion!) { + undoEmotionToComment(id: $id, emotion: $emotion) { + id + emotions { + beerCount + viewerHasBeered + latestBeerUsers { + login + nickname + } + } + } + } +` + const searchUsers = gql` query($name: String!) { searchUsers(name: $name) { @@ -113,9 +144,11 @@ const schema = { updateComment, replyComment, deleteComment, + searchUsers, upvoteComment, undoUpvoteComment, - searchUsers, + emotionToComment, + undoEmotionToComment, } export default schema diff --git a/utils/constant/emotion.ts b/utils/constant/emotion.ts index 0a22a3043..7c4be1d8c 100644 --- a/utils/constant/emotion.ts +++ b/utils/constant/emotion.ts @@ -1,12 +1,12 @@ -// import type { TMetric } from '@/spec' +import type { TEmotionType } from '@/spec' const EMOTION = { - DOWNVOTE: 'downvote', - BEER: 'beer', - HEART: 'heart', - CONFUSED: 'confused', - POPCORN: 'popcorn', - PILL: 'pill', + DOWNVOTE: 'downvote' as TEmotionType, + BEER: 'beer' as TEmotionType, + HEART: 'heart' as TEmotionType, + CONFUSED: 'confused' as TEmotionType, + POPCORN: 'popcorn' as TEmotionType, + PILL: 'pill' as TEmotionType, } export default EMOTION From 1cfa1bddf235f48361a2cbefc28b0c862f7ae706 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Thu, 7 Oct 2021 22:17:19 +0800 Subject: [PATCH 13/15] refactor(comment): style adjust --- src/components/ArtimentBody/FoldBox.tsx | 6 +++++- src/components/ArtimentBody/styles/fold_box.ts | 5 +++-- src/stores/Model/Comment.ts | 2 +- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/components/ArtimentBody/FoldBox.tsx b/src/components/ArtimentBody/FoldBox.tsx index 5a81d39f4..6f2dbe64d 100644 --- a/src/components/ArtimentBody/FoldBox.tsx +++ b/src/components/ArtimentBody/FoldBox.tsx @@ -12,7 +12,11 @@ type TProps = { const FoldBox: FC = ({ fold, onFold, onExpand, mode }) => { return ( - (fold ? onExpand() : onFold())}> + (fold ? onExpand() : onFold())} + > {!fold && ( 折叠 diff --git a/src/components/ArtimentBody/styles/fold_box.ts b/src/components/ArtimentBody/styles/fold_box.ts index d81c90901..3d3595323 100755 --- a/src/components/ArtimentBody/styles/fold_box.ts +++ b/src/components/ArtimentBody/styles/fold_box.ts @@ -4,9 +4,10 @@ import Img from '@/Img' // import { theme } from '@/utils/themes' import css from '@/utils/css' -export const Wrapper = styled.div<{ fold: boolean }>` +type TWrapper = { fold: boolean; mode: 'article' | 'comment' } +export const Wrapper = styled.div` ${css.flex('align-both')}; - width: 100%; + width: ${({ mode }) => (mode === 'article' ? '100%' : '96%')}; margin-top: 28px; margin-bottom: 28px; padding: 5px 0; diff --git a/src/stores/Model/Comment.ts b/src/stores/Model/Comment.ts index 8703a1862..a82380505 100755 --- a/src/stores/Model/Comment.ts +++ b/src/stores/Model/Comment.ts @@ -4,7 +4,7 @@ import { values, reduce, merge } from 'ramda' import { EMOTION } from '@/constant' import { titleCase } from '@/utils/helper' -import { User, SimpleUser } from './User' +import { SimpleUser } from './User' import { pagiFields, timestampFields } from './helper/common' From 3569ba2e5c091257c6042219261e835ad959e24f Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 8 Oct 2021 13:21:29 +0800 Subject: [PATCH 14/15] refactor(comment): emotion UX with server --- .../Upvote/styles/comment_layout.ts | 1 + src/containers/unit/Comments/logic.ts | 24 +++++++++++++++---- src/containers/unit/Comments/schema.ts | 14 +++++++++++ src/containers/unit/Comments/store.ts | 12 ++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/components/Upvote/styles/comment_layout.ts b/src/components/Upvote/styles/comment_layout.ts index 534932622..24003a422 100755 --- a/src/components/Upvote/styles/comment_layout.ts +++ b/src/components/Upvote/styles/comment_layout.ts @@ -12,6 +12,7 @@ export const Wrapper = styled.div.attrs(({ testid }: TTestable) => ({ }))` ${css.flexColumn('align-both')}; margin-left: -9px; + margin-top: 2px; ` export const UpWrapper = styled.div` margin-left: 7px; diff --git a/src/containers/unit/Comments/logic.ts b/src/containers/unit/Comments/logic.ts index 14f71edd8..f1ef97825 100755 --- a/src/containers/unit/Comments/logic.ts +++ b/src/containers/unit/Comments/logic.ts @@ -12,6 +12,7 @@ import { extractMentions, errRescue, authWarn, + titleCase, } from '@/utils/helper' import { buildLog } from '@/utils/logger' import { scrollIntoEle } from '@/utils/dom' @@ -204,15 +205,28 @@ export const handleEmotion = ( if (!store.isLogin) return authWarn({ hideToast: true }) const { id } = comment - console.log('handleEmotion comment: ', id) - console.log('handleEmotion name: ', name) - console.log('handleEmotion viewerHasEmotioned: ', viewerHasEmotioned) + // console.log('handleEmotion comment: ', id) + // console.log('handleEmotion name: ', name) + // console.log('handleEmotion viewerHasEmotioned: ', viewerHasEmotioned) const emotion = name.toUpperCase() + // comment.emotions if (viewerHasEmotioned) { // instantFresh + const emotionInfo = { + // @ts-ignore + [`${name}Count`]: comment.emotions[`${name}Count`] - 1, + [`viewerHas${titleCase(name)}ed`]: false, + } + store.upvoteEmotion(comment, emotionInfo) sr71$.mutate(S.undoEmotionToComment, { id, emotion }) } else { + const emotionInfo = { + // @ts-ignore + [`${name}Count`]: comment.emotions[`${name}Count`] + 1, + [`viewerHas${titleCase(name)}ed`]: true, + } + store.upvoteEmotion(comment, emotionInfo) // instantFresh sr71$.mutate(S.emotionToComment, { id, emotion }) } @@ -390,14 +404,14 @@ const DataSolver = [ match: asyncRes('emotionToComment'), action: ({ emotionToComment }) => { console.log('emotionToComment -> ', emotionToComment) - // store.updateUpvote(undoUpvoteComment, { upvotesCount, viewerHasUpvoted }) + store.upvoteEmotion(emotionToComment, emotionToComment.emotions) }, }, { match: asyncRes('undoEmotionToComment'), action: ({ undoEmotionToComment }) => { console.log('undoEmotionToComment -> ', undoEmotionToComment) - // store.updateUpvote(undoUpvoteComment, { upvotesCount, viewerHasUpvoted }) + store.upvoteEmotion(undoEmotionToComment, undoEmotionToComment.emotions) }, }, { diff --git a/src/containers/unit/Comments/schema.ts b/src/containers/unit/Comments/schema.ts index d24960c09..9f4a18155 100755 --- a/src/containers/unit/Comments/schema.ts +++ b/src/containers/unit/Comments/schema.ts @@ -101,6 +101,7 @@ const emotionToComment = gql` mutation ($id: ID!, $emotion: CommentEmotion!) { emotionToComment(id: $id, emotion: $emotion) { id + replyToId emotions { beerCount viewerHasBeered @@ -108,6 +109,12 @@ const emotionToComment = gql` login nickname } + pillCount + viewerHasPilled + latestPillUsers { + login + nickname + } } } } @@ -116,6 +123,7 @@ const undoEmotionToComment = gql` mutation ($id: ID!, $emotion: CommentEmotion!) { undoEmotionToComment(id: $id, emotion: $emotion) { id + replyToId emotions { beerCount viewerHasBeered @@ -123,6 +131,12 @@ const undoEmotionToComment = gql` login nickname } + pillCount + viewerHasPilled + latestPillUsers { + login + nickname + } } } } diff --git a/src/containers/unit/Comments/store.ts b/src/containers/unit/Comments/store.ts index 255af5b81..ec4930488 100755 --- a/src/containers/unit/Comments/store.ts +++ b/src/containers/unit/Comments/store.ts @@ -28,6 +28,7 @@ import type { TID, TPagedComments, TComment, + TEmotion, } from '@/spec' // import { TYPE } from '@/constant' import { markStates, toJS } from '@/utils/mobx' @@ -222,6 +223,17 @@ const CommentsStore = T.model('CommentsStore', { // @ts-ignore self.pagedComments.entries[index] = merge(entries[index], comment) }, + upvoteEmotion(comment: TComment, emotion: TEmotion): void { + const { id, replyToId } = comment + const slf = self as TStore + const { entries } = slf.pagedCommentsData + + const index = findIndex(propEq('id', id), entries) + self.pagedComments.entries[index].emotions = { + ...entries[index].emotions, + ...emotion, + } + }, updateUpvote(comment: TComment, info): void { const { id, replyToId } = comment const slf = self as TStore From 9b3d2aa7f8f057199404ecf86a313ddaac7da7d0 Mon Sep 17 00:00:00 2001 From: mydearxym Date: Fri, 8 Oct 2021 21:09:21 +0800 Subject: [PATCH 15/15] refactor(comment): reply emotion UX done --- src/containers/unit/Comments/schema.ts | 26 ++---------------- src/containers/unit/Comments/store.ts | 37 ++++++++++++++++++-------- src/schemas/fragments/base.ts | 2 +- src/schemas/fragments/index.ts | 2 ++ 4 files changed, 31 insertions(+), 36 deletions(-) diff --git a/src/containers/unit/Comments/schema.ts b/src/containers/unit/Comments/schema.ts index 9f4a18155..250e9d226 100755 --- a/src/containers/unit/Comments/schema.ts +++ b/src/containers/unit/Comments/schema.ts @@ -103,18 +103,7 @@ const emotionToComment = gql` id replyToId emotions { - beerCount - viewerHasBeered - latestBeerUsers { - login - nickname - } - pillCount - viewerHasPilled - latestPillUsers { - login - nickname - } + ${F.emotionQuery} } } } @@ -125,18 +114,7 @@ const undoEmotionToComment = gql` id replyToId emotions { - beerCount - viewerHasBeered - latestBeerUsers { - login - nickname - } - pillCount - viewerHasPilled - latestPillUsers { - login - nickname - } + ${F.emotionQuery} } } } diff --git a/src/containers/unit/Comments/store.ts b/src/containers/unit/Comments/store.ts index ec4930488..0ded0ca76 100755 --- a/src/containers/unit/Comments/store.ts +++ b/src/containers/unit/Comments/store.ts @@ -223,17 +223,6 @@ const CommentsStore = T.model('CommentsStore', { // @ts-ignore self.pagedComments.entries[index] = merge(entries[index], comment) }, - upvoteEmotion(comment: TComment, emotion: TEmotion): void { - const { id, replyToId } = comment - const slf = self as TStore - const { entries } = slf.pagedCommentsData - - const index = findIndex(propEq('id', id), entries) - self.pagedComments.entries[index].emotions = { - ...entries[index].emotions, - ...emotion, - } - }, updateUpvote(comment: TComment, info): void { const { id, replyToId } = comment const slf = self as TStore @@ -259,6 +248,32 @@ const CommentsStore = T.model('CommentsStore', { self.pagedComments.entries[index] = { ...entries[index], ...info } } }, + upvoteEmotion(comment: TComment, emotion: TEmotion): void { + const { id, replyToId } = comment + const slf = self as TStore + const { entries } = slf.pagedCommentsData + + if (self.mode === MODE.REPLIES && replyToId) { + const parentIndex = findIndex(propEq('id', replyToId), entries) + if (parentIndex < 0) return + const parentComment = entries[parentIndex] + const replyIndex = findIndex(propEq('id', id), parentComment.replies) + if (replyIndex < 0) return + const replyComment = parentComment.replies[replyIndex] + self.pagedComments.entries[parentIndex].replies[replyIndex].emotions = { + ...replyComment.emotions, + ...emotion, + } + } else { + const index = findIndex(propEq('id', id), entries) + if (index < 0) return + // @ts-ignore + self.pagedComments.entries[index].emotions = { + ...entries[index].emotions, + ...emotion, + } + } + }, mark(sobj: Record): void { markStates(sobj, self) }, diff --git a/src/schemas/fragments/base.ts b/src/schemas/fragments/base.ts index 61d0ea94b..89c9ebb42 100755 --- a/src/schemas/fragments/base.ts +++ b/src/schemas/fragments/base.ts @@ -180,7 +180,7 @@ export const userContributes = ` totalCount ` -const emotionQuery = flatten( +export const emotionQuery = flatten( values(EMOTION).map((emotion) => { return [ `${emotion}Count`, diff --git a/src/schemas/fragments/index.ts b/src/schemas/fragments/index.ts index 15ccaa899..47f29d7e9 100755 --- a/src/schemas/fragments/index.ts +++ b/src/schemas/fragments/index.ts @@ -22,6 +22,7 @@ import { userBackgrounds, userContributes, comment, + emotionQuery, commentParent, pagedCounts, } from './base' @@ -47,6 +48,7 @@ const F = { userContributes, comment, + emotionQuery, commentParent, pagedCounts, }