diff --git a/.eslintrc.js b/.eslintrc.js index 32bfdef03..47e77f7aa 100755 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -32,6 +32,7 @@ module.exports = { '@/schemas': 'src/schemas', '@/Img': 'src/components/Img', '@/SvgIcons': 'src/components/SvgIcons', + '@/icons': 'src/components/Icons', '@/i18n': 'i18n', '@/spec': 'src/spec', }, @@ -40,6 +41,7 @@ module.exports = { }, }, rules: { + '@typescript-eslint/no-var-requires': 0, '@typescript-eslint/ban-ts-comment': 0, 'react/jsx-uses-react': 'off', 'react/react-in-jsx-scope': 'off', diff --git a/jsconfig.json b/jsconfig.json index 040091793..21fcd2c3e 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -16,6 +16,7 @@ "@/schemas": ["src/schemas"], "@/Img": ["src/components/Img"], "@/SvgIcons/*": ["src/components/SvgIcons/*"], + "@/icons/*": ["src/components/icons/*"], "@/i18n": ["i18n"] } }, diff --git a/next.config.docker.js b/next.config.docker.js index 2b48a6e46..343b3cb78 100755 --- a/next.config.docker.js +++ b/next.config.docker.js @@ -24,9 +24,6 @@ const nextConfig = { 'process.env.SENTRY_RELEASE': JSON.stringify(buildId), }), ) - if (!isServer) { - config.resolve.alias['@sentry/node'] = '@sentry/browser' - } return config }, diff --git a/next.config.js b/next.config.js index 4f974319d..4a4169868 100755 --- a/next.config.js +++ b/next.config.js @@ -10,17 +10,17 @@ const withBundleAnalyzer = require('@next/bundle-analyzer')({ const offlineConfig = require('./config/next_offline') // Use the SentryWebpack plugin to upload the source maps during build step -const SentryWebpackPlugin = require('@sentry/webpack-plugin') +// const SentryWebpackPlugin = require('@sentry/webpack-plugin') -const { - NEXT_PUBLIC_SENTRY_DSN: SENTRY_DSN, - SENTRY_ORG, - SENTRY_PROJECT, - SENTRY_AUTH_TOKEN, - NODE_ENV, -} = process.env +// const { +// NEXT_PUBLIC_SENTRY_DSN: SENTRY_DSN, +// SENTRY_ORG, +// SENTRY_PROJECT, +// SENTRY_AUTH_TOKEN, +// NODE_ENV, +// } = process.env -process.env.SENTRY_DSN = SENTRY_DSN +// process.env.SENTRY_DSN = SENTRY_DSN // next-plugins end @@ -34,38 +34,6 @@ const nextConfig = { new webpack.ContextReplacementPlugin(/moment[/\\]locale$/, /(en)/), ) - // for sentry - config.plugins.push( - new webpack.DefinePlugin({ - 'process.env.SENTRY_RELEASE': JSON.stringify(buildId), - }), - ) - if (!isServer) { - config.resolve.alias['@sentry/node'] = '@sentry/browser' - } - - // When all the Sentry configuration env variables are available/configured - // The Sentry webpack plugin gets pushed to the webpack plugins to build - // and upload the source maps to sentry. - // This is an alternative to manually uploading the source maps - // Note: This is disabled in development mode. - if ( - SENTRY_DSN && - SENTRY_ORG && - SENTRY_PROJECT && - SENTRY_AUTH_TOKEN && - NODE_ENV === 'production' - ) { - config.plugins.push( - new SentryWebpackPlugin({ - include: '.next', - ignore: ['node_modules'], - urlPrefix: '~/_next', - release: buildId, - }), - ) - } - return config }, } diff --git a/package.json b/package.json index a0cb5f539..8c4ddb3a8 100644 --- a/package.json +++ b/package.json @@ -84,7 +84,6 @@ "graphql-voyager": "^1.0.0-rc.31", "js-cookie": "^2.2.0", "mastani-codehighlight": "0.0.7", - "mobile-device-detect": "^0.4.3", "mobx": "6.3.2", "mobx-react": "7.2.0", "mobx-react-lite": "3.2.0", @@ -95,7 +94,6 @@ "next-compose-plugins": "^2.2.0", "next-i18next": "4.4.1", "next-offline": "4.0.6", - "next-seo": "4.4.0", "nextjs-progressbar": "^0.0.6", "overlayscrollbars": "1.13.1", "path-match": "^1.2.4", @@ -110,6 +108,7 @@ "react-calendar-heatmap": "1.8.1", "react-content-loader": "3.4.2", "react-copy-to-clipboard": "^5.0.3", + "react-device-detect": "^1.17.0", "react-dom": "17.0.2", "react-highlight-words": "^0.16.0", "react-lazy-load-image-component": "1.5.0", diff --git a/server/index.js b/server/index.js index 3e8c4c12d..ecf65a677 100755 --- a/server/index.js +++ b/server/index.js @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ /** * * this server is only used for next.js SSR @@ -13,8 +14,8 @@ const mobxReact = require('mobx-react') // inspect graphql model const { express: voyagerMiddleware } = require('graphql-voyager/middleware') // i18n setup -const nextI18NextMiddleware = require('next-i18next/middleware').default -const nextI18next = require('../i18n') +// const nextI18NextMiddleware = require('next-i18next/middleware').default +// const nextI18next = require('../i18n') const app = require('./app') const { redirectToNakedUrl } = require('./helper') @@ -44,8 +45,8 @@ mobxReact.enableStaticRendering(true) voyagerMiddleware({ endpointUrl: CONFIG.GRAPHQL_ENDPOINT }), ) - await nextI18next.initPromise - server.use(nextI18NextMiddleware(nextI18next)) + // await nextI18next.initPromise + // server.use(nextI18NextMiddleware(nextI18next)) // eslint-disable-next-line global-require server.use('/', require('./routes')) diff --git a/src/components/ArticleBaseStats/index.tsx b/src/components/ArticleBaseStats/index.tsx index d883d37f8..28b84e13b 100755 --- a/src/components/ArticleBaseStats/index.tsx +++ b/src/components/ArticleBaseStats/index.tsx @@ -7,7 +7,6 @@ import { FC, memo } from 'react' import type { TArticle, TContainer } from '@/spec' -import { ICON } from '@/config' import { buildLog, scrollToComments } from '@/utils' import { Space } from '@/components/Common' @@ -36,11 +35,11 @@ const ArticleBaseStats: FC = ({ }) => { return ( - + {article.views} scrollToComments(container)}> - + {article.commentsCount} diff --git a/src/components/ArticleBaseStats/styles/index.ts b/src/components/ArticleBaseStats/styles/index.ts index 24aa5cc7c..df1330579 100755 --- a/src/components/ArticleBaseStats/styles/index.ts +++ b/src/components/ArticleBaseStats/styles/index.ts @@ -2,7 +2,9 @@ import styled from 'styled-components' import type { TTestable } from '@/spec' -import Img from '@/Img' +import ViewSVGIcon from '@/icons/View' +import CommentSVGIcon from '@/icons/Comment' + import { css, theme } from '@/utils' export const Wrapper = styled.div.attrs(({ testid }: TTestable) => ({ @@ -10,17 +12,19 @@ export const Wrapper = styled.div.attrs(({ testid }: TTestable) => ({ }))` ${css.flex('align-center')}; ` -const Icon = styled(Img)` +export const ViewsIcon = styled(ViewSVGIcon)` fill: ${theme('thread.articleDigest')}; ${css.size(14)}; transition: fill 0.25s; ` -export const ViewsIcon = styled(Icon)`` - export const CommentWrapper = styled.div` ${css.flex('align-center')}; ` -export const CommentIcon = styled(Icon)` +export const CommentIcon = styled(CommentSVGIcon)` + fill: ${theme('thread.articleDigest')}; + ${css.size(14)}; + transition: fill 0.25s; + ${CommentWrapper}:hover & { cursor: pointer; fill: ${theme('thread.articleTitle')}; diff --git a/src/components/ArticlesFilter/DesktopView.tsx b/src/components/ArticlesFilter/DesktopView.tsx index 39920984b..30b1522c8 100644 --- a/src/components/ArticlesFilter/DesktopView.tsx +++ b/src/components/ArticlesFilter/DesktopView.tsx @@ -9,9 +9,9 @@ import dynamic from 'next/dynamic' import type { TArticleFilter, TResState } from '@/spec' -import { TYPE } from '@/constant' +import { TYPE, THREAD } from '@/constant' import { buildLog } from '@/utils' -import { useViewing } from '@/hooks' +// import { useViewing } from '@/hooks' import FilterButton from './FilterButton' import SelectedFilters from './SelectedFilters' @@ -46,13 +46,14 @@ const ArticlesFilter: FC = ({ totalCount = 0, resState = TYPE.RES_STATE.DONE, }) => { - const { activeThread } = useViewing() + // NOTE: 这里使用 useViewing 会导致 build-size blow + // const { activeThread } = useViewing() return ( diff --git a/src/components/ArticlesFilter/FilterButton.tsx b/src/components/ArticlesFilter/FilterButton.tsx index f0aeeb396..a510ba882 100755 --- a/src/components/ArticlesFilter/FilterButton.tsx +++ b/src/components/ArticlesFilter/FilterButton.tsx @@ -3,7 +3,6 @@ import dynamic from 'next/dynamic' import type { TThread, TArticleFilter } from '@/spec' import { ICON_CMD } from '@/config' -import { useAccount } from '@/hooks' import Tooltip from '@/components/Tooltip' @@ -14,7 +13,7 @@ import { FilterIcon, } from './styles/filter_button' -const FilterPanel = dynamic(() => import('./FilterPanel/index'), { +const FilterPanel = dynamic(() => import('./FilterPanel'), { /* eslint-disable react/display-name */ loading: () =>
, ssr: false, @@ -27,8 +26,6 @@ type TProps = { } const FilterButton: FC = ({ thread, onSelect, activeFilter }) => { - const { isLogin } = useAccount() - return ( = ({ thread, onSelect, activeFilter }) => { ) diff --git a/src/components/ArticlesFilter/FilterPanel/index.tsx b/src/components/ArticlesFilter/FilterPanel/index.tsx index 2d29b1916..530c39476 100644 --- a/src/components/ArticlesFilter/FilterPanel/index.tsx +++ b/src/components/ArticlesFilter/FilterPanel/index.tsx @@ -2,6 +2,7 @@ import { FC, memo } from 'react' import type { TThread, TArticleFilter } from '@/spec' import { THREAD } from '@/constant' +import { useAccount } from '@/hooks' import TimeFilter from './TimeFilter' import SortFilter from './SortFilter' @@ -15,15 +16,11 @@ type TProps = { activeFilter: TArticleFilter onSelect: (filter: TArticleFilter) => void thread: TThread - isLogin?: boolean } -const FilterPanel: FC = ({ - thread, - activeFilter, - onSelect, - isLogin, -}) => { +const FilterPanel: FC = ({ thread, activeFilter, onSelect }) => { + const { isLogin } = useAccount() + switch (thread) { case THREAD.POST: return ( diff --git a/src/components/ArticlesFilter/index.tsx b/src/components/ArticlesFilter/index.tsx index 1d82aa405..c69835ef9 100755 --- a/src/components/ArticlesFilter/index.tsx +++ b/src/components/ArticlesFilter/index.tsx @@ -6,7 +6,7 @@ import { Fragment, memo } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog } from '@/utils' import DesktopView from './DesktopView' @@ -15,8 +15,6 @@ import DesktopView from './DesktopView' const log = buildLog('c:ArticlesFilter:index') const ArticlesFilter = (props) => { - const { isMobile } = useDevice() - return {!isMobile && } } diff --git a/src/components/ArticlesFilter/styles/filter_button.ts b/src/components/ArticlesFilter/styles/filter_button.ts index 13c6db160..a0caddbab 100755 --- a/src/components/ArticlesFilter/styles/filter_button.ts +++ b/src/components/ArticlesFilter/styles/filter_button.ts @@ -1,6 +1,6 @@ import styled from 'styled-components' -import { Button } from '@/components/Buttons' +import Button from '@/components/Buttons/Button' import { theme, css } from '@/utils' import Img from '@/Img' diff --git a/src/components/AvatarsRow/index.tsx b/src/components/AvatarsRow/index.tsx index d499cb1b3..157c63743 100755 --- a/src/components/AvatarsRow/index.tsx +++ b/src/components/AvatarsRow/index.tsx @@ -4,21 +4,49 @@ * */ -import { FC } from 'react' +import { FC, createContext, useContext } from 'react' +import dynamic from 'next/dynamic' import { compose, not, isNil, filter, reverse as reverseFn, slice } from 'ramda' import { trackWindowScroll } from 'react-lazy-load-image-component' -import type { TUser } from '@/spec' +import type { TUser, TSIZE } from '@/spec' +import type { TAvatarSize } from './spec' import { AVATARS_LIST_LENGTH } from '@/config' import { SIZE } from '@/constant' import { buildLog } from '@/utils' -import type { TAvatarSize } from './spec' - -import RealAvatar from './RealAvatar' +// import RealAvatar from './RealAvatar' import MoreItem from './MoreItem' -import { Wrapper, AvatarsWrapper, TotalOneOffset } from './styles' +import { getAvatarSize } from './styles/metric' +import { + Wrapper, + AvatarsWrapper, + TotalOneOffset, + AvatarFallback, +} from './styles' + +// @ts-ignore +const RealAvatarContext = createContext() + +export const RealAvatar = dynamic(() => import('./RealAvatar'), { + /* eslint-disable react/display-name */ + loading: () => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { size, user } = useContext(RealAvatarContext) as { + user: TUser + size: TSIZE + } + + return ( + + ) + }, + ssr: false, +}) /* eslint-disable-next-line */ const log = buildLog('c:AvatarsRow:index') @@ -89,20 +117,19 @@ const AvatarsRow: FC = ({ )} {totalCount === 1 ? ( - + + + ) : ( {slice(0, limit, sortedUsers).map((user) => ( - + + + ))} )} diff --git a/src/components/AvatarsRow/styles/index.ts b/src/components/AvatarsRow/styles/index.ts index a48c8166b..bcd931578 100755 --- a/src/components/AvatarsRow/styles/index.ts +++ b/src/components/AvatarsRow/styles/index.ts @@ -5,6 +5,8 @@ import { theme, css } from '@/utils' import { getAvatarSize, getUlMarginRight } from './metric' import type { TAvatarSize } from '../spec' +export { AvatarFallback } from './real_avatar' + export const Wrapper = styled.ul<{ total: number }>` ${css.flex('align-center')}; flex-direction: row-reverse; diff --git a/src/components/Buttons/DebugSizeButton.tsx b/src/components/Buttons/DebugSizeButton.tsx new file mode 100755 index 000000000..a79dfa64e --- /dev/null +++ b/src/components/Buttons/DebugSizeButton.tsx @@ -0,0 +1,22 @@ +/* + * + * ArrowButtons + * + */ + +import { FC } from 'react' + +import type { TSIZE } from '@/spec' + +type TProps = { + // children?: any + // onClick?: () => void + size?: TSIZE + // direction?: 'left' | 'right' + // dimWhenIdle?: boolean + // disabled?: boolean + // arrowStyle?: 'default' | 'simple' +} + +const ArrowButton: FC = () =>
i
+export default ArrowButton diff --git a/src/components/Buttons/IconButton.tsx b/src/components/Buttons/IconButton.tsx index c34b1c8f0..85e341886 100644 --- a/src/components/Buttons/IconButton.tsx +++ b/src/components/Buttons/IconButton.tsx @@ -1,12 +1,14 @@ import { FC, memo, ReactNode } from 'react' import { ICON } from '@/config' +import { SVG } from '@/constant' import Tooltip from '@/components/Tooltip' -import { Wrapper, Icon, Hint } from './styles/icon_button' +import { Wrapper, Icon, Hint, getIcon } from './styles/icon_button' export type TProps = { - path: string + path?: string | null + icon?: string | null size?: number mRight?: number mLeft?: number @@ -21,7 +23,8 @@ export type TProps = { } const IconButton: FC = ({ - path, + path = null, + icon = null, size = 16, mLeft = 0, mRight = 10, @@ -34,6 +37,26 @@ const IconButton: FC = ({ hintPlacement = 'top', onClick = console.log, }) => { + let realIcon = null + + if (path) { + // icon from OSS + realIcon = ( + + ) + } else { + const LocalIcon = getIcon(icon || SVG.UPVOTE) + + realIcon = ( + + ) + } + return ( = ({ noPadding delay={hintDelay} > - + {realIcon}
) : ( - + <>{realIcon} )}
) diff --git a/src/components/Buttons/index.tsx b/src/components/Buttons/index.tsx index 6c5cd2750..be7b9f192 100755 --- a/src/components/Buttons/index.tsx +++ b/src/components/Buttons/index.tsx @@ -11,3 +11,5 @@ export { default as FollowButton } from './FollowButton' export { default as YesOrNoButtons } from './YesOrNoButtons' export { default as IconButton } from './IconButton' export { default as CopyButton } from './CopyButton' + +export { default as DebugSizeButton } from './DebugSizeButton' diff --git a/src/components/Buttons/styles/icon_button.ts b/src/components/Buttons/styles/icon_button.ts index 4c664e2a5..28b8378d5 100644 --- a/src/components/Buttons/styles/icon_button.ts +++ b/src/components/Buttons/styles/icon_button.ts @@ -1,10 +1,17 @@ +import { FC } from 'react' import styled from 'styled-components' import type { TActive, TSpace } from '@/spec' +import { SVG } from '@/constant' import Img from '@/Img' import { css, theme } from '@/utils' +import UpvoteIcon from '@/icons/Upvote' +import LockIcon from '@/icons/Lock' +import ExpandIcon from '@/icons/Expand' +import FoldIcon from '@/icons/Fold' + import type { TProps as TIconButtonProps } from '../IconButton' type TWrapper = Omit @@ -22,9 +29,7 @@ type TIcon = { size: number; dimWhenIdle: boolean } & TSpace & TActive export const Icon = styled(Img)` fill: ${({ $active }) => $active ? '#00a59b' : theme('thread.articleDigest')}; - display: block; - width: ${({ size }) => `${size}px`}; - height: ${({ size }) => `${size}px`}; + ${({ size }) => css.size(size)}; opacity: ${({ dimWhenIdle }) => (dimWhenIdle ? 0.7 : 1)}; @@ -37,6 +42,48 @@ export const Icon = styled(Img)` transition: fill 0.2s; ` +export const getIcon = (type: string): FC => { + switch (type) { + case SVG.UPVOTE: { + return getStyledIcon(UpvoteIcon) + } + + case SVG.LOCK: { + return getStyledIcon(LockIcon) + } + + case SVG.EXPAND: { + return getStyledIcon(ExpandIcon) + } + + case SVG.FOLD: { + return getStyledIcon(FoldIcon) + } + + default: { + return getStyledIcon(UpvoteIcon) + } + } +} + +export const getStyledIcon = (comp: FC): FC => { + return styled(comp)` + fill: ${({ $active }) => + $active ? '#00a59b' : theme('thread.articleDigest')}; + ${({ size }) => css.size(size)}; + + opacity: ${({ dimWhenIdle }) => (dimWhenIdle ? 0.7 : 1)}; + + &:hover { + fill: #00a59b; + opacity: 1; + cursor: pointer; + } + + transition: fill 0.2s; + ` +} + export const Hint = styled.div` color: ${theme('thread.articleDigest')}; text-align: center; diff --git a/src/components/CommunityStatesPad/index.js b/src/components/CommunityStatesPad/index.js index 60e26da9d..deb20ed7a 100755 --- a/src/components/CommunityStatesPad/index.js +++ b/src/components/CommunityStatesPad/index.js @@ -7,7 +7,7 @@ import React from 'react' import T from 'prop-types' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog } from '@/utils' import Charger from '@/components/Charger' @@ -40,8 +40,6 @@ const CommunityStatesPad = ({ jobsCount, viewerHasSubscribed, } = community - const { isMobile } = useDevice() - const contentsCount = postsCount + reposCount + jobsCount return ( diff --git a/src/components/ContentSourceCard/index.js b/src/components/ContentSourceCard/index.js index 107fe13d9..2e6c33c4c 100755 --- a/src/components/ContentSourceCard/index.js +++ b/src/components/ContentSourceCard/index.js @@ -7,7 +7,7 @@ import React from 'react' import T from 'prop-types' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog } from '@/utils' import DesktopView from './DesktopView' @@ -17,8 +17,6 @@ import MobileView from './MobileView' const log = buildLog('c:ContentSourceCard:index') const ContentSourceCard = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/components/CustomScroller/HorizontalScroller.tsx b/src/components/CustomScroller/HorizontalScroller.tsx index d54e92610..90d820420 100755 --- a/src/components/CustomScroller/HorizontalScroller.tsx +++ b/src/components/CustomScroller/HorizontalScroller.tsx @@ -10,8 +10,9 @@ import { Waypoint } from 'react-waypoint' import type { TThemeMap } from '@/spec' import { buildLog } from '@/utils' -import { SIZE } from '@/constant' import { useCustomScroll } from '@/hooks' +// import ViewportTracker from '@/components/ViewportTracker' +import { SIZE } from '@/constant' import type { TProps as TScrollProps } from './index' diff --git a/src/components/CustomScroller/VerticalScroller.tsx b/src/components/CustomScroller/VerticalScroller.tsx index 7d0a8e70f..388e99b78 100755 --- a/src/components/CustomScroller/VerticalScroller.tsx +++ b/src/components/CustomScroller/VerticalScroller.tsx @@ -6,12 +6,15 @@ import { FC, useState, useRef, useCallback, memo } from 'react' import { useTheme } from 'styled-components' + +// NOTE: do not use ViewportTracker here, it cause crash import { Waypoint } from 'react-waypoint' import type { TThemeMap } from '@/spec' import { buildLog, debounce } from '@/utils' import { SIZE } from '@/constant' import { useCustomScroll } from '@/hooks' +// import ViewportTracker from '@/components/ViewportTracker' import type { TProps as TScrollProps } from './index' diff --git a/src/components/Icons/Acount.tsx b/src/components/Icons/Acount.tsx new file mode 100644 index 000000000..c23f01111 --- /dev/null +++ b/src/components/Icons/Acount.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Account = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Account) diff --git a/src/components/Icons/Arrow.tsx b/src/components/Icons/Arrow.tsx new file mode 100644 index 000000000..ccba103b6 --- /dev/null +++ b/src/components/Icons/Arrow.tsx @@ -0,0 +1,22 @@ +import { memo, SVGProps } from 'react' + +const Arrow = (props: SVGProps) => { + return ( + + + + + + + + ) +} + +export default memo(Arrow) diff --git a/src/components/Icons/Checked.tsx b/src/components/Icons/Checked.tsx new file mode 100644 index 000000000..4f8884a7b --- /dev/null +++ b/src/components/Icons/Checked.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Checked = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Checked) diff --git a/src/components/Icons/CollectionFolder.tsx b/src/components/Icons/CollectionFolder.tsx new file mode 100644 index 000000000..29e366d44 --- /dev/null +++ b/src/components/Icons/CollectionFolder.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const CollectionFolder = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(CollectionFolder) diff --git a/src/components/Icons/Comment.tsx b/src/components/Icons/Comment.tsx new file mode 100644 index 000000000..0c661e5d7 --- /dev/null +++ b/src/components/Icons/Comment.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Comment = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Comment) diff --git a/src/components/Icons/CopyrightCC.tsx b/src/components/Icons/CopyrightCC.tsx new file mode 100644 index 000000000..cab9f3452 --- /dev/null +++ b/src/components/Icons/CopyrightCC.tsx @@ -0,0 +1,18 @@ +import { memo, SVGProps } from 'react' + +const CopyrightCC = (props: SVGProps) => { + return ( + + + + + ) +} + +export default memo(CopyrightCC) diff --git a/src/components/Icons/Emotion.tsx b/src/components/Icons/Emotion.tsx new file mode 100644 index 000000000..a1e888724 --- /dev/null +++ b/src/components/Icons/Emotion.tsx @@ -0,0 +1,18 @@ +import { memo, SVGProps } from 'react' + +const Emotion = (props: SVGProps) => { + return ( + + + + + ) +} + +export default memo(Emotion) diff --git a/src/components/Icons/Expand.tsx b/src/components/Icons/Expand.tsx new file mode 100644 index 000000000..160b295d8 --- /dev/null +++ b/src/components/Icons/Expand.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Expand = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Expand) diff --git a/src/components/Icons/Fold.tsx b/src/components/Icons/Fold.tsx new file mode 100644 index 000000000..3ed07c0d3 --- /dev/null +++ b/src/components/Icons/Fold.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Expand = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Expand) diff --git a/src/components/Icons/GotoTop.tsx b/src/components/Icons/GotoTop.tsx new file mode 100644 index 000000000..83efd5236 --- /dev/null +++ b/src/components/Icons/GotoTop.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const GotoTop = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(GotoTop) diff --git a/src/components/Icons/Lock.tsx b/src/components/Icons/Lock.tsx new file mode 100644 index 000000000..797a00bc3 --- /dev/null +++ b/src/components/Icons/Lock.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Lock = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Lock) diff --git a/src/components/Icons/MagicStick.tsx b/src/components/Icons/MagicStick.tsx new file mode 100644 index 000000000..57034b033 --- /dev/null +++ b/src/components/Icons/MagicStick.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const MagicStick = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(MagicStick) diff --git a/src/components/Icons/More.tsx b/src/components/Icons/More.tsx new file mode 100644 index 000000000..2b7c05496 --- /dev/null +++ b/src/components/Icons/More.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const More = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(More) diff --git a/src/components/Icons/MoreL.tsx b/src/components/Icons/MoreL.tsx new file mode 100644 index 000000000..3c9eaab51 --- /dev/null +++ b/src/components/Icons/MoreL.tsx @@ -0,0 +1,18 @@ +import { memo, SVGProps } from 'react' + +const MoreL = (props: SVGProps) => { + return ( + + + + + ) +} + +export default memo(MoreL) diff --git a/src/components/Icons/Pulse.tsx b/src/components/Icons/Pulse.tsx new file mode 100644 index 000000000..b9209223f --- /dev/null +++ b/src/components/Icons/Pulse.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Pulse = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Pulse) diff --git a/src/components/Icons/Question.tsx b/src/components/Icons/Question.tsx new file mode 100644 index 000000000..6c33edc35 --- /dev/null +++ b/src/components/Icons/Question.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Question = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Question) diff --git a/src/components/Icons/ReplyMode.tsx b/src/components/Icons/ReplyMode.tsx new file mode 100644 index 000000000..31b411985 --- /dev/null +++ b/src/components/Icons/ReplyMode.tsx @@ -0,0 +1,24 @@ +import { memo, SVGProps } from 'react' + +const ReplyMode = (props: SVGProps) => { + return ( + + + + + + + + + + ) +} + +export default memo(ReplyMode) diff --git a/src/components/Icons/Report.tsx b/src/components/Icons/Report.tsx new file mode 100644 index 000000000..cf3f35936 --- /dev/null +++ b/src/components/Icons/Report.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Report = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Report) diff --git a/src/components/Icons/Share.tsx b/src/components/Icons/Share.tsx new file mode 100644 index 000000000..0938e0644 --- /dev/null +++ b/src/components/Icons/Share.tsx @@ -0,0 +1,18 @@ +import { memo, SVGProps } from 'react' + +const Share = (props: SVGProps) => { + return ( + + + + + ) +} + +export default memo(Share) diff --git a/src/components/Icons/Star.tsx b/src/components/Icons/Star.tsx new file mode 100644 index 000000000..7bbcae0ca --- /dev/null +++ b/src/components/Icons/Star.tsx @@ -0,0 +1,22 @@ +import { memo, SVGProps } from 'react' + +const Star = (props: SVGProps) => { + return ( + + + + + + + + ) +} + +export default memo(Star) diff --git a/src/components/Icons/TimelineMode.tsx b/src/components/Icons/TimelineMode.tsx new file mode 100644 index 000000000..94034c46f --- /dev/null +++ b/src/components/Icons/TimelineMode.tsx @@ -0,0 +1,22 @@ +import { memo, SVGProps } from 'react' + +const TimelineMode = (props: SVGProps) => { + return ( + + + + + + + + ) +} + +export default memo(TimelineMode) diff --git a/src/components/Icons/Upvote.tsx b/src/components/Icons/Upvote.tsx new file mode 100644 index 000000000..ec5224c04 --- /dev/null +++ b/src/components/Icons/Upvote.tsx @@ -0,0 +1,18 @@ +import { memo, SVGProps } from 'react' + +const Upvote = (props: SVGProps) => { + return ( + + + + + ) +} + +export default memo(Upvote) diff --git a/src/components/Icons/View.tsx b/src/components/Icons/View.tsx new file mode 100644 index 000000000..ede877785 --- /dev/null +++ b/src/components/Icons/View.tsx @@ -0,0 +1,23 @@ +import { memo, SVGProps } from 'react' + +const View = (props: SVGProps) => { + return ( + + + + + + + + + ) +} + +export default memo(View) diff --git a/src/components/Icons/Warning.tsx b/src/components/Icons/Warning.tsx new file mode 100644 index 000000000..b61711a10 --- /dev/null +++ b/src/components/Icons/Warning.tsx @@ -0,0 +1,21 @@ +import { memo, SVGProps } from 'react' + +const Warning = (props: SVGProps) => { + return ( + + + + + + + ) +} + +export default memo(Warning) diff --git a/src/components/JobItem/index.tsx b/src/components/JobItem/index.tsx index 086bb8e51..78e632216 100755 --- a/src/components/JobItem/index.tsx +++ b/src/components/JobItem/index.tsx @@ -6,9 +6,8 @@ import { FC, memo } from 'react' -import type { TJob, TID } from '@/spec' +import type { TJob, TID, TC11N } from '@/spec' import { buildLog } from '@/utils' -import { useAccount } from '@/hooks' import ArticleCard from '@/components/ArticleCard' @@ -20,11 +19,10 @@ const log = buildLog('c:JobItem:index') type TProps = { entry: TJob activeId: TID | null + c11n: TC11N } -const JobItem: FC = ({ entry, activeId }) => { - const { c11n } = useAccount() - +const JobItem: FC = ({ entry, activeId, c11n }) => { return ( diff --git a/src/components/Modal/index.tsx b/src/components/Modal/index.tsx index 03e58233d..1ed4f4aba 100755 --- a/src/components/Modal/index.tsx +++ b/src/components/Modal/index.tsx @@ -6,12 +6,12 @@ import { FC, ReactNode, useEffect, useState, useCallback, memo } from 'react' import usePortal from 'react-useportal' -import { Waypoint } from 'react-waypoint' import { ICON_CMD } from '@/config' import { buildLog, toggleGlobalBlur } from '@/utils' import { useShortcut } from '@/hooks' +import ViewportTracker from '@/components/ViewportTracker' import Belt from './Belt' import { Mask, Wrapper, CloseBtn, EscHint, ChildrenWrapper } from './styles' @@ -71,7 +71,7 @@ const Modal: FC = ({ background={background} offsetTop={offsetTop} > - setVisibleOnPage(true)} /> + setVisibleOnPage(true)} /> import('@/components/BlinkCursor'), { + ssr: false, +}) + const renderMainEntries = (metric) => { switch (metric) { case METRIC.ARTICLE_EDITOR: { diff --git a/src/components/Navigator/MainEntries/DesktopView.tsx b/src/components/Navigator/MainEntries/DesktopView.tsx index 1591be7c8..581aa693d 100644 --- a/src/components/Navigator/MainEntries/DesktopView.tsx +++ b/src/components/Navigator/MainEntries/DesktopView.tsx @@ -1,14 +1,14 @@ import { FC, memo } from 'react' import Link from 'next/link' import { useRouter } from 'next/router' +import dynamic from 'next/dynamic' -import { ICON_CMD } from '@/config' import { ROUTE } from '@/constant' import { getRouteMainPath } from '@/utils' -import Tooltip from '@/components/Tooltip' -import MorePanel from '../MorePanel' -import { Wrapper, DotDivider, SiteLink, Icon } from '../styles/main_entries' +import { Wrapper, DotDivider, SiteLink } from '../styles/main_entries' + +const MoreLink = dynamic(() => import('./MoreLink'), { ssr: false }) const splitMargin = 7 @@ -64,17 +64,7 @@ const DesktopView: FC = ({ type }) => { - } - placement="bottom" - hideOnClick={false} - trigger="click" - noPadding - > - - 更多 - - + ) } diff --git a/src/components/Navigator/MainEntries/MobileView.tsx b/src/components/Navigator/MainEntries/MobileView.tsx index 5a130f29e..515f70e6c 100644 --- a/src/components/Navigator/MainEntries/MobileView.tsx +++ b/src/components/Navigator/MainEntries/MobileView.tsx @@ -3,8 +3,6 @@ import { FC, memo } from 'react' import { ICON } from '@/config' import { TYPE, EVENT } from '@/constant' import { send } from '@/utils' -// import Tooltip from '@/components/Tooltip' -// import MorePanel from '../MorePanel' import { Wrapper, SiteLink, MobileIcon } from '../styles/main_entries' export const openMobileNaviMenu = (): void => { diff --git a/src/components/Navigator/MainEntries/MoreLink.tsx b/src/components/Navigator/MainEntries/MoreLink.tsx new file mode 100644 index 000000000..6cfc8c253 --- /dev/null +++ b/src/components/Navigator/MainEntries/MoreLink.tsx @@ -0,0 +1,26 @@ +import { FC, memo } from 'react' + +import { ICON_CMD } from '@/config' + +import Tooltip from '@/components/Tooltip' + +import MorePanel from '../MorePanel' +import { SiteLink, Icon } from '../styles/main_entries' + +const DesktopView: FC = () => { + return ( + } + placement="bottom" + hideOnClick={false} + trigger="click" + noPadding + > + + 更多 + + + ) +} + +export default memo(DesktopView) diff --git a/src/components/Navigator/MainEntries/index.tsx b/src/components/Navigator/MainEntries/index.tsx index a97a60447..a4e8d79ac 100644 --- a/src/components/Navigator/MainEntries/index.tsx +++ b/src/components/Navigator/MainEntries/index.tsx @@ -1,13 +1,11 @@ import { Fragment } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView' const MainEntries = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/components/Navigator/MorePanel/index.tsx b/src/components/Navigator/MorePanel/index.tsx index a0f3808b8..1b4b77ddb 100755 --- a/src/components/Navigator/MorePanel/index.tsx +++ b/src/components/Navigator/MorePanel/index.tsx @@ -1,13 +1,11 @@ import { Fragment, memo } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView' const MoreContent = () => { - const { isMobile } = useDevice() - return {!isMobile ? : } } diff --git a/src/components/PagedArticles/ArticleList.tsx b/src/components/PagedArticles/ArticleList.tsx index 653ef375f..ce5e05e6d 100755 --- a/src/components/PagedArticles/ArticleList.tsx +++ b/src/components/PagedArticles/ArticleList.tsx @@ -11,7 +11,7 @@ import EmptyLabel from '@/components/EmptyLabel' import PostsList from './PostsList' import JobsList from './JobsList' -import ReposList from './ReposList' +// import ReposList from './ReposList' const ArticleList = (props) => { const { thread, resState, community, emptyPrefix } = props @@ -35,8 +35,8 @@ const ArticleList = (props) => { case THREAD.JOB: return - case THREAD.REPO: - return + // case THREAD.REPO: + // return default: return diff --git a/src/components/PagedArticles/JobsList.tsx b/src/components/PagedArticles/JobsList.tsx index 1d87f41e9..edcb87a1c 100755 --- a/src/components/PagedArticles/JobsList.tsx +++ b/src/components/PagedArticles/JobsList.tsx @@ -1,19 +1,20 @@ import { FC, memo } from 'react' -import type { TJob, TID } from '@/spec' +import type { TJob, TID, TC11N } from '@/spec' import JobItem from '@/components/JobItem' import MasonryCards from '@/components/MasonryCards' type TProps = { entries: TJob[] activeId: TID | null + c11n: TC11N } -const JobsList: FC = ({ entries, activeId }) => { +const JobsList: FC = ({ entries, activeId, c11n }) => { return ( {entries.map((entry) => ( - + ))} ) diff --git a/src/components/PagedArticles/PostsList.tsx b/src/components/PagedArticles/PostsList.tsx index fd5d8e383..2d9ec99ef 100755 --- a/src/components/PagedArticles/PostsList.tsx +++ b/src/components/PagedArticles/PostsList.tsx @@ -1,18 +1,24 @@ import { FC, Fragment, memo } from 'react' -import type { TPost, TID } from '@/spec' +import type { TPost, TID, TC11N } from '@/spec' import PostItem from '@/components/PostItem' type TProps = { entries: TPost[] activeId: TID + c11n: TC11N } -const PostsList: FC = ({ entries, activeId }) => { +const PostsList: FC = ({ entries, activeId, c11n }) => { return ( {entries.map((entry) => ( - + ))} ) diff --git a/src/components/PagedArticles/index.tsx b/src/components/PagedArticles/index.tsx index 46f8c159c..115bed15e 100755 --- a/src/components/PagedArticles/index.tsx +++ b/src/components/PagedArticles/index.tsx @@ -5,18 +5,28 @@ */ import { Fragment, FC, memo } from 'react' +import dynamic from 'next/dynamic' -import type { TThread, TPagedArticles, TResState, TArticle } from '@/spec' +import type { + TThread, + TPagedArticles, + TResState, + TArticle, + TC11N, +} from '@/spec' import { EVENT } from '@/constant' import { buildLog, send } from '@/utils' -import Pagi from '@/components/Pagi' import ArticleList from './ArticleList' -import CommunityRecommends from './CommunityRecommends' +// import CommunityRecommends from './CommunityRecommends' /* eslint-disable-next-line */ const log = buildLog('c:PagedArticles:index') +export const Pagi = dynamic(() => import('@/components/Pagi'), { + ssr: false, +}) + type TProps = { thread: TThread data: TPagedArticles @@ -24,6 +34,7 @@ type TProps = { // TODO: remove emptyPrefix?: string viewingArticle: TArticle + c11n: TC11N } const PagedArticles: FC = ({ @@ -32,6 +43,7 @@ const PagedArticles: FC = ({ resState, viewingArticle, emptyPrefix, + c11n, }) => { const { entries, ...pagi } = data @@ -43,6 +55,7 @@ const PagedArticles: FC = ({ entries={entries} resState={resState} emptyPrefix={emptyPrefix} + c11n={c11n} /> = ({ onChange={(page) => send(EVENT.REFRESH_ARTICLES, { page })} margin={{ bottom: '60px', top: '60px' }} > - +
todo
+ {/* */}
) diff --git a/src/components/Pagi/Next/Bottom.js b/src/components/Pagi/Next/Bottom.tsx similarity index 76% rename from src/components/Pagi/Next/Bottom.js rename to src/components/Pagi/Next/Bottom.tsx index ffb6bb715..1fd056ade 100755 --- a/src/components/Pagi/Next/Bottom.js +++ b/src/components/Pagi/Next/Bottom.tsx @@ -1,8 +1,9 @@ -import React from 'react' +import { FC, memo } from 'react' import { ICON } from '@/config' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' +import type { TProps as TIndex } from '../Perv' import { Wrapper, ArrowWrapper, @@ -12,9 +13,8 @@ import { Hint, } from '../styles/next/bottom' -const Bottom = ({ disabled, pageNumber, onChange }) => { - const { isMobile } = useDevice() - +type TProps = Omit +const Bottom: FC = ({ disabled, pageNumber, onChange }) => { const iconSrc = !isMobile ? `${ICON}/shape/arrow.svg` : `${ICON}/shape/arrow-simple.svg` @@ -46,4 +46,4 @@ const Bottom = ({ disabled, pageNumber, onChange }) => { ) } -export default React.memo(Bottom) +export default memo(Bottom) diff --git a/src/components/Pagi/Next/Center.js b/src/components/Pagi/Next/Center.tsx similarity index 76% rename from src/components/Pagi/Next/Center.js rename to src/components/Pagi/Next/Center.tsx index a12609c09..da1cb569a 100755 --- a/src/components/Pagi/Next/Center.js +++ b/src/components/Pagi/Next/Center.tsx @@ -1,8 +1,9 @@ -import React from 'react' +import { FC, memo } from 'react' import { ICON } from '@/config' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' +import type { TProps as TIndex } from '../Perv' import { Wrapper, ArrowWrapper, @@ -12,9 +13,8 @@ import { Hint, } from '../styles/next/center' -const Center = ({ disabled, pageNumber, onChange }) => { - const { isMobile } = useDevice() - +type TProps = Omit +const Center: FC = ({ disabled, pageNumber, onChange }) => { const iconSrc = !isMobile ? `${ICON}/shape/arrow.svg` : `${ICON}/shape/arrow-simple.svg` @@ -46,4 +46,4 @@ const Center = ({ disabled, pageNumber, onChange }) => { ) } -export default React.memo(Center) +export default memo(Center) diff --git a/src/components/Pagi/Next/index.js b/src/components/Pagi/Next/index.js deleted file mode 100755 index b44eae7cb..000000000 --- a/src/components/Pagi/Next/index.js +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react' - -import Center from './Center' -import Bottom from './Bottom' - -const Next = ({ type, ...restProps }) => { - switch (type) { - case 'center': - return
- - default: { - return - } - } -} - -export default React.memo(Next) diff --git a/src/components/Pagi/Perv/index.js b/src/components/Pagi/Next/index.tsx similarity index 58% rename from src/components/Pagi/Perv/index.js rename to src/components/Pagi/Next/index.tsx index b8f3d093d..4b92ad19d 100755 --- a/src/components/Pagi/Perv/index.js +++ b/src/components/Pagi/Next/index.tsx @@ -1,9 +1,10 @@ -import React from 'react' +import { FC, memo } from 'react' +import { TProps } from '../Perv' import Center from './Center' import Bottom from './Bottom' -const Perv = ({ type, ...restProps }) => { +const Next: FC = ({ type, ...restProps }) => { switch (type) { case 'center': return
@@ -14,4 +15,4 @@ const Perv = ({ type, ...restProps }) => { } } -export default React.memo(Perv) +export default memo(Next) diff --git a/src/components/Pagi/Perv/Bottom.js b/src/components/Pagi/Perv/Bottom.tsx similarity index 76% rename from src/components/Pagi/Perv/Bottom.js rename to src/components/Pagi/Perv/Bottom.tsx index 18bf08ff3..a728a877d 100755 --- a/src/components/Pagi/Perv/Bottom.js +++ b/src/components/Pagi/Perv/Bottom.tsx @@ -1,8 +1,9 @@ -import React from 'react' +import { FC, memo } from 'react' import { ICON } from '@/config' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' +import type { TProps as TIndex } from './index' import { Wrapper, ArrowWrapper, @@ -12,9 +13,9 @@ import { Hint, } from '../styles/perv/bottom' -const Bottom = ({ disabled, pageNumber, onChange }) => { - const { isMobile } = useDevice() +type TProps = Omit +const Bottom: FC = ({ disabled, pageNumber, onChange }) => { const iconSrc = !isMobile ? `${ICON}/shape/arrow.svg` : `${ICON}/shape/arrow-simple.svg` @@ -46,4 +47,4 @@ const Bottom = ({ disabled, pageNumber, onChange }) => { ) } -export default React.memo(Bottom) +export default memo(Bottom) diff --git a/src/components/Pagi/Perv/Center.js b/src/components/Pagi/Perv/Center.tsx similarity index 76% rename from src/components/Pagi/Perv/Center.js rename to src/components/Pagi/Perv/Center.tsx index 214a204e7..c29d4265b 100755 --- a/src/components/Pagi/Perv/Center.js +++ b/src/components/Pagi/Perv/Center.tsx @@ -1,8 +1,9 @@ -import React from 'react' +import { FC, memo } from 'react' import { ICON } from '@/config' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' +import type { TProps as TIndex } from './index' import { Wrapper, ArrowWrapper, @@ -12,9 +13,9 @@ import { Hint, } from '../styles/perv/center' -const Center = ({ disabled, pageNumber, onChange }) => { - const { isMobile } = useDevice() +type TProps = Omit +const Center: FC = ({ disabled, pageNumber, onChange }) => { const iconSrc = !isMobile ? `${ICON}/shape/arrow.svg` : `${ICON}/shape/arrow-simple.svg` @@ -46,4 +47,4 @@ const Center = ({ disabled, pageNumber, onChange }) => { ) } -export default React.memo(Center) +export default memo(Center) diff --git a/src/components/Pagi/Perv/index.tsx b/src/components/Pagi/Perv/index.tsx new file mode 100755 index 000000000..2cf14bbf0 --- /dev/null +++ b/src/components/Pagi/Perv/index.tsx @@ -0,0 +1,24 @@ +import { FC, memo } from 'react' + +import Center from './Center' +import Bottom from './Bottom' + +export type TProps = { + type?: 'bottom' | 'center' + pageNumber: number + disabled?: boolean + onChange?: (page: number) => void +} + +const Perv: FC = ({ type, ...restProps }) => { + switch (type) { + case 'center': + return
+ + default: { + return + } + } +} + +export default memo(Perv) diff --git a/src/components/Pagi/index.js b/src/components/Pagi/index.tsx similarity index 59% rename from src/components/Pagi/index.js rename to src/components/Pagi/index.tsx index 8e0e39878..caf32af75 100755 --- a/src/components/Pagi/index.js +++ b/src/components/Pagi/index.tsx @@ -4,15 +4,16 @@ * */ -import React from 'react' -import T from 'prop-types' +import { FC, memo, ReactNode } from 'react' import { merge } from 'ramda' +import type { TSpace } from '@/spec' import { buildLog } from '@/utils' import Perv from './Perv' import Next from './Next' import { Wrapper, EmptyWrapper, BottomMsg } from './styles' + /* eslint-disable-next-line */ const log = buildLog('c:Pagi:index') @@ -28,7 +29,7 @@ const defaultMargin = { * @param precision The number of decimal places to preserve * see: https://stackoverflow.com/questions/5191088/how-to-round-up-a-number-in-javascript */ -const roundUp = (num, precision = 0) => { +const roundUp = (num: number, precision = 0): number => { // eslint-disable-next-line no-restricted-properties precision = Math.pow(10, precision) return Math.ceil(num * precision) / precision @@ -41,23 +42,37 @@ const BottomFooter = ({ show, msg }) => { const hasExtraPage = (totalCount, pageSize) => totalCount > pageSize -const Pagi = ({ - children, - type, - pageNumber, - pageSize, - totalCount, - margin: marginProp, - onChange, - showBottomMsg, - emptyMsg, - noMoreMsg, +type TProps = { + children?: ReactNode + type?: 'bottom' | 'center' + pageNumber?: number + pageSize?: number + totalCount?: number + margin?: TSpace + emptyMsg?: string + noMoreMsg?: string + showBottomMsg?: boolean + onChange?: (page: number) => void +} + +const Pagi: FC = ({ + children =
, + type = 'bottom', + pageNumber = 0, + pageSize = 0, + totalCount = 0, + onChange = log, + + margin = {}, + showBottomMsg = false, + emptyMsg = '还没有评论', + noMoreMsg = '没有更多评论了', }) => { - const margin = merge(defaultMargin, marginProp) + const theMargin = merge(defaultMargin, margin) if (totalCount === 0) { return ( - + ) @@ -66,7 +81,7 @@ const Pagi = ({ return ( <> {hasExtraPage(totalCount, pageSize) ? ( - + ) : ( - + )} @@ -90,40 +105,4 @@ const Pagi = ({ ) } -Pagi.propTypes = { - children: T.node, - type: T.oneOf(['bottom', 'center']), - pageNumber: T.number, - pageSize: T.number, - totalCount: T.number, - margin: T.shape({ - top: T.string, - bottom: T.string, - left: T.string, - right: T.string, - }), - emptyMsg: T.string, - noMoreMsg: T.string, - showBottomMsg: T.bool, - onChange: T.func, -} - -Pagi.defaultProps = { - children:
, - type: 'bottom', - pageNumber: 0, - pageSize: 0, - totalCount: 0, - onChange: log, - margin: { - top: '0', - bottom: '0', - left: '0', - right: '0', - }, - showBottomMsg: false, - emptyMsg: '还没有评论', - noMoreMsg: '没有更多评论了', -} - -export default React.memo(Pagi) +export default memo(Pagi) diff --git a/src/components/Pagi/styles/next/bottom.ts b/src/components/Pagi/styles/next/bottom.ts index a5dd4ea37..b527b9120 100755 --- a/src/components/Pagi/styles/next/bottom.ts +++ b/src/components/Pagi/styles/next/bottom.ts @@ -4,7 +4,7 @@ import { css } from '@/utils' import { CommonNavi, CommonHint, CommonBottomArrowIcon } from '../index' -export const Wrapper = styled.div<{ disabled: boolean }>` +export const Wrapper = styled.div<{ disabled?: boolean }>` ${css.flex('align-end')}; color: #196780; @@ -25,7 +25,7 @@ export const Icon = styled(CommonBottomArrowIcon)` fill: #327faf; } ` -export const NaviInfo = styled.div<{ disabled: boolean }>` +export const NaviInfo = styled.div<{ disabled?: boolean }>` ${css.flexColumn('align-end')}; margin-right: 10px; diff --git a/src/components/Pagi/styles/next/center.ts b/src/components/Pagi/styles/next/center.ts index 7d69fa11b..2416c4be4 100755 --- a/src/components/Pagi/styles/next/center.ts +++ b/src/components/Pagi/styles/next/center.ts @@ -4,7 +4,7 @@ import { css } from '@/utils' import { CommonNavi, CommonHint, CommonCenterArrowIcon } from '../index' -export const Wrapper = styled.div<{ disabled: boolean }>` +export const Wrapper = styled.div<{ disabled?: boolean }>` ${css.flex('align-center')}; color: #196780; @@ -19,7 +19,7 @@ export const Icon = styled(CommonCenterArrowIcon)` fill: #327faf; } ` -export const NaviInfo = styled.div<{ disabled: boolean }>` +export const NaviInfo = styled.div<{ disabled?: boolean }>` ${css.flexColumn('align-center')}; margin-right: 10px; diff --git a/src/components/Pagi/styles/perv/bottom.ts b/src/components/Pagi/styles/perv/bottom.ts index 5a0a7d2ab..7fefc708d 100755 --- a/src/components/Pagi/styles/perv/bottom.ts +++ b/src/components/Pagi/styles/perv/bottom.ts @@ -4,7 +4,7 @@ import { css } from '@/utils' import { CommonNavi, CommonHint, CommonBottomArrowIcon } from '../index' -export const Wrapper = styled.div<{ disabled: boolean }>` +export const Wrapper = styled.div<{ disabled?: boolean }>` ${css.flex('align-end', 'justify-end')}; color: #196780; @@ -24,7 +24,7 @@ export const Icon = styled(CommonBottomArrowIcon)` fill: #327faf; } ` -export const NaviInfo = styled.div<{ disabled: boolean }>` +export const NaviInfo = styled.div<{ disabled?: boolean }>` ${css.flexColumn('align-start')}; margin-left: 8px; diff --git a/src/components/Pagi/styles/perv/center.ts b/src/components/Pagi/styles/perv/center.ts index c36814435..e8213b053 100755 --- a/src/components/Pagi/styles/perv/center.ts +++ b/src/components/Pagi/styles/perv/center.ts @@ -4,7 +4,7 @@ import { css } from '@/utils' import { CommonNavi, CommonHint, CommonCenterArrowIcon } from '../index' -export const Wrapper = styled.div<{ disabled: boolean }>` +export const Wrapper = styled.div<{ disabled?: boolean }>` ${css.flex('align-center')}; color: #196780; @@ -21,7 +21,7 @@ export const Icon = styled(CommonCenterArrowIcon)` } ` -export const NaviInfo = styled.div<{ disabled: boolean }>` +export const NaviInfo = styled.div<{ disabled?: boolean }>` ${css.flexColumn('align-center')}; margin-left: 10px; ${Wrapper}:hover & { diff --git a/src/components/PostItem/DigestView/index.tsx b/src/components/PostItem/DigestView/index.tsx index 865ea7668..c53d727e0 100644 --- a/src/components/PostItem/DigestView/index.tsx +++ b/src/components/PostItem/DigestView/index.tsx @@ -1,13 +1,11 @@ import { Fragment } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView/index' import MobileView from './MobileView/index' const DigestView = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/components/PostItem/index.tsx b/src/components/PostItem/index.tsx index 1c4b3768f..efa13a5f1 100755 --- a/src/components/PostItem/index.tsx +++ b/src/components/PostItem/index.tsx @@ -5,13 +5,12 @@ */ import { FC, memo } from 'react' +import dynamic from 'next/dynamic' -import type { TPost, TID, TUser, TAccount } from '@/spec' +import type { TPost, TID, TUser, TAccount, TC11N } from '@/spec' import { buildLog } from '@/utils' -import { useAccount } from '@/hooks' - -import ArticleItemPrefixLabel from '@/components/ArticleItemPrefixLabel' +// import ArticleItemPrefixLabel from '@/components/ArticleItemPrefixLabel' import DigestView from './DigestView/index' // import ListView from './ListView' @@ -20,9 +19,17 @@ import { Wrapper } from './styles' /* eslint-disable-next-line */ const log = buildLog('c:PostItem:index') +export const ArticleItemPrefixLabel = dynamic( + () => import('@/components/ArticleItemPrefixLabel'), + { + ssr: false, + }, +) + type TProps = { activeId?: TID | null entry: TPost + c11n: TC11N onUserSelect?: (obj: TUser) => void onAuthorSelect?: (obj: TAccount) => void @@ -33,9 +40,8 @@ const PostItem: FC = ({ onUserSelect = log, onAuthorSelect = log, activeId = null, + c11n, }) => { - const { c11n } = useAccount() - return ( diff --git a/src/components/Switcher/Tabs/DesktopView.tsx b/src/components/Switcher/Tabs/DesktopView.tsx index 9bb47f36f..ac8e3df2d 100644 --- a/src/components/Switcher/Tabs/DesktopView.tsx +++ b/src/components/Switcher/Tabs/DesktopView.tsx @@ -8,7 +8,7 @@ import { FC, useEffect, useRef, useState, useCallback, memo } from 'react' import { isEmpty, findIndex } from 'ramda' import type { TSIZE_SM, TTabItem, TC11NLayout } from '@/spec' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { SIZE, C11N } from '@/constant' import { buildLog, isString } from '@/utils' @@ -66,8 +66,6 @@ const Tabs: FC = ({ activeKey = '', slipHeight = '2px', }) => { - const { isMobile } = useDevice() - const defaultActiveTabIndex = getDefaultActiveTabIndex(items, activeKey) const [active, setActive] = useState(defaultActiveTabIndex) diff --git a/src/components/Switcher/Tabs/MobileView/ExpandView.tsx b/src/components/Switcher/Tabs/MobileView/ExpandView.tsx index f3c9fd383..02603cf62 100644 --- a/src/components/Switcher/Tabs/MobileView/ExpandView.tsx +++ b/src/components/Switcher/Tabs/MobileView/ExpandView.tsx @@ -9,7 +9,7 @@ import { FC, useEffect, useRef, useState, useCallback, memo } from 'react' import type { TSIZE_SM, TTabItem } from '@/spec' import { ICON } from '@/config' import { SIZE } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog, isString } from '@/utils' import TabItem from '../TabItem' @@ -38,8 +38,6 @@ const MobileView: FC = ({ activeKey = '', toggleExpand, }) => { - const { isMobile } = useDevice() - const [tabWidthList, setTabWidthList] = useState([]) const [showMore, setShowMore] = useState(false) const navRef = useRef(null) diff --git a/src/components/Switcher/Tabs/MobileView/NormalView.tsx b/src/components/Switcher/Tabs/MobileView/NormalView.tsx index ead3dbe8d..78d6dd8ac 100644 --- a/src/components/Switcher/Tabs/MobileView/NormalView.tsx +++ b/src/components/Switcher/Tabs/MobileView/NormalView.tsx @@ -10,7 +10,7 @@ import { isEmpty, findIndex } from 'ramda' import type { TSIZE_SM, TTabItem } from '@/spec' import { ICON } from '@/config' import { SIZE } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog, isString } from '@/utils' import TabItem from '../TabItem' @@ -74,8 +74,6 @@ const MobileView: FC = ({ slipHeight = '2px', toggleExpand, }) => { - const { isMobile } = useDevice() - const defaultActiveTabIndex = getDefaultActiveTabIndex(items, activeKey) const [active, setActive] = useState(defaultActiveTabIndex) diff --git a/src/components/Switcher/Tabs/ModelineView.tsx b/src/components/Switcher/Tabs/ModelineView.tsx index f38e83aa0..2c43537d1 100644 --- a/src/components/Switcher/Tabs/ModelineView.tsx +++ b/src/components/Switcher/Tabs/ModelineView.tsx @@ -8,7 +8,7 @@ import { FC, useEffect, useRef, useState, useCallback, memo } from 'react' import { isEmpty, findIndex } from 'ramda' import type { TSIZE_SM, TTabItem } from '@/spec' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { SIZE } from '@/constant' import { buildLog, isString } from '@/utils' @@ -68,8 +68,6 @@ const ModelineView: FC = ({ activeKey = '', slipHeight = '2px', }) => { - const { isMobile } = useDevice() - const defaultActiveTabIndex = getDefaultActiveTabIndex(items, activeKey) const [active, setActive] = useState(defaultActiveTabIndex) diff --git a/src/components/Switcher/Tabs/index.tsx b/src/components/Switcher/Tabs/index.tsx index 8c31a0e5d..3f5f4ca2c 100644 --- a/src/components/Switcher/Tabs/index.tsx +++ b/src/components/Switcher/Tabs/index.tsx @@ -7,7 +7,7 @@ import { memo } from 'react' import { VIEW } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog } from '@/utils' import DesktopView from './DesktopView' @@ -19,8 +19,6 @@ import DrawerView from './DrawerView' const log = buildLog('c:Tabs:index') const Tabs = (props) => { - const { isMobile } = useDevice() - const { view } = props const curMedia = isMobile ? VIEW.MOBILE : VIEW.DESKTOP diff --git a/src/components/TabBar/MobileView.tsx b/src/components/TabBar/MobileView.tsx index a957271ba..f80df71fb 100644 --- a/src/components/TabBar/MobileView.tsx +++ b/src/components/TabBar/MobileView.tsx @@ -1,7 +1,7 @@ import { memo } from 'react' import { sortByIndex } from '@/utils' -import { Tabs } from '@/components/Switcher' +import Tabs from '@/components/Switcher/Tabs' // priority: icon > localIcon || raw const getLocalIcon = (item) => { diff --git a/src/components/TabBar/index.tsx b/src/components/TabBar/index.tsx index dd67645e3..4b886879a 100755 --- a/src/components/TabBar/index.tsx +++ b/src/components/TabBar/index.tsx @@ -5,7 +5,7 @@ import { memo } from 'react' import { VIEW } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { buildLog } from '@/utils' import DesktopView from './DesktopView' @@ -16,7 +16,6 @@ const log = buildLog('c:TabBar:index') const TabBar = (props) => { // const { view } = props - const { isMobile } = useDevice() const curMedia = isMobile ? VIEW.MOBILE : VIEW.DESKTOP // const curView = view && view === 'auto' ? curMedia : view diff --git a/src/components/Tooltip/RealTooltip.tsx b/src/components/Tooltip/RealTooltip.tsx new file mode 100755 index 000000000..6437cd25f --- /dev/null +++ b/src/components/Tooltip/RealTooltip.tsx @@ -0,0 +1,172 @@ +/* + * Tooltip + + * use custom animation Globally at GlobalStyle.ts + */ + +import { FC, ReactNode, useState, useRef, memo } from 'react' +import { hideAll } from 'tippy.js' + +import type { TTooltipPlacement } from '@/spec' +import { css, buildLog, isDescendant, isString } from '@/utils' +import { useOutsideClick } from '@/hooks' + +import ConfirmFooter from './ConfirmFooter' +import { FOOTER_BEHAVIOR } from './constant' + +import { + StyledTippy, + NoPaddingStyledTippy, + ChildrenWrapper, + ContentWrapper, + TopArrow, + BottomArrow, + LeftArrow, +} from './styles' + +/* eslint-disable-next-line */ +const log = buildLog('c:Tooltip:index') + +type TProps = { + children: ReactNode + content: string | ReactNode + placement?: TTooltipPlacement + // more options see: https://atomiks.github.io/tippyjs/all-options/ + delay?: number + duration?: number + trigger?: 'mouseenter focus' | 'click' + hideOnClick?: boolean + noPadding?: boolean + showArrow?: boolean + behavior?: 'default' | 'confirm' | 'delete-confirm' | 'add' + // currently only for AvatarsRow, it will collapse the height + // for same reason, figure out later + contentHeight?: string + + /** + * z-index is a magic number for IconSwitcher's mask situation, + * DO NOT USE unless you know what you are doing + * 在类似 IconSwitcher 的场景下(有一个基于 positon: absolute 的滑动遮罩)的场景下,需要将外层 + * 的 ChildrenWrapper z-index 置为 1, 否则滑动遮罩会在最外面。 + * + * 理论上 zIndex 一直设置为 1,也没问题,但是会导致某些使用了 Tooltip 的地方有严重的粘滞感,比如 “CopyRight” 那里。 + * 暂时没有精力看 Tippy 的具体实现,小心使用。 + */ + forceZIndex?: boolean + + onShow?: () => void + onHide?: () => void + onConfirm?: () => void +} + +const Tooltip: FC = ({ + children, + noPadding = false, + onHide, + onShow, + placement = 'top', + delay = 0, + duration = 0, + content, + hideOnClick = true, + showArrow = false, + forceZIndex = false, + behavior = 'default', + trigger = 'mouseenter focus', + onConfirm, + contentHeight, +}) => { + const [instance, setInstance] = useState(null) + const [active, setActive] = useState(false) + + const ContentComp = showArrow ? ( + + {active && placement === 'bottom' && } + {active && placement === 'top' && } + {active && placement === 'right' && } + +
{children}
+
+ ) : ( + +
{children}
+
+ ) + + const contentRef = useRef() + + const PopoverContent = ( + { + if (hideOnClick) instance?.hide() + }} + > + {content} + {active && behavior !== FOOTER_BEHAVIOR.DEFAULT && ( + { + onConfirm?.() + instance?.hide() + }} + onCancel={() => instance?.hide()} + behavior={behavior} + /> + )} + + ) + + const ref = useRef() + + useOutsideClick(ref, (e) => { + if (!instance) return false + + const isClickInsidePopover = isDescendant(contentRef?.current, e.target) + if (hideOnClick || (!hideOnClick && !isClickInsidePopover)) { + // if (instance) { + // NOTE: this is a hack, svg will swallow events like click + // and the pointer-events solution not work + const { nodeName } = e.target + if (nodeName === 'svg' || nodeName === 'path') return false + + instance.hide() + } + }) + + const props = { + ref, + content: PopoverContent, + placement, + hideOnClick, + zIndex: css.zIndex.popover, + active: true, + delay: [delay, 0] as [number, number], + offset: [5, 5] as [number, number], + duration, + trigger, + // see https://github.com/atomiks/tippyjs/issues/751#issuecomment-611979594 for detail + interactive: true, + + onHide: () => { + setInstance(null) + setActive(false) + onHide?.() + }, + onShow: (instance) => { + // see https://github.com/atomiks/tippyjs/issues/260#issuecomment-462031748 + hideAll({ exclude: instance }) + setInstance(instance) + setActive(true) + onShow?.() + }, + } + + return !noPadding ? ( + {ContentComp} + ) : ( + {ContentComp} + ) +} + +export default memo(Tooltip) diff --git a/src/components/Tooltip/index.tsx b/src/components/Tooltip/index.tsx index 6437cd25f..47e4826c1 100755 --- a/src/components/Tooltip/index.tsx +++ b/src/components/Tooltip/index.tsx @@ -4,25 +4,26 @@ * use custom animation Globally at GlobalStyle.ts */ -import { FC, ReactNode, useState, useRef, memo } from 'react' -import { hideAll } from 'tippy.js' +import { FC, Fragment, ReactNode, memo, createContext, useContext } from 'react' +import dynamic from 'next/dynamic' import type { TTooltipPlacement } from '@/spec' -import { css, buildLog, isDescendant, isString } from '@/utils' -import { useOutsideClick } from '@/hooks' +import { buildLog } from '@/utils' -import ConfirmFooter from './ConfirmFooter' -import { FOOTER_BEHAVIOR } from './constant' +// @ts-ignore +const TooltipContext = createContext() -import { - StyledTippy, - NoPaddingStyledTippy, - ChildrenWrapper, - ContentWrapper, - TopArrow, - BottomArrow, - LeftArrow, -} from './styles' +const RealTooltip = dynamic(() => import('./RealTooltip'), { + /* eslint-disable react/display-name */ + loading: () => { + // eslint-disable-next-line react-hooks/rules-of-hooks + const { children } = useContext(TooltipContext) as { + children: ReactNode + } + return {children} + }, + ssr: false, +}) /* eslint-disable-next-line */ const log = buildLog('c:Tooltip:index') @@ -59,113 +60,12 @@ type TProps = { onConfirm?: () => void } -const Tooltip: FC = ({ - children, - noPadding = false, - onHide, - onShow, - placement = 'top', - delay = 0, - duration = 0, - content, - hideOnClick = true, - showArrow = false, - forceZIndex = false, - behavior = 'default', - trigger = 'mouseenter focus', - onConfirm, - contentHeight, -}) => { - const [instance, setInstance] = useState(null) - const [active, setActive] = useState(false) - - const ContentComp = showArrow ? ( - - {active && placement === 'bottom' && } - {active && placement === 'top' && } - {active && placement === 'right' && } - -
{children}
-
- ) : ( - -
{children}
-
- ) - - const contentRef = useRef() - - const PopoverContent = ( - { - if (hideOnClick) instance?.hide() - }} - > - {content} - {active && behavior !== FOOTER_BEHAVIOR.DEFAULT && ( - { - onConfirm?.() - instance?.hide() - }} - onCancel={() => instance?.hide()} - behavior={behavior} - /> - )} - - ) - - const ref = useRef() - - useOutsideClick(ref, (e) => { - if (!instance) return false - - const isClickInsidePopover = isDescendant(contentRef?.current, e.target) - if (hideOnClick || (!hideOnClick && !isClickInsidePopover)) { - // if (instance) { - // NOTE: this is a hack, svg will swallow events like click - // and the pointer-events solution not work - const { nodeName } = e.target - if (nodeName === 'svg' || nodeName === 'path') return false - - instance.hide() - } - }) - - const props = { - ref, - content: PopoverContent, - placement, - hideOnClick, - zIndex: css.zIndex.popover, - active: true, - delay: [delay, 0] as [number, number], - offset: [5, 5] as [number, number], - duration, - trigger, - // see https://github.com/atomiks/tippyjs/issues/751#issuecomment-611979594 for detail - interactive: true, - - onHide: () => { - setInstance(null) - setActive(false) - onHide?.() - }, - onShow: (instance) => { - // see https://github.com/atomiks/tippyjs/issues/260#issuecomment-462031748 - hideAll({ exclude: instance }) - setInstance(instance) - setActive(true) - onShow?.() - }, - } - - return !noPadding ? ( - {ContentComp} - ) : ( - {ContentComp} +const Tooltip: FC = (props) => { + const { children } = props + return ( + + + ) } diff --git a/src/components/Upvote/UpvoteBtn.tsx b/src/components/Upvote/UpvoteBtn.tsx index 50bf35a74..d473507b3 100644 --- a/src/components/Upvote/UpvoteBtn.tsx +++ b/src/components/Upvote/UpvoteBtn.tsx @@ -7,7 +7,6 @@ import { FC, memo, useState, useCallback } from 'react' import type { TUser, TUpvoteLayout } from '@/spec' -import { ICON } from '@/config' import { buildLog } from '@/utils' import { @@ -60,11 +59,7 @@ const UpvoteBtn: FC = ({ ) : ( )} - +
diff --git a/src/components/Upvote/styles/upvote_btn.ts b/src/components/Upvote/styles/upvote_btn.ts index d2301c6f5..dd04fa0cd 100644 --- a/src/components/Upvote/styles/upvote_btn.ts +++ b/src/components/Upvote/styles/upvote_btn.ts @@ -3,7 +3,7 @@ import styled, { keyframes } from 'styled-components' import type { TUpvoteLayout, TActive } from '@/spec' import { UPVOTE_LAYOUT } from '@/constant' -import Img from '@/Img' +import UpvoteIcon from '@/icons/Upvote' import { css, theme } from '@/utils' import { @@ -196,7 +196,7 @@ export const ArticleShipWindow = styled(ShipWindow)` ` type TUpIcon = { type: TUpvoteLayout } & TActive -export const UpIcon = styled(Img)` +export const UpIcon = styled(UpvoteIcon)` fill: ${({ $active }) => $active ? '#139B9D;' : theme('thread.articleDigest')}; diff --git a/src/components/VerifiedSign/index.js b/src/components/VerifiedSign/index.tsx similarity index 65% rename from src/components/VerifiedSign/index.js rename to src/components/VerifiedSign/index.tsx index 85d30d47a..b621318f8 100755 --- a/src/components/VerifiedSign/index.js +++ b/src/components/VerifiedSign/index.tsx @@ -4,8 +4,7 @@ * */ -import React from 'react' -import T from 'prop-types' +import { FC, memo } from 'react' import { ICON_CMD } from '@/config' import { buildLog } from '@/utils' @@ -37,21 +36,23 @@ const PopContent = ({ communityTitle }) => { {communityTitle} 官方开通
- { - e.stopPropagation() - console.log('oo') - }} - > - 认证规则 - + 认证规则 ) } -const VerifiedSign = ({ text, type, communityTitle }) => { +type TProps = { + type?: 'community' | 'editor' + text?: string + communityTitle?: string +} + +const VerifiedSign: FC = ({ + text = '官方', + type = 'community', + communityTitle = 'groupher', +}) => { log('type: ', type) return ( @@ -65,16 +66,4 @@ const VerifiedSign = ({ text, type, communityTitle }) => { ) } -VerifiedSign.propTypes = { - type: T.oneOf(['community', 'editor']), - text: T.string, - communityTitle: T.string, -} - -VerifiedSign.defaultProps = { - type: 'community', - text: '官方', - communityTitle: 'groupher', -} - -export default React.memo(VerifiedSign) +export default memo(VerifiedSign) diff --git a/src/components/ViewportTracker/index.tsx b/src/components/ViewportTracker/index.tsx new file mode 100755 index 000000000..507a4c387 --- /dev/null +++ b/src/components/ViewportTracker/index.tsx @@ -0,0 +1,28 @@ +// avold SSR to save first load build size +import { FC } from 'react' + +import dynamic from 'next/dynamic' + +type TProps = { + /** + * Function called when waypoint enters viewport + */ + onEnter: () => void + /** + * Function called when waypoint leaves viewport + */ + onLeave?: () => void + /** + * Whether to activate on horizontal scrolling instead of vertical + */ + horizontal?: boolean +} + +const Waypoint = dynamic( + () => import('react-waypoint').then((mod) => mod.Waypoint), + { + ssr: false, + }, +) + +export default Waypoint as FC diff --git a/src/components/ViewportTracker/styles/index.ts b/src/components/ViewportTracker/styles/index.ts new file mode 100755 index 000000000..1dadcf108 --- /dev/null +++ b/src/components/ViewportTracker/styles/index.ts @@ -0,0 +1,12 @@ +import styled from 'styled-components' + +import type { TTestable } from '@/spec' + +// import Img from '@/Img' +// import { theme } from '@/utils' + +export const Wrapper = styled.div.attrs(({ testid }: TTestable) => ({ + 'data-test-id': testid, +}))`` + +export const Title = styled.div`` diff --git a/src/containers/viewer/PostViewer/tests/index.test.ts b/src/components/ViewportTracker/tests/index.test.ts similarity index 64% rename from src/containers/viewer/PostViewer/tests/index.test.ts rename to src/components/ViewportTracker/tests/index.test.ts index ceb1e1d9c..df121acb4 100755 --- a/src/containers/viewer/PostViewer/tests/index.test.ts +++ b/src/components/ViewportTracker/tests/index.test.ts @@ -1,9 +1,9 @@ // import React from 'react' // import { shallow } from 'enzyme' -// import PostViewer from '../index' +// import ViewportTracker from '../index' -describe('TODO ', () => { +describe('TODO ', () => { it('Expect to have unit tests specified', () => { expect(true).toEqual(true) }) diff --git a/src/containers/content/ArticleContent/DesktopView/index.tsx b/src/containers/content/ArticleContent/DesktopView/index.tsx index c8022e486..89c5be028 100644 --- a/src/containers/content/ArticleContent/DesktopView/index.tsx +++ b/src/containers/content/ArticleContent/DesktopView/index.tsx @@ -5,18 +5,19 @@ */ import { FC, useRef } from 'react' -import { Waypoint } from 'react-waypoint' +import dynamic from 'next/dynamic' import type { TMetric } from '@/spec' import { pluggedIn, buildLog } from '@/utils' -import Comments from '@/containers/unit/Comments' -// import ArticleAuthorCard from '@/containers/unit/ArticleAuthorCard' +// import Comments from '@/containers/unit/Comments' import ArticleSticker from '@/containers/tool/ArticleSticker' import ArticleFooter from '@/containers/unit/ArticleFooter' +import ViewportTracker from '@/components/ViewportTracker' import Maybe from '@/components/Maybe' import MarkDownRender from '@/components/MarkDownRender' +import { LavaLampLoading } from '@/components/Loading' import type { TStore } from '../store' @@ -34,6 +35,12 @@ import { useInit, checkAnchor } from '../logic' /* eslint-disable-next-line */ const log = buildLog('C:PostContent') +export const Comments = dynamic(() => import('@/containers/unit/Comments'), { + /* eslint-disable react/display-name */ + loading: () => , + ssr: false, +}) + type TProps = { articleContent?: TStore testid?: string @@ -54,20 +61,20 @@ const ArticleContentContainer: FC = ({ - checkAnchor(ref?.current)} onLeave={() => checkAnchor(ref?.current)} - /> + /> */} - checkAnchor(ref?.current)} onLeave={() => checkAnchor(ref?.current)} - /> + /> */} diff --git a/src/containers/content/ArticleContent/MobileView/index.tsx b/src/containers/content/ArticleContent/MobileView/index.tsx index 6ecae0116..9bdb887b0 100644 --- a/src/containers/content/ArticleContent/MobileView/index.tsx +++ b/src/containers/content/ArticleContent/MobileView/index.tsx @@ -5,16 +5,15 @@ */ import { FC } from 'react' -import { Waypoint } from 'react-waypoint' import { pluggedIn, buildLog } from '@/utils' import Comments from '@/containers/unit/Comments' -// import ArticleAuthorCard from '@/containers/unit/ArticleAuthorCard' import ArticleFooter from '@/containers/unit/ArticleFooter' import Maybe from '@/components/Maybe' import MarkDownRender from '@/components/MarkDownRender' +import ViewportTracker from '@/components/ViewportTracker' import type { TStore } from '../store' @@ -51,7 +50,10 @@ const PostContentContainer: FC = ({ - + {/* @ts-ignore */} diff --git a/src/containers/content/ArticleContent/index.tsx b/src/containers/content/ArticleContent/index.tsx index 0e0e39fd9..4d54273c7 100755 --- a/src/containers/content/ArticleContent/index.tsx +++ b/src/containers/content/ArticleContent/index.tsx @@ -6,14 +6,12 @@ import { Fragment } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView' const ArticleContent = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/containers/content/CommunityContent/HolyGrailLayout.tsx b/src/containers/content/CommunityContent/HolyGrailLayout.tsx index 136af3eb1..573503236 100644 --- a/src/containers/content/CommunityContent/HolyGrailLayout.tsx +++ b/src/containers/content/CommunityContent/HolyGrailLayout.tsx @@ -5,17 +5,17 @@ */ import { FC, memo } from 'react' +import dynamic from 'next/dynamic' import { TCommunity, TThread } from '@/spec' import { C11N, EVENT } from '@/constant' import { buildLog, send } from '@/utils' -import ThreadSidebar from '@/containers/thread/ThreadSidebar' - import TabBar from '@/components/TabBar' -import ThreadContent from './ThreadContent' +import { LavaLampLoading } from '@/components/Loading' +import ThreadContent from './ThreadContent' import SubscribedList from './SubscribedList' import { @@ -28,6 +28,15 @@ import { /* eslint-disable-next-line */ const log = buildLog('C:CommunityContent') +const ThreadSidebar = dynamic( + () => import('@/containers/thread/ThreadSidebar'), + { + /* eslint-disable react/display-name */ + loading: () => , + ssr: false, + }, +) + type TProps = { thread: TThread community: TCommunity diff --git a/src/containers/content/CommunityContent/ThreadContent.tsx b/src/containers/content/CommunityContent/ThreadContent.tsx index 768c21758..dc8e29168 100644 --- a/src/containers/content/CommunityContent/ThreadContent.tsx +++ b/src/containers/content/CommunityContent/ThreadContent.tsx @@ -4,7 +4,7 @@ import type { TThread } from '@/spec' import { THREAD } from '@/constant' import ArticlesThread from '@/containers//thread/ArticlesThread' -import ReposThread from '@/containers/thread/ReposThread' +// import ReposThread from '@/containers/thread/ReposThread' import UsersThread from '@/containers/thread/UsersThread' type TProps = { @@ -13,8 +13,8 @@ type TProps = { const ThreadContent: FC = ({ thread }) => { switch (thread) { - case THREAD.REPO: - return + // case THREAD.REPO: + // return case THREAD.USER: return diff --git a/src/containers/content/CommunityContent/index.tsx b/src/containers/content/CommunityContent/index.tsx index 6d95db9c0..3ed611d5a 100755 --- a/src/containers/content/CommunityContent/index.tsx +++ b/src/containers/content/CommunityContent/index.tsx @@ -1,13 +1,11 @@ /* - * - * CommunityContent - * + * CommunityContent. */ import { FC, Fragment } from 'react' +import { isMobile } from 'react-device-detect' import { C11N } from '@/constant' -import { useDevice } from '@/hooks' import { pluggedIn, buildLog } from '@/utils' import ClassicLayout from './ClassicLayout' @@ -25,7 +23,6 @@ type TProps = { const CommunityContentContainer: FC = ({ communityContent: store }) => { useInit(store) - const { isMobile } = useDevice() const { curThread, diff --git a/src/containers/content/RecipesContent/FilterBar.js b/src/containers/content/RecipesContent/FilterBar.js index 89b12d12a..bd6eb63ab 100644 --- a/src/containers/content/RecipesContent/FilterBar.js +++ b/src/containers/content/RecipesContent/FilterBar.js @@ -2,7 +2,6 @@ import React from 'react' import { ICON_CMD } from '@/config' import { RECIPE } from '@/constant' -import { useTrans } from '@/hooks' import Sticky from '@/components/Sticky' import { OrButton } from '@/components/Buttons' @@ -26,8 +25,6 @@ import { import { topFilterOnChange, mainViewOnChange } from './logic' const FilterBar = ({ mainView, topFilter, initActiveMenuId }) => { - const { t } = useTrans() - return ( @@ -38,13 +35,13 @@ const FilterBar = ({ mainView, topFilter, initActiveMenuId }) => { testid="filter-navi-intro" /> {topFilter !== 'all' && ( - + )} - + ) } diff --git a/src/containers/digest/ArticleDigest/MobileView/index.tsx b/src/containers/digest/ArticleDigest/MobileView/index.tsx index 110f75c85..0f2a72138 100644 --- a/src/containers/digest/ArticleDigest/MobileView/index.tsx +++ b/src/containers/digest/ArticleDigest/MobileView/index.tsx @@ -6,13 +6,14 @@ import { FC } from 'react' import { isNil } from 'ramda' -import { Waypoint } from 'react-waypoint' import type { TScrollDirection } from '@/spec' import { useScroll } from '@/hooks' import { pluggedIn, buildLog } from '@/utils' import ArticleBaseStats from '@/components/ArticleBaseStats' +import ViewportTracker from '@/components/ViewportTracker' + import PublishDate from '../DesktopView/PostLayout/PublishDate' import type { TStore } from '../store' @@ -51,7 +52,7 @@ const ArticleDigestContainer: FC = ({ articleDigest: store }) => { - +
) } diff --git a/src/containers/digest/ArticleDigest/index.tsx b/src/containers/digest/ArticleDigest/index.tsx index 6e54d60f6..fd746f884 100755 --- a/src/containers/digest/ArticleDigest/index.tsx +++ b/src/containers/digest/ArticleDigest/index.tsx @@ -6,14 +6,12 @@ import { Fragment } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView/index' const ArticleDigest = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx b/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx index c879a20f0..6f3df59cf 100644 --- a/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx +++ b/src/containers/digest/CommunityDigest/ClassicLayout/CommunityBrief.tsx @@ -1,12 +1,11 @@ import { FC, memo } from 'react' +import dynamic from 'next/dynamic' import { contains } from 'ramda' import type { TCommunity } from '@/spec' import { ICON_CMD } from '@/config' import { HCN, NON_FILL_COMMUNITY } from '@/constant' -import VerifiedSign from '@/components/VerifiedSign' - import ExpandTexts from '../ExpandTexts' import SocialList from '../SocialList' @@ -21,6 +20,12 @@ 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 = { diff --git a/src/containers/digest/CommunityDigest/ClassicLayout/index.tsx b/src/containers/digest/CommunityDigest/ClassicLayout/index.tsx index a0ac400b9..2c6eb5b6c 100644 --- a/src/containers/digest/CommunityDigest/ClassicLayout/index.tsx +++ b/src/containers/digest/CommunityDigest/ClassicLayout/index.tsx @@ -1,13 +1,13 @@ import { FC, memo } from 'react' import { contains } from 'ramda' -import { Waypoint } from 'react-waypoint' +import { isMobile } from 'react-device-detect' import type { TC11NLayout, TThread, TCommunity, TMetric } from '@/spec' import { HCN, EVENT } from '@/constant' -import { useDevice } from '@/hooks' import { send } from '@/utils' import TabBar from '@/components/TabBar' +import ViewportTracker from '@/components/ViewportTracker' import CommunityStatesPad from '@/components/CommunityStatesPad' import CommunityBrief from './CommunityBrief' @@ -40,8 +40,6 @@ const ClassicLayout: FC = ({ layout, metric, }) => { - const { isMobile } = useDevice() - return ( = ({ - setViewport(true)} onLeave={() => setViewport(false)} /> diff --git a/src/containers/digest/CommunityDigest/ExpandTexts.tsx b/src/containers/digest/CommunityDigest/ExpandTexts.tsx index a37c206e9..837720bb4 100644 --- a/src/containers/digest/CommunityDigest/ExpandTexts.tsx +++ b/src/containers/digest/CommunityDigest/ExpandTexts.tsx @@ -1,7 +1,7 @@ import { FC, memo } from 'react' import { ICON_CMD } from '@/config' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { cutRest } from '@/utils' import { @@ -24,7 +24,6 @@ type TProps = { } const ExpandTexts: FC = ({ descExpand }) => { - const { isMobile } = useDevice() const cutLength = !isMobile ? 26 : 10 return ( diff --git a/src/containers/editor/JobEditor/CompanyInfoEditor.js b/src/containers/editor/JobEditor/CompanyInfoEditor.js deleted file mode 100755 index d52d3073b..000000000 --- a/src/containers/editor/JobEditor/CompanyInfoEditor.js +++ /dev/null @@ -1,63 +0,0 @@ -import React from 'react' -import { isEmpty } from 'ramda' - -import DocUploader from '@/containers/tool/DocUploader' - -import { - Wrapper, - Content, - LogoUploadBox, - CompanyLogo, - CompanyInfo, - TitleInputer, - LinkInputer, - UploadHint, -} from './styles/company_info_editor' - -import { inputOnChange } from './logic' - -const CompanyInfoEditor = ({ - editData: { company, companyLogo, companyLink, desc }, -}) => ( - - - inputOnChange('companyLogo')} - pasteImage={false} - > - {isEmpty(companyLogo) ? ( - - 公司 Logo - - ) : ( - - )} - - -
- inputOnChange('company')} - /> -
-
- inputOnChange('companyLink')} - /> -
-
- inputOnChange('desc')} - /> -
-
-
-
-) - -export default React.memo(CompanyInfoEditor) diff --git a/src/containers/editor/JobEditor/Editor.js b/src/containers/editor/JobEditor/Editor.js deleted file mode 100755 index d6214138d..000000000 --- a/src/containers/editor/JobEditor/Editor.js +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Editor based on Draft - */ - -import React from 'react' -// import T from 'prop-types' - -import MarkdownEditor from '@/components/MarkdownEditor' -import ArticleEditToolbar from '@/components/ArticleEditToolbar' -import EditorFooter from './EditorFooter' - -import { Wrapper, TitleInput, FooterWrapper } from './styles/editor' - -import { - inputOnChange, - bodyInputOnChange, - onMention, - onMentionSearch, - changeView, -} from './logic' - -const Editor = ({ isEdit, thread, editData, mentionList }) => { - const { title, body } = editData - - return ( - - inputOnChange('copyRight')} - onLinkAddrChange={() => inputOnChange('linkAddr')} - onPreview={() => changeView('PREVIEW_VIEW')} - /> - - inputOnChange('title')} - /> - -
- - - - -
- ) -} - -export default React.memo(Editor) diff --git a/src/containers/editor/JobEditor/EditorFooter.js b/src/containers/editor/JobEditor/EditorFooter.js deleted file mode 100755 index a3f56691f..000000000 --- a/src/containers/editor/JobEditor/EditorFooter.js +++ /dev/null @@ -1,73 +0,0 @@ -import React from 'react' -import { pluck } from 'ramda' - -import { ICON_CMD } from '@/config' -import { uid } from '@/utils' - -import DocUploader from '@/containers/tool/DocUploader' -import Labeler from '@/containers/unit/Labeler' -import Maybe from '@/components/Maybe' - -import CompanyInfoEditor from './CompanyInfoEditor' - -import { - Wrapper, - Item, - ItemTitle, - ItemIcon, - Divider, -} from './styles/editor_footer' - -import { onUploadImageDone } from './logic' - -const PicUploader = ({ divider }) => ( - <> - - - - - - - 上传图片 - - - -) - -const LabelList = ({ data }) => ( - - - - - - - - - - - - - - - -) - -/* - NOTE, the uid.gen is a magic fix and i don't kown why.. - if not use uid.gen, the labels in create/edit is choas - */ -const EditorFooter = ({ isEdit, editData }) => ( -
- - - {isEdit ? ( - - ) : ( - - )} - - -
-) - -export default React.memo(EditorFooter) diff --git a/src/containers/editor/JobEditor/Header.js b/src/containers/editor/JobEditor/Header.js deleted file mode 100755 index 9e4fb6824..000000000 --- a/src/containers/editor/JobEditor/Header.js +++ /dev/null @@ -1,65 +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/JobEditor/MarkDownHelper.js b/src/containers/editor/JobEditor/MarkDownHelper.js deleted file mode 100755 index b14a60355..000000000 --- a/src/containers/editor/JobEditor/MarkDownHelper.js +++ /dev/null @@ -1,108 +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 notTooLong = (l) => l.length < 20 - -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/JobEditor/Preview.js b/src/containers/editor/JobEditor/Preview.js deleted file mode 100755 index 5ff99a5ca..000000000 --- a/src/containers/editor/JobEditor/Preview.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Editor based on Draft - */ - -import React from 'react' - -import { Button } from '@/components/Buttons' -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/JobEditor/emojis.js b/src/containers/editor/JobEditor/emojis.js deleted file mode 100755 index 691e521ab..000000000 --- a/src/containers/editor/JobEditor/emojis.js +++ /dev/null @@ -1,4 +0,0 @@ -// prettier-ignore -module.exports = { - ':alarm_clock:': '\u23F0', -}; diff --git a/src/containers/editor/JobEditor/index.js b/src/containers/editor/JobEditor/index.js deleted file mode 100755 index 1c651cbc4..000000000 --- a/src/containers/editor/JobEditor/index.js +++ /dev/null @@ -1,112 +0,0 @@ -/* - * - * jobEditor - * - */ - -import React from 'react' -import dynamic from 'next/dynamic' - -import { pluggedIn, buildLog } from '@/utils' - -import ArticleEditFooter from '@/components/ArticleEditFooter' -import { ArticleContentLoading } from '@/components/Loading' - -import Editor from './Editor' -import Preview from './Preview' -// import MarkDownHelper from './MarkDownHelper' -import Header from './Header' - -import { Wrapper, ViewerWrapper } from './styles' - -import { useInit, changeView, onPublish, cancelPublish } from './logic' - -export const MarkDownHelper = dynamic(() => import('./MarkDownHelper'), { - /* eslint-disable react/display-name */ - loading: () => , - ssr: false, -}) - -/* eslint-disable-next-line */ -const log = buildLog('C:JobEditor') - -const View = ({ - isEdit, - curView, - thread, - editData, - mentionList, - contentDomId, -}) => { - if (curView === 'CREATE_VIEW' || curView === 'PREVIEW_VIEW') { - return ( - <> - - - - - changeView('CREATE_VIEW')} - /> - - - ) - } - return -} - -const JobEditorContainer = ({ jobEditor: store, attachment }) => { - useInit(store, attachment) - - const { - copyRight, - thread, - curView, - publishing, - isEdit, - editData, - mentionListData, - referUsersData, - contentDomId, - } = store - - log('editData in views: ', editData) - - return ( - -
- - - - ) -} - -// JobEditorContainer.propTypes = { -// https://www.npmjs.com/package/prop-types -// closeDrawer: T.func.isRequired, -// } - -// JobEditorContainer.defaultProps = {} - -export default pluggedIn(JobEditorContainer) diff --git a/src/containers/editor/JobEditor/logic.js b/src/containers/editor/JobEditor/logic.js deleted file mode 100755 index 45ad6dfa4..000000000 --- a/src/containers/editor/JobEditor/logic.js +++ /dev/null @@ -1,246 +0,0 @@ -import { useEffect } from 'react' -import { merge, slice, trim, isEmpty, repeat } from 'ramda' - -import { TYPE, EVENT, ERR, THREAD } from '@/constant' -import { - asyncSuit, - buildLog, - send, - countWords, - extractAttachments, - extractMentions, - updateEditing, - closeDrawer, - cast, - nilOrEmpty, - errRescue, - BStore, -} from '@/utils' - -import { S, updatableJobFields } from './schema' - -/* eslint-disable-next-line */ -const log = buildLog('L:JobEditor') - -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 onPublish = () => { - if ( - !store.validator('general') || - !store.validator('companyInfo') || - !store.validator(`${THREAD.JOB}_LABELS`) - ) { - return false - } - - const { isEdit } = store - const { body } = store.editData - - const digest = getDigest(body) - const length = countWords(body) - - const variables = { - ...store.editData, - ...store.labelsData, - digest, - length, - communityId: store.viewing.community.id, - mentionUsers: store.referUsersData.map((user) => ({ id: user.id })), - } - - if (nilOrEmpty(variables.desc)) variables.desc = '不加班,福利好,美女多..' - - publishing() - if (isEdit) { - const args = cast( - updatableJobFields, - merge(variables, { tags: store.labelsData.tags }), - ) - return sr71$.mutate(S.updateJob, args) - } - - sr71$.mutate(S.createJob, 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 loadJob = (id) => sr71$.query(S.job, { id }) - -const openAttachment = (att) => { - if (!att) return false - // const { id, title, body, digest } = att - const { type } = att - if (type === TYPE.DRAWER.JOB_EDIT) loadJob(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) => { - store.mark({ extractMentions: extractMentions(content) }) - - if (store.isEdit && content === '') return false - // 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('createJob'), - action: () => { - store.toast('success', { - title: '招聘信息已发布', - msg: '预祝你在这里的招聘工作一切顺利 :)', - position: 'topCenter', - }) - - doneCleanUp() - clearDraft() - send(EVENT.REFRESH_JOBS) - }, - }, - { - match: asyncRes('updateJob'), - action: () => { - store.toast('success', { - title: '更新成功', - msg: '.', - position: 'topCenter', - }) - - doneCleanUp() - send(EVENT.REFRESH_JOBS) - }, - }, - - { - match: asyncRes('job'), - action: ({ job }) => store.updateEditing(job), - }, - { - 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: 'JobEditor' }) - }, - }, - { - match: asyncErr(ERR.NETWORK), - action: () => { - cancelLoading() - errRescue({ type: ERR.NETWORK, path: 'JobEditor' }) - }, - }, -] - -const initDraftTimmer = () => { - // only save draft in create mode - if (store.isEdit) return false - if (saveDraftTimmer) clearInterval(saveDraftTimmer) - - saveDraftTimmer = setInterval(() => saveDraftIfNeed(store.editJob.body), 3000) -} - -// ############################### -// init & uninit -// ############################### -export const useInit = (_store, attachment) => { - useEffect(() => { - store = _store - // log('effect init') - sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) - openAttachment(attachment) - initDraftTimmer() - - return () => { - // log('effect uninit') - if (saveDraftTimmer) clearInterval(saveDraftTimmer) - store.mark({ editJob: {} }) - sr71$.stop() - sub$.unsubscribe() - } - }, [_store, attachment]) -} diff --git a/src/containers/editor/JobEditor/schema.ts b/src/containers/editor/JobEditor/schema.ts deleted file mode 100755 index 33d29a9f0..000000000 --- a/src/containers/editor/JobEditor/schema.ts +++ /dev/null @@ -1,158 +0,0 @@ -import gql from 'graphql-tag' -import { F } from '@/schemas' - -const createJob = gql` - mutation( - $title: String! - $body: String! - $desc: String - $digest: String! - $length: Int! - $communityId: ID! - $company: String! - $companyLogo: String! - $companyLink: String - $copyRight: String - $linkAddr: String - $salary: String! - $exp: String! - $education: String! - $finance: String! - $scale: String! - $field: String! - $mentionUsers: [Ids] - $tags: [Ids] - ) { - createJob( - title: $title - body: $body - desc: $desc - digest: $digest - length: $length - communityId: $communityId - company: $company - companyLogo: $companyLogo - companyLink: $companyLink - copyRight: $copyRight - linkAddr: $linkAddr - salary: $salary - exp: $exp - education: $education - finance: $finance - scale: $scale - field: $field - mentionUsers: $mentionUsers - tags: $tags - ) { - id - title - body - salary - exp - education - field - communities { - id - title - } - } - } -` - -const updateJob = gql` - mutation( - $id: ID! - $title: String - $body: String - $desc: String - $digest: String - $length: Int - $company: String - $companyLogo: String - $companyLink: String - $copyRight: String - $salary: String - $exp: String - $education: String - $finance: String - $scale: String - $field: String - $tags: [Ids] - ) { - updateJob( - id: $id - title: $title - body: $body - desc: $desc - digest: $digest - length: $length - company: $company - companyLogo: $companyLogo - companyLink: $companyLink - copyRight: $copyRight - salary: $salary - exp: $exp - education: $education - finance: $finance - scale: $scale - field: $field - tags: $tags - ) { - id - } - } -` - -const job = gql` - query($id: ID!) { - job(id: $id) { - ${F.job} - body - author { - ${F.author} - } - tags { - ${F.tag} - } - } - } -` - -const searchUsers = gql` - query($name: String!) { - searchUsers(name: $name) { - entries { - ${F.author} - } - } - } -` - -export const updatableJobFields = [ - 'id', - 'title', - 'body', - 'desc', - 'digest', - 'length', - 'company', - 'companyLogo', - 'companyLink', - 'copyRight', - 'linkAddr', - 'salary', - 'exp', - 'education', - 'finance', - 'scale', - 'field', - // TODO: 'mentionUsers', - 'tags', -] - -export const S = { - createJob, - updateJob, - searchUsers, - job, -} diff --git a/src/containers/editor/JobEditor/store.js b/src/containers/editor/JobEditor/store.js deleted file mode 100755 index 76df81cd8..000000000 --- a/src/containers/editor/JobEditor/store.js +++ /dev/null @@ -1,168 +0,0 @@ -/* - * JobEditorStore store - * - */ - -import { types as T, getParent } from 'mobx-state-tree' -import { - merge, - filter, - contains, - clone, - uniq, - concat, - map, - findIndex, -} from 'ramda' - -import { THREAD } from '@/constant' -import { markStates, buildLog, stripMobx, changeset } from '@/utils' -import { Job } from '@/model' - -/* eslint-disable-next-line */ -const log = buildLog('S:JobEditorStore') - -const Mention = T.model('Mention', { - id: T.string, - name: T.string, - avatar: T.string, -}) - -const JobEditorStore = T.model('JobEditorStore', { - editJob: T.optional(Job, {}), - - 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, 'job_editor_content_id'), - - publishing: T.optional(T.boolean, false), - isEdit: T.optional(T.boolean, false), -}) - .views((self) => ({ - get root() { - return getParent(self) - }, - get curRoute() { - return self.root.curRoute - }, - get viewing() { - return stripMobx(self.root.viewing) - }, - get editData() { - return stripMobx(self.editJob) - }, - get curCommunity() { - return stripMobx(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 stripMobx(self.mentionList) - }, - get referUsersData() { - const referUsers = stripMobx(self.referUsers) - const extractMentions = stripMobx(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) - .startsWith( - { linkAddr: '原链接地址' }, - 'https://', - self.changesetErr, - self.editData.copyRight !== 'original', - ) - .done() - - return result.passed - } - case `${THREAD.JOB}_LABELS`: { - const result = changeset(self.labelsData) - .exist({ tags: '所在城市' }, self.changesetErr) - .exist({ salary: '月薪' }, self.changesetErr) - .exist({ education: '学历要求' }, self.changesetErr) - .exist({ exp: '工作经验' }, self.changesetErr) - .exist({ field: '领域(主要业务)' }, self.changesetErr) - .exist({ finance: '公司融资情况' }, self.changesetErr) - .exist({ scale: '公司规模' }, self.changesetErr) - .done() - - return result.passed - } - case 'companyInfo': { - const result = changeset(self.editData) - .exist({ company: '公司名称' }, self.changesetErr) - .exist({ companyLogo: '公司Logo' }, self.changesetErr) - .exist({ companyLink: '公司主页' }, self.changesetErr) - .done() - - return result.passed - } - default: { - log('unknow validator') - return false - } - } - }, - updateEditing(sobj) { - const editJob = merge(self.editData, { ...sobj }) - return self.mark({ editJob }) - }, - reset() { - self.mark({ isEdit: false, mentionList: [] }) - self.editJob = { 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 JobEditorStore diff --git a/src/containers/editor/JobEditor/styles/company_info_editor.ts b/src/containers/editor/JobEditor/styles/company_info_editor.ts deleted file mode 100755 index 7ec39bf96..000000000 --- a/src/containers/editor/JobEditor/styles/company_info_editor.ts +++ /dev/null @@ -1,65 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme, css } from '@/utils' -import { TitleInput } from './editor' - -export const Wrapper = styled.div` - ${css.flex('justify-center')}; - margin-bottom: 20px; -` -export const Content = styled.div` - ${css.flex()}; - - padding: 10px; - border: 1px solid; - width: 350px; - height: 120px; - border-radius: 4px - border: 1px solid; - border-top: 2px solid; - border-color: ${theme('editor.title')}; -` -export const LogoUploadBox = styled.div` - ${css.flex('align-both')}; - - width: 100px; - height: 100px; - border: 1px dashed; - border-radius: 4px; - margin-right: 10px; -` -export const CompanyLogo = styled(Img)` - border-radius: 3px; - width: 100px; - height: 100px; - margin-right: 10px; -` - -export const UploadHint = styled.div` - padding: 10px; - text-align: center; - color: ${theme('thread.articleDigest')}; - &:hover { - color: ${theme('thread.articleTitle')}; - cursor: pointer; - } -` -export const CompanyInfo = styled.div` - ${css.flexColumn()}; -` -const Inputer = styled(TitleInput)` - height: 32px; - text-align: left; - width: 100%; -` -export const TitleInputer = styled(Inputer)` - height: 32px; - font-size: 1rem; - text-align: left; -` -export const LinkInputer = styled(Inputer)` - height: 32px; - font-size: 0.9rem; - text-align: left; -` diff --git a/src/containers/editor/JobEditor/styles/editor.ts b/src/containers/editor/JobEditor/styles/editor.ts deleted file mode 100755 index 1990f5000..000000000 --- a/src/containers/editor/JobEditor/styles/editor.ts +++ /dev/null @@ -1,44 +0,0 @@ -import styled from 'styled-components' - -import { theme, css } from '@/utils' -import Input from '@/components/Input' - -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-color: ${theme('editor.border')}; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.borderActive')}; - } - &:focus { - border-color: ${theme('editor.border')}; - 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/JobEditor/styles/editor_footer.ts b/src/containers/editor/JobEditor/styles/editor_footer.ts deleted file mode 100755 index c78423225..000000000 --- a/src/containers/editor/JobEditor/styles/editor_footer.ts +++ /dev/null @@ -1,41 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { animate, theme, css } from '@/utils' -// -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/JobEditor/styles/header.ts b/src/containers/editor/JobEditor/styles/header.ts deleted file mode 100755 index c1b9d72b7..000000000 --- a/src/containers/editor/JobEditor/styles/header.ts +++ /dev/null @@ -1,55 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme, css } from '@/utils' - -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/JobEditor/styles/index.ts b/src/containers/editor/JobEditor/styles/index.ts deleted file mode 100755 index 1f0d8dc41..000000000 --- a/src/containers/editor/JobEditor/styles/index.ts +++ /dev/null @@ -1,56 +0,0 @@ -import styled from 'styled-components' - -import type { TActive } from '@/spec' -import Input from '@/components/Input' -import { theme, css } from '@/utils' - -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 { - border-color: ${theme('editor.headerBg')}; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.border')}; - color: ${theme('editor.title')}; - } - &:focus { - border-color: ${theme('editor.headerBg')}; - box-shadow: none; - border-bottom: 1px solid; - border-bottom-color: ${theme('editor.placeholder')}; - color: ${theme('editor.title')}; - text-align: left; - } -` -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/JobEditor/styles/markdown_helper.ts b/src/containers/editor/JobEditor/styles/markdown_helper.ts deleted file mode 100755 index 2e2d2a8f1..000000000 --- a/src/containers/editor/JobEditor/styles/markdown_helper.ts +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components' - -import { theme } from '@/utils' - -export const EmojiWrapper = styled.div` - margin-top: 18px; -` -export const EmojiItem = styled.div` - width: 200px; -` -export const Wrapper = styled.div` - background: ${theme('drawer.markdownHelperBg')}; - padding: 20px; - margin-left: 4%; - margin-right: 4%; -` diff --git a/src/containers/editor/JobEditor/styles/preview.ts b/src/containers/editor/JobEditor/styles/preview.ts deleted file mode 100755 index a06c5fd49..000000000 --- a/src/containers/editor/JobEditor/styles/preview.ts +++ /dev/null @@ -1,25 +0,0 @@ -import styled from 'styled-components' - -// BodyWrapper, BodyHeader, BackToEditBtn, PreviewHeader -import { theme, css } from '@/utils' - -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/JobEditor/tests/index.test.ts b/src/containers/editor/JobEditor/tests/index.test.ts deleted file mode 100755 index f10b57aeb..000000000 --- a/src/containers/editor/JobEditor/tests/index.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import React from 'react' -// import { shallow } from 'enzyme' - -// import JobEditor from '../index' - -describe('TODO ', () => { - it('Expect to have unit tests specified', () => { - expect(true).toEqual(true) - }) -}) diff --git a/src/containers/editor/JobEditor/tests/store.test.ts b/src/containers/editor/JobEditor/tests/store.test.ts deleted file mode 100755 index eaac84d82..000000000 --- a/src/containers/editor/JobEditor/tests/store.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * JobEditor store test - * - */ - -// import JobEditor from '../index' - -it('TODO: store test JobEditor', () => { - expect(1 + 1).toBe(2) -}) diff --git a/src/containers/editor/PostEditor/EditorFooter.js b/src/containers/editor/PostEditor/EditorFooter.js index ffe3c38d3..7e0e208ad 100755 --- a/src/containers/editor/PostEditor/EditorFooter.js +++ b/src/containers/editor/PostEditor/EditorFooter.js @@ -4,7 +4,6 @@ import { pluck } from 'ramda' import { ICON_CMD } from '@/config' import DocUploader from '@/containers/tool/DocUploader' -import Labeler from '@/containers/unit/Labeler' import Maybe from '@/components/Maybe' import { @@ -45,8 +44,6 @@ const PicUploader = ({ divider }) => ( const EditorFooter = ({ isEdit, editData }) => ( - {!isEdit && } - diff --git a/src/containers/layout/GlobalLayout/Addon.tsx b/src/containers/layout/GlobalLayout/Addon.tsx new file mode 100644 index 000000000..f2f225a91 --- /dev/null +++ b/src/containers/layout/GlobalLayout/Addon.tsx @@ -0,0 +1,23 @@ +import { FC, Fragment, memo, useEffect } from 'react' + +import { useShortcut } from '@/hooks' +import { openDoraemon, logBuddha } from './logic' + +import { AbuseReport, Drawer, Doraemon, ErrorBox, Share } from './dynamic' + +const Addon: FC = () => { + useShortcut('Control+P', openDoraemon) + useEffect(() => logBuddha(), []) + + return ( + + + + + + + + ) +} + +export default memo(Addon) diff --git a/src/containers/layout/GlobalLayout/SEO.tsx b/src/containers/layout/GlobalLayout/SEO.tsx index 9c5f5aed3..1aa99a3f3 100755 --- a/src/containers/layout/GlobalLayout/SEO.tsx +++ b/src/containers/layout/GlobalLayout/SEO.tsx @@ -5,10 +5,10 @@ */ import { FC } from 'react' -import { NextSeo, BlogJsonLd, SocialProfileJsonLd } from 'next-seo' +import Head from 'next/head' import type { TMetric } from '@/spec' -import { METRIC } from '@/constant' +// import { METRIC } from '@/constant' type TProps = { metric: TMetric @@ -16,52 +16,28 @@ type TProps = { } const SEO: FC = ({ metric, config }) => { - switch (metric) { - case METRIC.ARTICLE: { - return ( - - ) - } - - case METRIC.USER: { - return ( - - ) - } - - default: { - return ( - - ) - } - } + // switch (metric) { + // case METRIC.ARTICLE: { + return ( + + {config.title} + + + + + + {/* */} + + // + ) } export default SEO diff --git a/src/containers/layout/GlobalLayout/dynamic.tsx b/src/containers/layout/GlobalLayout/dynamic.tsx index d78474728..e06c0e5d8 100644 --- a/src/containers/layout/GlobalLayout/dynamic.tsx +++ b/src/containers/layout/GlobalLayout/dynamic.tsx @@ -1,7 +1,33 @@ import dynamic from 'next/dynamic' +import { ScrollHolder } from './styles' import { TProps as TErrorPage } from '@/components/ErrorPage' +export const Sidebar = dynamic(() => import('@/containers/unit/Sidebar'), { + ssr: false, +}) + +export const CustomScroller = dynamic( + () => import('@/components/CustomScroller'), + { + /* eslint-disable react/display-name */ + loading: () => , + ssr: false, + }, +) + +export const Drawer = dynamic(() => import('@/containers/tool/Drawer'), { + /* eslint-disable react/display-name */ + loading: () =>
, + ssr: false, +}) + +export const ModeLine = dynamic(() => import('@/containers/unit/ModeLine'), { + /* eslint-disable react/display-name */ + loading: () =>
, + ssr: false, +}) + export const Doraemon = dynamic(() => import('@/containers/tool/Doraemon'), { /* eslint-disable react/display-name */ loading: () =>
, diff --git a/src/containers/layout/GlobalLayout/index.tsx b/src/containers/layout/GlobalLayout/index.tsx index 24c977d6b..76170dcba 100755 --- a/src/containers/layout/GlobalLayout/index.tsx +++ b/src/containers/layout/GlobalLayout/index.tsx @@ -4,43 +4,32 @@ * */ -import React, { FC, ReactNode, useEffect } from 'react' +import { FC, Fragment, ReactNode } from 'react' +import dynamic from 'next/dynamic' +import { isMobile } from 'react-device-detect' import type { TSEO, TMetric } from '@/spec' import { ANCHOR, SIZE, C11N, BODY_SCROLLER } from '@/constant' import AnalysisService from '@/services/Analysis' -import { useNetwork, useShortcut, usePlatform, useDevice } from '@/hooks' import { pluggedIn } from '@/utils' import ThemePalette from '@/containers/layout/ThemePalette' import Header from '@/containers/unit/Header' -import Sidebar from '@/containers/unit/Sidebar' -import ModeLine from '@/containers/unit/ModeLine' -import Drawer from '@/containers/tool/Drawer' +// import ModeLine from '@/containers/unit/ModeLine' -import CustomScroller from '@/components/CustomScroller' +// import Drawer from '@/containers/tool/Drawer' +// import CustomScroller from '@/components/CustomScroller' import type { TStore } from './store' import SEO from './SEO' -import { - AbuseReport, - Doraemon, - ErrorBox, - Footer, - ErrorPage, - Share, -} from './dynamic' - +import { CustomScroller, Sidebar, Footer, ErrorPage, ModeLine } from './dynamic' import { Wrapper, InnerWrapper, BodyWrapper, ContentWrapper } from './styles' +import { useInit, onPageScrollDirhange, childrenWithProps } from './logic' -import { - useInit, - openDoraemon, - logBuddha, - bodyScrollDirectionOnChange, - childrenWithProps, -} from './logic' +const Addon = dynamic(() => import('./Addon'), { + ssr: false, +}) type TProps = { globalLayout?: TStore @@ -64,22 +53,12 @@ const GlobalLayoutContainer: FC = ({ noFooter = false, metric, }) => { - const { online } = useNetwork() - const platform = usePlatform() - const { isMobile } = useDevice() - + // const { online } = useNetwork() // TODO: move it to Header // load debug graph - useEffect(() => logBuddha(), []) + useInit(store, { isMobile }) - useInit(store, { online, platform, isMobile }) - useShortcut('Control+P', openDoraemon) - - const { - sidebarPin, - accountInfo: { - customization: { bannerLayout }, - }, - } = store + const { sidebarPin, c11n } = store + const { bannerLayout } = c11n return ( @@ -92,20 +71,11 @@ const GlobalLayoutContainer: FC = ({ target={errorPath} /> ) : ( - + - - + {!noSidebar && bannerLayout !== C11N.HOLY_GRAIL && } - - - - - + = ({ barSize={SIZE.MEDIUM} showShadow={false} onScrollDirectionChange={(direction) => - bodyScrollDirectionOnChange(direction) + onPageScrollDirhange(direction) } autoHide > @@ -131,7 +101,7 @@ const GlobalLayoutContainer: FC = ({ - + )} diff --git a/src/containers/layout/GlobalLayout/logic.ts b/src/containers/layout/GlobalLayout/logic.ts index 4541872a3..7e930080d 100755 --- a/src/containers/layout/GlobalLayout/logic.ts +++ b/src/containers/layout/GlobalLayout/logic.ts @@ -12,7 +12,7 @@ let store: TStore | undefined export const openDoraemon = (): void => store.openDoraemon() // custromScroll's scroll direction change -export const bodyScrollDirectionOnChange = ( +export const onPageScrollDirhange = ( bodyScrollDirection: TScrollDirection, ): void => store.mark({ bodyScrollDirection }) /** @@ -80,7 +80,7 @@ export const useInit = (_store: TStore, extra): void => { // scrollbars: { autoHide: 'scroll', autoHideDelay: 500 }, // }) - const { online, platform, isMobile } = extra - store.mark({ online, platform, isMobile }) + const { online, isMobile } = extra + store.mark({ online, isMobile }) }, [_store, extra]) } diff --git a/src/containers/layout/GlobalLayout/store.ts b/src/containers/layout/GlobalLayout/store.ts index a6eb15ad8..62c2e0a01 100755 --- a/src/containers/layout/GlobalLayout/store.ts +++ b/src/containers/layout/GlobalLayout/store.ts @@ -5,7 +5,7 @@ import { types as T, getParent, Instance } from 'mobx-state-tree' -import type { TRootStore, TAccount } from '@/spec' +import type { TRootStore, TAccount, TC11N } from '@/spec' import { markStates, buildLog } from '@/utils' /* eslint-disable-next-line */ @@ -31,6 +31,10 @@ const GlobalLayout = T.model('GlobalLayoutStore', { const root = getParent(self) as TRootStore return root.accountInfo }, + get c11n(): TC11N { + const root = getParent(self) as TRootStore + return root.account.c11n + }, get sidebarPin(): boolean { const root = getParent(self) as TRootStore return root.sidebar.pin diff --git a/src/containers/layout/GlobalLayout/styles/index.ts b/src/containers/layout/GlobalLayout/styles/index.ts index 44c827c85..c571b0d61 100755 --- a/src/containers/layout/GlobalLayout/styles/index.ts +++ b/src/containers/layout/GlobalLayout/styles/index.ts @@ -64,3 +64,7 @@ export const ContentWrapper = styled.div<{ offsetLeft: boolean }>` /* for global blur */ transition: filter 0.25s; ` +export const ScrollHolder = styled.div` + height: 100vh; + width: 100%; +` diff --git a/src/containers/thread/ArticlesThread/index.tsx b/src/containers/thread/ArticlesThread/index.tsx index f8ed0b5b4..283b35290 100755 --- a/src/containers/thread/ArticlesThread/index.tsx +++ b/src/containers/thread/ArticlesThread/index.tsx @@ -7,21 +7,26 @@ */ import { FC } from 'react' -import { Waypoint } from 'react-waypoint' +import dynamic from 'next/dynamic' import type { TResState } from '@/spec' import { C11N } from '@/constant' import { pluggedIn, buildLog } from '@/utils' -import ThreadSidebar from '@/containers/thread/ThreadSidebar' import PagedArticles from '@/components/PagedArticles' -import ArticlesFilter from '@/components/ArticlesFilter' +import ViewportTracker from '@/components/ViewportTracker' +// import ArticlesFilter from '@/components/ArticlesFilter' +import ThreadSidebar from '@/containers/thread/ThreadSidebar' import type { TStore } from './store' import { Wrapper, MainWrapper, FilterWrapper } from './styles' import { useInit, inAnchor, outAnchor, onFilterSelect } from './logic' +const ArticlesFilter = dynamic(() => import('@/components/ArticlesFilter'), { + ssr: false, +}) + /* eslint-disable-next-line */ const log = buildLog('C:ArticlesThread') @@ -38,17 +43,18 @@ const ArticlesThreadContainer: FC = ({ articlesThread: store }) => { curThread, showFilters, viewingArticle, - accountInfo: { - customization: { bannerLayout }, - }, + c11n, } = store + + const { bannerLayout } = c11n + const resState = store.resState as TResState const { pageNumber, totalCount } = pagedArticlesData return ( - + {showFilters && ( = ({ articlesThread: store }) => { thread={curThread} viewingArticle={viewingArticle} resState={resState} + c11n={c11n} /> diff --git a/src/containers/thread/ArticlesThread/store.ts b/src/containers/thread/ArticlesThread/store.ts index 7d4a01b3f..acc18d8b1 100755 --- a/src/containers/thread/ArticlesThread/store.ts +++ b/src/containers/thread/ArticlesThread/store.ts @@ -14,6 +14,7 @@ import type { TCommunity, TThread, TArticleFilter, + TC11N, } from '@/spec' import { TYPE, THREAD } from '@/constant' @@ -60,6 +61,10 @@ const ArticlesThread = T.model('ArticlesThread', { const root = getParent(self) as TRootStore return root.account.accountInfo }, + get c11n(): TC11N { + const root = getParent(self) as TRootStore + return root.account.c11n + }, get filtersData(): TArticleFilter { return stripMobx(pickBy((v) => !isEmpty(v), self.filters)) }, diff --git a/src/containers/thread/ReposThread/index.js b/src/containers/thread/ReposThread/index.js index 39d84249e..fbaf6a0dd 100755 --- a/src/containers/thread/ReposThread/index.js +++ b/src/containers/thread/ReposThread/index.js @@ -5,7 +5,6 @@ */ import React from 'react' -import { Waypoint } from 'react-waypoint' import { ICON_CMD } from '@/config' import { THREAD } from '@/constant' @@ -18,6 +17,7 @@ import { PublishButton } from '@/components/Buttons' import PagedArticles from '@/components/PagedArticles' import ArticlesFilter from '@/components/ArticlesFilter' import Maybe from '@/components/Maybe' +import ViewportTracker from '@/components/ViewportTracker' import { Wrapper, @@ -61,7 +61,7 @@ const ReposThreadContainer = ({ reposThread: store }) => { return ( - + = ({ + showCommunityBadge, + onTagSelect, + onAdsClose, +}) => { + return ( + + + + + + + + + + ) +} + +export default memo(ClassicLayout) diff --git a/src/containers/thread/ThreadSidebar/ClassicLayout.tsx b/src/containers/thread/ThreadSidebar/ClassicLayout/index.tsx similarity index 57% rename from src/containers/thread/ThreadSidebar/ClassicLayout.tsx rename to src/containers/thread/ThreadSidebar/ClassicLayout/index.tsx index 1ddc4bbc2..c2470f385 100644 --- a/src/containers/thread/ThreadSidebar/ClassicLayout.tsx +++ b/src/containers/thread/ThreadSidebar/ClassicLayout/index.tsx @@ -7,29 +7,33 @@ */ import { FC, memo } from 'react' +import dynamic from 'next/dynamic' import { buildLog } from '@/utils' -import CommunityJoinBadge from '@/containers/tool/CommunityJoinBadge' -import TagsBar from '@/containers/unit/TagsBar' - import Sticky from '@/components/Sticky' +import { LavaLampLoading } from '@/components/Loading' import { PublishButton } from '@/components/Buttons' -import PromotionList from '@/components/PromotionList' -import type { TBaseProps } from './index' +import type { TBaseProps } from '../index' -import { onCreate } from './logic' -import { - Wrapper, - BadgeWrapper, - TagsBarWrapper, - PublishWrapper, -} from './styles/classic_layout' +import { Wrapper, PublishWrapper } from '../styles/classic_layout' +import { onCreate } from '../logic' /* eslint-disable-next-line */ const log = buildLog('c:ClassicSidebar') +export const DynamicPart = dynamic(() => import('./DynamicPart'), { + /* eslint-disable react/display-name */ + loading: () => ( + <> +
+ + + ), + ssr: false, +}) + type TProps = { showCommunityBadge: boolean } & TBaseProps const ClassicLayout: FC = ({ @@ -43,14 +47,11 @@ const ClassicLayout: FC = ({ - - - - - - - - +
) diff --git a/src/containers/thread/ThreadSidebar/HolyGrailLayout/DynamicPart.tsx b/src/containers/thread/ThreadSidebar/HolyGrailLayout/DynamicPart.tsx new file mode 100644 index 000000000..bd55fef18 --- /dev/null +++ b/src/containers/thread/ThreadSidebar/HolyGrailLayout/DynamicPart.tsx @@ -0,0 +1,26 @@ +import { FC, Fragment, memo } from 'react' + +import { Br } from '@/components/Common' +import Sticky from '@/components/Sticky' +import TagsBar from '@/containers/unit/TagsBar' +import { PublishButton } from '@/components/Buttons' + +import ExtraInfo from './ExtraInfo' + +// 没有各种外链接,打赏信息等的官方社区 + +const DynamicPart: FC = () => { + return ( + + +
+ +
+ + + +
+ ) +} + +export default memo(DynamicPart) diff --git a/src/containers/thread/ThreadSidebar/HolyGrailLayout/index.tsx b/src/containers/thread/ThreadSidebar/HolyGrailLayout/index.tsx index 7fd94f47b..9374db778 100644 --- a/src/containers/thread/ThreadSidebar/HolyGrailLayout/index.tsx +++ b/src/containers/thread/ThreadSidebar/HolyGrailLayout/index.tsx @@ -1,19 +1,21 @@ import { FC, memo } from 'react' +import dynamic from 'next/dynamic' import type { TCommunity } from '@/spec' -import { Br } from '@/components/Common' -import Sticky from '@/components/Sticky' -import TagsBar from '@/containers/unit/TagsBar' -import { PublishButton } from '@/components/Buttons' - import CommunityBrief from './CommunityBrief' -import ExtraInfo from './ExtraInfo' +import { LavaLampLoading } from '@/components/Loading' import { Wrapper, Divider } from '../styles/holy_grail_layout' // 没有各种外链接,打赏信息等的官方社区 +export const DynamicPart = dynamic(() => import('./DynamicPart'), { + /* eslint-disable react/display-name */ + loading: () => , + ssr: false, +}) + type TProps = { community: TCommunity } @@ -23,13 +25,7 @@ const HolyGrailLayout: FC = ({ community }) => { - -
- -
- - - +
) } diff --git a/src/containers/thread/UsersThread/index.js b/src/containers/thread/UsersThread/RealMap.tsx similarity index 63% rename from src/containers/thread/UsersThread/index.js rename to src/containers/thread/UsersThread/RealMap.tsx index 9b4ae3945..1d17e88eb 100755 --- a/src/containers/thread/UsersThread/index.js +++ b/src/containers/thread/UsersThread/RealMap.tsx @@ -4,8 +4,7 @@ * */ -import React from 'react' -import dynamic from 'next/dynamic' +import { FC, Fragment } from 'react' import { useTheme } from 'styled-components' import { pluggedIn, buildLog } from '@/utils' @@ -13,20 +12,19 @@ import { useScript } from '@/hooks' import NumDashboard from './NumDashboard' import MapLoading from './MapLoading' +import GeoMap from './GeoMap' -import { Wrapper } from './styles' +import type { TStore } from './store' import { useInit } from './logic' /* eslint-disable-next-line */ const log = buildLog('C:UsersThread') -export const GeoMapSSR = dynamic(() => import('./GeoMap.js'), { - /* eslint-disable react/display-name */ - loading: () => , - ssr: false, -}) +type TProps = { + usersThread?: TStore +} -const UsersThreadContainer = ({ usersThread }) => { +const UsersThreadContainer: FC = ({ usersThread }) => { /* load g2 from CDN, it's too big for dynamic import, and i am poor ..' */ const [g2ScriptLoaded] = useScript( 'https://a.alipayobjects.com/g/datavis/g2/2.3.13/index.js', @@ -43,10 +41,10 @@ const UsersThreadContainer = ({ usersThread }) => { showNums, } = usersThread - const ready = g2ScriptLoaded && GeoMapSSR !== null && !geoDataLoading + const ready = g2ScriptLoaded && !geoDataLoading return ( - + {ready && ( { /> )} {ready ? ( - + ) : ( )} - + ) } -export default pluggedIn(UsersThreadContainer) +export default pluggedIn(UsersThreadContainer) as FC diff --git a/src/containers/thread/UsersThread/index.tsx b/src/containers/thread/UsersThread/index.tsx new file mode 100755 index 000000000..dcc83f61b --- /dev/null +++ b/src/containers/thread/UsersThread/index.tsx @@ -0,0 +1,33 @@ +/* + * + * UsersThread + * + */ + +import React from 'react' +import dynamic from 'next/dynamic' + +import { buildLog } from '@/utils' + +import MapLoading from './MapLoading' + +import { Wrapper } from './styles' + +/* eslint-disable-next-line */ +const log = buildLog('C:UsersThread') + +export const RealMap = dynamic(() => import('./RealMap'), { + /* eslint-disable react/display-name */ + loading: () => , + ssr: false, +}) + +const UsersThread = () => { + return ( + + + + ) +} + +export default UsersThread diff --git a/src/containers/thread/UsersThread/store.js b/src/containers/thread/UsersThread/store.ts similarity index 60% rename from src/containers/thread/UsersThread/store.js rename to src/containers/thread/UsersThread/store.ts index 6218b249c..1f1f9fc95 100755 --- a/src/containers/thread/UsersThread/store.js +++ b/src/containers/thread/UsersThread/store.ts @@ -3,9 +3,10 @@ * */ -import { types as T, getParent } from 'mobx-state-tree' +import { types as T, getParent, Instance } from 'mobx-state-tree' import { markStates, buildLog, stripMobx } from '@/utils' +import { TCommunity, TTheme, TRootStore } from '@/spec' /* eslint-disable-next-line */ const log = buildLog('S:UsersThread') @@ -23,23 +24,23 @@ const UsersThread = T.model('UsersThread', { showNums: T.optional(T.boolean, false), }) .views((self) => ({ - get root() { - return getParent(self) + get curTheme(): TTheme { + const root = getParent(self) as TRootStore + return root.theme.curTheme }, - get curTheme() { - return self.root.theme.curTheme - }, - get curCommunity() { - return stripMobx(self.root.viewing.community) + get curCommunity(): TCommunity { + const root = getParent(self) as TRootStore + return stripMobx(root.viewing.community) }, get geoInfosData() { return stripMobx(self.geoInfos) }, })) .actions((self) => ({ - mark(sobj) { + mark(sobj: Record): void { markStates(sobj, self) }, })) +export type TStore = Instance export default UsersThread diff --git a/src/containers/tool/C11NSettingPanel/GeneralSettings.js b/src/containers/tool/C11NSettingPanel/GeneralSettings.js index 32d0a0507..a13c11813 100644 --- a/src/containers/tool/C11NSettingPanel/GeneralSettings.js +++ b/src/containers/tool/C11NSettingPanel/GeneralSettings.js @@ -2,7 +2,7 @@ import React from 'react' import { contains } from 'ramda' import { THREAD, C11N } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { Br } from '@/components/Common' import { Radio } from '@/components/Switcher' @@ -11,8 +11,6 @@ import { Wrapper, Title, Desc, Divider } from './styles/gerneral_settings' import { onC11NChange } from './logic' const GeneralSettings = ({ curThread, customization }) => { - const { isMobile } = useDevice() - const { bannerLayout, contentDivider, diff --git a/src/containers/tool/Drawer/Content/index.tsx b/src/containers/tool/Drawer/Content/index.tsx index 3f7dba7d5..19e3168dd 100644 --- a/src/containers/tool/Drawer/Content/index.tsx +++ b/src/containers/tool/Drawer/Content/index.tsx @@ -1,13 +1,11 @@ import { Fragment, memo } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView' const Content = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/containers/tool/Drawer/Content/renderContent.js b/src/containers/tool/Drawer/Content/renderContent.js index d725809f8..1691027ef 100644 --- a/src/containers/tool/Drawer/Content/renderContent.js +++ b/src/containers/tool/Drawer/Content/renderContent.js @@ -8,14 +8,11 @@ import PlaceHolder from './PlaceHolder' import { ArticleViewer, - // PostViewer, - JobViewer, MailsViewer, RepoViewer, // editors AccountEditor, PostEditor, - JobEditor, RepoEditor, // utils C11NSettingPanel, @@ -29,8 +26,6 @@ const renderContent = (type, attachment, attUser, mmType) => { case TYPE.DRAWER.POST_VIEW: return // post - // case TYPE.DRAWER.POST_VIEW: - // return case TYPE.DRAWER.POST_CREATE: return @@ -39,14 +34,6 @@ const renderContent = (type, attachment, attUser, mmType) => { return // job - case TYPE.DRAWER.JOB_CREATE: - return - - case TYPE.DRAWER.JOB_VIEW: - return - - case TYPE.DRAWER.JOB_EDIT: - return // repo case TYPE.DRAWER.REPO_VIEW: diff --git a/src/containers/tool/Drawer/Viewer/index.tsx b/src/containers/tool/Drawer/Viewer/index.tsx index d3b6ef606..a1cddc4f7 100644 --- a/src/containers/tool/Drawer/Viewer/index.tsx +++ b/src/containers/tool/Drawer/Viewer/index.tsx @@ -1,7 +1,7 @@ import React, { useEffect } from 'react' import dynamic from 'next/dynamic' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' let CurrentView = null @@ -10,8 +10,6 @@ let CurrentView = null * @returns */ const Viewer = (props) => { - const { isMobile } = useDevice() - useEffect(() => { if (!isMobile) { CurrentView = dynamic(() => import('./DesktopView'), { ssr: false }) diff --git a/src/containers/tool/Drawer/dynamics.tsx b/src/containers/tool/Drawer/dynamics.tsx index 6680bf954..98994d704 100755 --- a/src/containers/tool/Drawer/dynamics.tsx +++ b/src/containers/tool/Drawer/dynamics.tsx @@ -30,16 +30,6 @@ export const ArticleViewer = dynamic( commonConfig, ) -export const PostViewer = dynamic( - () => import('@/containers/viewer/PostViewer'), - commonConfig, -) - -export const JobViewer = dynamic( - () => import('@/containers/viewer/JobViewer'), - commonConfig, -) - export const MailsViewer = dynamic( () => import('@/containers/viewer/MailsViewer'), commonConfig, @@ -61,11 +51,6 @@ export const PostEditor = dynamic( editorConfig, ) -export const JobEditor = dynamic( - () => import('@/containers/editor/JobEditor'), - editorConfig, -) - export const RepoEditor = dynamic( () => import('@/containers/editor/RepoEditor'), editorConfig, diff --git a/src/containers/unit/ArticleAuthorCard/ReactionNumbers.js b/src/containers/unit/ArticleAuthorCard/ReactionNumbers.js deleted file mode 100755 index 8b8c90e7d..000000000 --- a/src/containers/unit/ArticleAuthorCard/ReactionNumbers.js +++ /dev/null @@ -1,80 +0,0 @@ -import React from 'react' -import T from 'prop-types' - -import { ISSUE_ADDR } from '@/config' -import { TYPE } from '@/constant' - -import Tooltip from '@/components/Tooltip' -import DiscussLinker from '@/components/DiscussLinker' - -import { - Wrapper, - ReactionNum, - NumDesc, - Number, - ReadOnlyNumber, -} from './styles/reaction_numbers' - -import { onListUsers } from './logic' - -const ReactionNumbers = ({ user }) => { - // early user has no reutation - const achievement = user.achievement || { reputation: 0 } - - return ( - - - 声望 - } - > - {achievement.reputation} - - - - 关注者 - - onListUsers(TYPE.USER_LISTER_FOLLOWERS, { - id: user.id, - brief: user.nickname, - }) - } - > - {user.achievement.followersCount} - - - - 关注中 - - onListUsers(TYPE.USER_LISTER_FOLLOWINGS, { - id: user.id, - brief: user.nickname, - }) - } - > - {user.achievement.followingsCount} - - - - ) -} - -ReactionNumbers.propTypes = { - user: T.shape({ - id: T.string, - nickname: T.string, - achievement: T.shape({ - reputation: T.number, - followersCount: T.number, - followingsCount: T.number, - }), - }).isRequired, -} - -ReactionNumbers.defaultProps = {} - -export default React.memo(ReactionNumbers) diff --git a/src/containers/unit/ArticleAuthorCard/UserInfo.js b/src/containers/unit/ArticleAuthorCard/UserInfo.js deleted file mode 100755 index e791ea8d1..000000000 --- a/src/containers/unit/ArticleAuthorCard/UserInfo.js +++ /dev/null @@ -1,44 +0,0 @@ -import React from 'react' -import T from 'prop-types' - -import { cutRest } from '@/utils' -import { FollowButton } from '@/components/Buttons' - -import { Wrapper, Avatar, Brief, Nickname, Bio } from './styles/user_info' - -import { onFollow, onUndoFollow } from './logic' - -const UserInfo = ({ user, isSelfViewing }) => ( - - - - {user.nickname} - {user.id && !isSelfViewing && ( - - )} - - {cutRest(user.bio || '--', 35)} - -) - -UserInfo.propTypes = { - user: T.shape({ - id: T.string, - avatar: T.string, - nickname: T.string, - bio: T.string, - viewerHasFollowed: T.bool, - }).isRequired, - isSelfViewing: T.bool, -} - -UserInfo.defaultProps = { - isSelfViewing: false, -} - -export default React.memo(UserInfo) diff --git a/src/containers/unit/ArticleAuthorCard/index.js b/src/containers/unit/ArticleAuthorCard/index.js deleted file mode 100755 index d5702b36e..000000000 --- a/src/containers/unit/ArticleAuthorCard/index.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * - * ArticleAuthorCard - * - */ - -import React from 'react' -import T from 'prop-types' - -import { pluggedIn, buildLog } from '@/utils' - -import UserInfo from './UserInfo' -// import ReactionNumbers from './ReactionNumbers' - -import { Wrapper } from './styles' -import { useInit } from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('C:ArticleAuthorCard') - -const ArticleAuthorCardContainer = ({ articleAuthorCard: store, user }) => { - useInit(store, user) - - const { isSelfViewing } = store - - return ( - - - {/* */} - - ) -} - -ArticleAuthorCardContainer.propTypes = { - // later - articleAuthorCard: T.object.isRequired, - user: T.shape({ - id: T.string, - login: T.string, - avatar: T.string, - nickname: T.string, - bio: T.string, - - achievement: T.shape({ - reputation: T.number, - followersCount: T.number, - followingsCount: T.number, - }), - }).isRequired, -} - -ArticleAuthorCardContainer.defaultProps = {} - -export default pluggedIn(ArticleAuthorCardContainer) diff --git a/src/containers/unit/ArticleAuthorCard/logic.js b/src/containers/unit/ArticleAuthorCard/logic.js deleted file mode 100755 index 1d733ecc3..000000000 --- a/src/containers/unit/ArticleAuthorCard/logic.js +++ /dev/null @@ -1,98 +0,0 @@ -import { useEffect } from 'react' - -import { EVENT, ERR } from '@/constant' -import { asyncSuit, buildLog, send, errRescue } from '@/utils' - -import S from './schema' - -/* eslint-disable-next-line */ -const log = buildLog('L:ArticleAuthorCard') - -const { SR71, $solver, asyncRes, asyncErr } = asyncSuit -const sr71$ = new SR71() - -let sub$ = null -let store = null - -export const loadUser = (user) => { - if (!store.isLogin) return false - const { login } = user - - store.mark({ user }) - sr71$.query(S.user, { login, userHasLogin: store.isLogin }) -} - -export const onListUsers = (type, data) => - send(EVENT.USER_LISTER_OPEN, { type, data }) - -export const onFollow = (userId) => { - store.mark({ following: true }) - sr71$.mutate(S.follow, { userId }) -} -export const onUndoFollow = (userId) => { - store.mark({ following: true }) - sr71$.mutate(S.undoFollow, { userId }) -} - -// ############################### -// Data & Error handlers -// ############################### - -const DataSolver = [ - { - match: asyncRes('user'), - action: ({ user }) => store.updateUser(user), - }, - { - match: asyncRes('follow'), - action: ({ follow: user }) => { - store.mark({ following: false }) - store.updateUser(user) - }, - }, - { - match: asyncRes('undoFollow'), - action: ({ undoFollow: user }) => { - store.mark({ following: false }) - store.updateUser(user) - }, - }, -] -const ErrSolver = [ - { - match: asyncErr(ERR.GRAPHQL), - action: () => store.mark({ following: false }), - }, - { - match: asyncErr(ERR.TIMEOUT), - action: ({ details }) => { - store.mark({ following: false }) - errRescue({ type: ERR.TIMEOUT, details, path: 'ArticleAuthorCard' }) - }, - }, - { - match: asyncErr(ERR.NETWORK), - action: () => { - store.mark({ following: false }) - errRescue({ type: ERR.NETWORK, path: 'ArticleAuthorCard' }) - }, - }, -] - -// ############################### -// init & uninit -// ############################### -export const useInit = (_store, user) => { - useEffect(() => { - store = _store - - sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) - loadUser(user) - - return () => { - // log('effect uninit') - sr71$.stop() - sub$.unsubscribe() - } - }, [_store, user]) -} diff --git a/src/containers/unit/ArticleAuthorCard/schema.ts b/src/containers/unit/ArticleAuthorCard/schema.ts deleted file mode 100755 index 41d6073f2..000000000 --- a/src/containers/unit/ArticleAuthorCard/schema.ts +++ /dev/null @@ -1,26 +0,0 @@ -import gql from 'graphql-tag' -import { P } from '@/schemas' - -const user = gql` - query user($login: String!, $userHasLogin: Boolean!) { - user(login: $login) { - viewerHasFollowed @include(if: $userHasLogin) - } - } -` - -const follow = gql` - ${P.follow} -` - -const undoFollow = gql` - ${P.undoFollow} -` - -const schema = { - user, - follow, - undoFollow, -} - -export default schema diff --git a/src/containers/unit/ArticleAuthorCard/store.js b/src/containers/unit/ArticleAuthorCard/store.js deleted file mode 100755 index 4a60af487..000000000 --- a/src/containers/unit/ArticleAuthorCard/store.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ArticleAuthorCard store - * - */ - -import { types as T, getParent } from 'mobx-state-tree' -import { merge } from 'ramda' - -import { markStates, buildLog, stripMobx } from '@/utils' -import { User } from '@/model' - -/* eslint-disable-next-line */ -const log = buildLog('S:ArticleAuthorCard') - -const ArticleAuthorCard = T.model('ArticleAuthorCard', { - hasFollowed: T.optional(T.boolean, false), - following: T.optional(T.boolean, false), - user: T.optional(User, {}), -}) - .views((self) => ({ - get root() { - return getParent(self) - }, - get isLogin() { - return self.root.account.isLogin - }, - get isSelfViewing() { - const { isLogin } = self.root.accountInfo - if (!isLogin) return false - - const { id: accountId } = self.root.accountInfo - const { id: userId } = self.user - return accountId === userId - }, - get userData() { - return stripMobx(self.user) - }, - })) - .actions((self) => ({ - authWarning(options) { - self.root.authWarning(options) - }, - updateUser(sobj) { - const user = merge(self.user, { ...sobj }) - self.mark({ user }) - }, - mark(sobj) { - markStates(sobj, self) - }, - })) - -export default ArticleAuthorCard diff --git a/src/containers/unit/ArticleAuthorCard/styles/index.ts b/src/containers/unit/ArticleAuthorCard/styles/index.ts deleted file mode 100755 index 5c635194d..000000000 --- a/src/containers/unit/ArticleAuthorCard/styles/index.ts +++ /dev/null @@ -1,24 +0,0 @@ -import styled from 'styled-components' - -import { css } from '@/utils' - -export const Wrapper = styled.div` - min-height: 50px; - padding: 10px; - margin-top: 20px; - - max-width: 300px; - width: 100%; - flex-wrap: wrap; - - ${css.media.tablet` - width: 50%; - `}; - - ${css.media.mobile` - width: 50%; - padding: 10px; - `}; -` - -export const holder = 1 diff --git a/src/containers/unit/ArticleAuthorCard/styles/reaction_numbers.ts b/src/containers/unit/ArticleAuthorCard/styles/reaction_numbers.ts deleted file mode 100755 index a84cfd7cf..000000000 --- a/src/containers/unit/ArticleAuthorCard/styles/reaction_numbers.ts +++ /dev/null @@ -1,33 +0,0 @@ -import styled from 'styled-components' - -import { theme, css } from '@/utils' - -export const Wrapper = styled.div` - ${css.flex('justify-between')}; - padding: 0 10px; - margin-top: 15px; -` -export const ReactionNum = styled.div` - ${css.flexColumn('justify-center')}; - text-align: center; -` -export const NumDesc = styled.div` - color: ${theme('thread.articleDigest')}; - font-size: 0.8rem; -` - -export const ReadOnlyNumber = styled.div` - color: ${theme('thread.articleTitle')}; - font-size: 1rem; - cursor: help; -` - -export const Number = styled(ReadOnlyNumber)` - color: ${theme('thread.articleTitle')}; - font-size: 1rem; - - &:hover { - color: ${theme('banner.active')}; - cursor: pointer; - } -` diff --git a/src/containers/unit/ArticleAuthorCard/styles/user_info.ts b/src/containers/unit/ArticleAuthorCard/styles/user_info.ts deleted file mode 100755 index 7ccabcc62..000000000 --- a/src/containers/unit/ArticleAuthorCard/styles/user_info.ts +++ /dev/null @@ -1,29 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme, css } from '@/utils' - -export const Wrapper = styled.div` - ${css.flexColumn()}; -` -export const Avatar = styled(Img)` - ${css.circle(25)}; - margin-right: 10px; - - ${css.media.mobile` - ${css.circle(25)}; - `}; -` -export const Brief = styled.div` - ${css.flex()}; -` -export const Nickname = styled.div` - color: ${theme('thread.articleTitle')}; - font-size: 16px; - flex-grow: 1; -` -export const Bio = styled.div` - color: ${theme('thread.articleDigest')}; - font-size: 15px; - margin-top: 10px; -` diff --git a/src/containers/unit/ArticleAuthorCard/tests/index.test.ts b/src/containers/unit/ArticleAuthorCard/tests/index.test.ts deleted file mode 100755 index 9d96ffa89..000000000 --- a/src/containers/unit/ArticleAuthorCard/tests/index.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import React from 'react' -// import { shallow } from 'enzyme' - -// import ArticleAuthorCard from '../index' - -describe('TODO ', () => { - it('Expect to have unit tests specified', () => { - expect(true).toEqual(true) - }) -}) diff --git a/src/containers/unit/ArticleAuthorCard/tests/store.test.ts b/src/containers/unit/ArticleAuthorCard/tests/store.test.ts deleted file mode 100755 index 585e62a4f..000000000 --- a/src/containers/unit/ArticleAuthorCard/tests/store.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * ArticleAuthorCard store test - * - */ - -// import ArticleAuthorCard from '../index' - -it('TODO: store test ArticleAuthorCard', () => { - expect(1 + 1).toBe(2) -}) diff --git a/src/containers/unit/ArticleBodyHeader/index.js b/src/containers/unit/ArticleBodyHeader/index.js index a31a11327..629a07b91 100755 --- a/src/containers/unit/ArticleBodyHeader/index.js +++ b/src/containers/unit/ArticleBodyHeader/index.js @@ -12,7 +12,6 @@ import { ICON_CMD } from '@/config' import { THREAD } from '@/constant' import { pluggedIn, buildLog } from '@/utils' -import Labeler from '@/containers/unit/Labeler' import CommunitySetter from '@/containers/tool/CommunitySetter' import Tooltip from '@/components/Tooltip' import ArticleActionsPanel from '@/components/ArticleActionsPanel' @@ -78,16 +77,6 @@ const ArticleBodyHeaderContainer = ({ {middle === 'linker' && } - {middle === 'labeler' && ( - ${thread}.tag.set`} - ownerId={data.author && data.author.id} - fallbackProps="readOnly" - onTagSelect={onTagSelect} - onTagUnselect={onTagUnselect} - selected={tagTitleList} - /> - )}
) diff --git a/src/containers/unit/ArticleFooter/Actions/index.tsx b/src/containers/unit/ArticleFooter/Actions/index.tsx index 57aade781..5c54e5338 100644 --- a/src/containers/unit/ArticleFooter/Actions/index.tsx +++ b/src/containers/unit/ArticleFooter/Actions/index.tsx @@ -1,6 +1,6 @@ import { FC, memo } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { report } from '@/utils' import DotDivider from '@/components/DotDivider' @@ -14,8 +14,6 @@ type TProps = { } const Actions: FC = ({ showReferenceList, showOperationList }) => { - const { isMobile } = useDevice() - return ( toggleActionPanel('reference-list')}> diff --git a/src/containers/unit/Comments/Comment/index.tsx b/src/containers/unit/Comments/Comment/index.tsx index 20ccbf0e7..14a98f980 100755 --- a/src/containers/unit/Comments/Comment/index.tsx +++ b/src/containers/unit/Comments/Comment/index.tsx @@ -1,13 +1,11 @@ import { Fragment, memo } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView/index' const Comment = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/containers/unit/Comments/List/Header.tsx b/src/containers/unit/Comments/List/Header.tsx index 41025fc0d..99fbd3169 100644 --- a/src/containers/unit/Comments/List/Header.tsx +++ b/src/containers/unit/Comments/List/Header.tsx @@ -1,6 +1,7 @@ import { FC, memo } from 'react' import { ICON } from '@/config' +import { SVG } from '@/constant' import { IconButton } from '@/components/Buttons' import { IconSwitcher } from '@/components/Switcher' @@ -50,7 +51,7 @@ const Header: FC = ({ totalCount, filterType }) => { = ({ totalCount, filterType }) => { {isAllFolded ? ( ) : ( diff --git a/src/containers/unit/Footer/index.tsx b/src/containers/unit/Footer/index.tsx index 118143965..245332d80 100755 --- a/src/containers/unit/Footer/index.tsx +++ b/src/containers/unit/Footer/index.tsx @@ -6,14 +6,12 @@ import { Fragment } from 'react' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView' import MobileView from './MobileView' const FooterContainer = (props) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/containers/unit/Header/DesktopView/ArticleView.tsx b/src/containers/unit/Header/DesktopView/ArticleView.tsx index fa683dbb3..c7e6857db 100644 --- a/src/containers/unit/Header/DesktopView/ArticleView.tsx +++ b/src/containers/unit/Header/DesktopView/ArticleView.tsx @@ -11,7 +11,6 @@ import type { TMetric } from '@/spec' import { ICON } from '@/config' import { pluggedIn, buildLog } from '@/utils' -import UserLister from '@/containers/user/UserLister' import Navigator from '@/components/Navigator' import type { TStore } from '../store' @@ -76,7 +75,6 @@ const ArticleHeaderContainer: FC = ({ header: store, metric }) => { {MailBox && } - {/* */} diff --git a/src/containers/unit/Header/DesktopView/CommunityVIew.tsx b/src/containers/unit/Header/DesktopView/CommunityVIew.tsx index 5329c90c2..8c5bfe5b1 100644 --- a/src/containers/unit/Header/DesktopView/CommunityVIew.tsx +++ b/src/containers/unit/Header/DesktopView/CommunityVIew.tsx @@ -11,11 +11,9 @@ import type { TMetric } from '@/spec' import { C11N, METRIC } from '@/constant' import { pluggedIn, buildLog } from '@/utils' -import UserLister from '@/containers/user/UserLister' import Navigator from '@/components/Navigator' import type { TStore } from '../store' -import UserAccount from '../UserAccount' import AddOns from '../AddOns' import { @@ -34,6 +32,8 @@ const log = buildLog('C:Header') let MailBox +const UserAccount = dynamic(() => import('../UserAccount'), { ssr: false }) + type TProps = { // T.oneOf(values(METRIC)) TODO metric?: TMetric @@ -95,8 +95,6 @@ const CommunityHeaderContainer: FC = ({ {MailBox && } - - {/* */} diff --git a/src/containers/unit/Header/index.tsx b/src/containers/unit/Header/index.tsx index 4636e1576..58a6021b3 100755 --- a/src/containers/unit/Header/index.tsx +++ b/src/containers/unit/Header/index.tsx @@ -5,15 +5,13 @@ */ import { ANCHOR } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import DesktopView from './DesktopView/index' import { Wrapper, MobileWrapper } from './styles' const HeaderContainer = ({ metric }) => { - const { isMobile } = useDevice() - return ( {!isMobile ? : } diff --git a/src/containers/unit/Labeler/Options.js b/src/containers/unit/Labeler/Options.js deleted file mode 100755 index 25b04ee81..000000000 --- a/src/containers/unit/Labeler/Options.js +++ /dev/null @@ -1,57 +0,0 @@ -import React from 'react' -import { contains } from 'ramda' - -import { ICON_CMD, LABEL_POOL } from '@/config' -import { uid } from '@/utils' - -import TagList from './TagList' - -import { - OptionWrapper, - OptionItem, - OptionCheckIcon, - OptionText, -} from './styles/options' - -const OptionItems = ({ items, selected, onOptionSelect }) => ( - - {items.map((item) => ( - - - onOptionSelect(item)}>{item} - - ))} - -) - -const renderOptions = (label, items, selected, onOptionSelect) => { - switch (label) { - case 'default': - case 'city': - return ( - - ) - - default: - return ( - - ) - } -} - -const Options = ({ label, items, selected, onOptionSelect }) => ( - <>{renderOptions(label, items, selected, onOptionSelect)} -) - -export default React.memo(Options) diff --git a/src/containers/unit/Labeler/Selected.js b/src/containers/unit/Labeler/Selected.js deleted file mode 100755 index 688f031ba..000000000 --- a/src/containers/unit/Labeler/Selected.js +++ /dev/null @@ -1,81 +0,0 @@ -import React from 'react' -import { reject, isEmpty } from 'ramda' - -import Maybe from '@/components/Maybe' -import { uid, Trans } from '@/utils' -import { Wrapper, Item, Hightlight } from './styles/selected' - -const renderItems = (items) => { - if (!items) return null - const tagsList = reject((t) => t === 'refined', items) - - switch (tagsList.length) { - case 0: - return (--) - - case 1: - return ( - - ({Trans(tagsList[0])}) - - ) - - case 2: - return ( - - ( - - {Trans(tagsList[0])}, {Trans(tagsList[1])} - - ) - - ) - - default: - return ( - - ({Trans(tagsList[0])}, ..) - - ) - } -} - -const renderReadonlyItems = (items) => { - if (!items) return null - const tagsList = reject((t) => t === 'refined', items) - - const totalLength = tagsList.length - - if (totalLength === 0) return (--) - - if (totalLength === 1) { - return ( - - {Trans(tagsList[0])} - - ) - } - - return ( - - {tagsList.slice(0, totalLength - 1).map((tag) => ( - {Trans(tag)}, - ))} - - {Trans(tagsList[totalLength - 1])} - - ) -} - -const Selected = ({ items, readOnly }) => ( - - - {renderItems(items)} - - - {renderReadonlyItems(items)} - - -) - -export default React.memo(Selected) diff --git a/src/containers/unit/Labeler/TagList.js b/src/containers/unit/Labeler/TagList.js deleted file mode 100755 index 0b2d0f385..000000000 --- a/src/containers/unit/Labeler/TagList.js +++ /dev/null @@ -1,25 +0,0 @@ -import React from 'react' -import { contains } from 'ramda' - -import { ICON_CMD } from '@/config' - -import { uid, sortByColor, Trans } from '@/utils' -import { OptionCheckIcon } from './styles/options' -import { Wrapper, TagItem, TagDot, TagTitle } from './styles/tag_list' - -const TagList = ({ items, selected, onOptionSelect }) => ( - - {sortByColor(items).map((tag) => ( - onOptionSelect(tag.title)}> - - - {Trans(tag.title)} - - ))} - -) - -export default React.memo(TagList) diff --git a/src/containers/unit/Labeler/index.class.js b/src/containers/unit/Labeler/index.class.js deleted file mode 100755 index 8abb04027..000000000 --- a/src/containers/unit/Labeler/index.class.js +++ /dev/null @@ -1,147 +0,0 @@ -/* - * - * Labeler - * - */ - -import React from 'react' -import T from 'prop-types' -import { inject, observer } from 'mobx-react' -import { contains, propEq, findIndex, reject } from 'ramda' - -import { LABEL_POOL } from '@/config' -import { buildLog, storePlug, uid, Trans } from '@/utils' -import { withGuardian } from '@/hoc' - -import Maybe from '@/components/Maybe' -import Tooltip from '@/components/Tooltip' - -import Options from './Options' -import Selected from './Selected' -import { Wrapper, LabelItem, LabelIcon, Title, PopHint } from './styles' - -import * as logic from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('C:Labeler') - -class LabelerContainer extends React.Component { - constructor(props) { - super(props) - this.state = { uniqId: uid.gen() } - - const { labeler, label, multi, selected } = props - const { uniqId } = this.state - - const options = { label, multi, selected } - logic.init(labeler, uniqId, options) - } - - componentWillUnmount() { - const { uniqId } = this.state - logic.uninit(uniqId) - } - - onTagSelect(uniqId, item) { - const { selected, onTagSelect, onTagUnselect } = this.props - // const { labelsData, labelEntriesData } = labeler - logic.onOptionSelect(uniqId, item) - const tagId = logic.getSelectedTagId(item) - if (contains(item, selected)) { - onTagUnselect(tagId) - } else { - onTagSelect(tagId) - } - } - - render() { - const { uniqId } = this.state - const { labeler, label, readOnly } = this.props - /* const { tagsData, popVisible, selectedData, labelEntriesData } = labeler */ - const { labelEntriesData } = labeler - const targetIndex = findIndex(propEq('uniqId', uniqId))(labelEntriesData) - - const { tags, popVisible, selected } = labelEntriesData[targetIndex] || {} - const tagsList = reject((t) => t.title === 'refined', tags) - - return ( - - - {Trans[label]}} - placement="bottom" - > - - - - <Selected items={selected} readOnly={readOnly} /> - - - - - - {targetIndex >= 0 ? ( - this.onTagSelect(uniqId)} - /> - } - placement="right" - trigger="click" - visible={popVisible} - onVisibleChange={() => logic.onVisibleChange(uniqId)} - > - - - - {Trans[label]} - <Selected items={selected} readOnly={readOnly} /> - - - - ) : ( -
- )} - - - ) - } -} - -LabelerContainer.propTypes = { - label: T.oneOf([ - 'default', - 'salary', - 'city', - 'exp', - 'education', - 'finance', - 'scale', - 'field', - ]), - labeler: T.any, - multi: T.bool, - selected: T.arrayOf(T.string), - - onTagSelect: T.func, - onTagUnselect: T.func, - readOnly: T.bool, -} - -LabelerContainer.defaultProps = { - label: 'default', - labeler: {}, - multi: false, - selected: [], - readOnly: false, - onTagSelect: log, - onTagUnselect: log, -} - -export default withGuardian( - inject(storePlug('labeler'))(observer(LabelerContainer)), -) diff --git a/src/containers/unit/Labeler/index.hooks.js b/src/containers/unit/Labeler/index.hooks.js deleted file mode 100755 index 2dd46efc6..000000000 --- a/src/containers/unit/Labeler/index.hooks.js +++ /dev/null @@ -1,104 +0,0 @@ -/* - * - * Labeler - * - */ - -/* -import React, { useState } from 'react' -import T from 'prop-types' -import { inject, observer } from 'mobx-react' -import { findIndex, reject, propEq } from 'ramda' - -import { LABEL_POOL } from '@/config' -import { pluggedIn, buildLog, storePlug, uid } from '@/utils' - -import { withGuardian } from '@/hoc' -import Maybe from '@/components/Maybe' -import Tooltip from '@/components/Tooltip' -import Options from './Options' -import Selected from './Selected' - -import { Wrapper, LabelItem, LabelIcon, Title, PopHint } from './styles' -import { useInit, onVisibleChange, onTagSelect } from './logic' - -const log = buildLog('C:Labeler') - -const trans = { - default: '标签', - city: '城市', - salary: '月薪', - exp: '经验', - education: '学历', - finance: '融资', - scale: '规模', - field: '领域', -} - -const LabelerContainer = ({ - labeler, - label, - multi, - readOnly, - selected, - onTagSelect: onTagSelectCb, - onTagUnselect: onTagUnselectCb, -}) => { - const [uniqId] = useState(uid.gen()) - const options = { label, multi, selected } - - log('uniqId: ', uniqId) - log('options: ', options) - - useInit(labeler, '1001', options) - // useInit(labeler, options) - - const { labelEntriesData } = labeler - const targetIndex = findIndex(propEq('uniqId', uniqId))(labelEntriesData) - - const { tags, popVisible, selected: selectedOnes } = - labelEntriesData[targetIndex] || {} - - log('targetIndex --> ', targetIndex) - log('labelEntriesData -> ', labelEntriesData) - log('tags --> : ', tags) - - const tagsList = tags ? reject(t => t.title === 'refined', tags) : [] - - const callbacks = { onTagSelectCb, onTagUnselectCb } - - return fjie -} - -LabelerContainer.propTypes = { - label: T.oneOf([ - 'default', - 'salary', - 'city', - 'exp', - 'education', - 'finance', - 'scale', - 'field', - ]), - labeler: T.any, - multi: T.bool, - selected: T.arrayOf(T.string), - - onTagSelect: T.func, - onTagUnselect: T.func, - readOnly: T.bool, -} - -LabelerContainer.defaultProps = { - label: 'default', - labeler: {}, - multi: false, - selected: [], - readOnly: false, - onTagSelect: log, - onTagUnselect: log, -} - -export default withGuardian(pluggedIn(LabelerContainer)) -*/ diff --git a/src/containers/unit/Labeler/index.js b/src/containers/unit/Labeler/index.js deleted file mode 100755 index 3c6c09cf4..000000000 --- a/src/containers/unit/Labeler/index.js +++ /dev/null @@ -1,153 +0,0 @@ -/* - * - * Labeler - * - */ - -import React from 'react' -import T from 'prop-types' -import { inject, observer } from 'mobx-react' -import { findIndex, propEq, reject, contains } from 'ramda' - -import { LABEL_POOL } from '@/config' -import { buildLog, storePlug, uid, Trans } from '@/utils' -import { withGuardian } from '@/hoc' - -import Maybe from '@/components/Maybe' -import Tooltip from '@/components/Tooltip' - -import Options from './Options' -import Selected from './Selected' - -import { Wrapper, LabelItem, LabelIcon, Title, PopHint } from './styles' -import { - init, - uninit, - onOptionSelect, - getSelectedTagId, - onVisibleChange, -} from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('C:Labeler') - -class LabelerContainer extends React.Component { - constructor(props) { - super(props) - this.state = { uniqId: uid.gen() } - - const { labeler, label, multi, selected } = props - const { uniqId } = this.state - - const options = { label, multi, selected } - init(labeler, uniqId, options) - } - - componentWillUnmount() { - const { uniqId } = this.state - uninit(uniqId) - } - - onTagSelect(uniqId, item) { - const { selected, onTagSelect, onTagUnselect } = this.props - // const { labelsData, labelEntriesData } = labeler - onOptionSelect(uniqId, item) - const tagId = getSelectedTagId(item) - if (contains(item, selected)) { - onTagUnselect(tagId) - } else { - onTagSelect(tagId) - } - } - - render() { - const { uniqId } = this.state - const { labeler, label, readOnly } = this.props - /* const { tagsData, popVisible, selectedData, labelEntriesData } = labeler */ - const { labelEntriesData } = labeler - const targetIndex = findIndex(propEq('uniqId', uniqId))(labelEntriesData) - - const { tags, popVisible, selected } = labelEntriesData[targetIndex] || {} - const tagsList = reject((t) => t.title === 'refined', tags) - - return ( - - - {Trans[label]}} - placement="bottom" - > - - - - <Selected items={selected} readOnly={readOnly} /> - - - - - - {targetIndex >= 0 ? ( - this.onTagSelect(uniqId)} - /> - } - placement="right" - trigger="click" - visible={popVisible} - onVisibleChange={() => onVisibleChange(uniqId)} - > - - - - {Trans[label]} - <Selected items={selected} readOnly={readOnly} /> - - - - ) : ( -
- )} - - - ) - } -} - -LabelerContainer.propTypes = { - label: T.oneOf([ - 'default', - 'salary', - 'city', - 'exp', - 'education', - 'finance', - 'scale', - 'field', - ]), - labeler: T.any, - multi: T.bool, - selected: T.arrayOf(T.string), - - onTagSelect: T.func, - onTagUnselect: T.func, - readOnly: T.bool, -} - -LabelerContainer.defaultProps = { - label: 'default', - labeler: {}, - multi: false, - selected: [], - readOnly: false, - onTagSelect: log, - onTagUnselect: log, -} - -export default withGuardian( - inject(storePlug('labeler'))(observer(LabelerContainer)), -) diff --git a/src/containers/unit/Labeler/logic.hooks.js b/src/containers/unit/Labeler/logic.hooks.js deleted file mode 100755 index 5018ac4de..000000000 --- a/src/containers/unit/Labeler/logic.hooks.js +++ /dev/null @@ -1,20 +0,0 @@ -// ... - -// ############################### -// init & uninit -// ############################### -/* -export const useInit = (_store, uniqId, options) => { - useEffect( - () => { - store = _store - store.markUniqState(uniqId, options) - - return () => { - store.uninit(uniqId) - } - }, - [_store, uniqId, options] - ) -} -*/ diff --git a/src/containers/unit/Labeler/logic.js b/src/containers/unit/Labeler/logic.js deleted file mode 100755 index ff645c0af..000000000 --- a/src/containers/unit/Labeler/logic.js +++ /dev/null @@ -1,101 +0,0 @@ -import { - findIndex, - propEq, - reject, - uniq, - concat, - contains, - toUpper, -} from 'ramda' - -import { buildLog, asyncSuit, makeGQClient } from '@/utils' -import S from './schema' - -/* eslint-disable-next-line */ -const log = buildLog('L:Labeler') - -const { SR71, $solver } = asyncSuit -const sr71$ = new SR71() - -let sub$ = null -let store = null - -export const loadTags = (uniqId) => { - const communityId = store.curCommunity.id - const thread = toUpper(store.curThread) - - const args = { communityId, thread } - const { request } = makeGQClient() - - request(S.partialTags, args) - .then(({ partialTags: tags }) => store.markUniqState(uniqId, { tags })) - .catch(() => store.toast('error', { title: 'tag 加载失败', msg: '--' })) -} - -export const onOptionSelect = (uniqId, item) => { - const index = findIndex(propEq('uniqId', uniqId))(store.labelEntriesData) - if (index < 0) return false - // return false - // toggle item if exist - if (contains(item, store.labelEntriesData[index].selected)) { - return store.markUniqState(uniqId, { - selected: reject( - (e) => e === item, - store.labelEntriesData[index].selected, - ), - }) - } - // replace selected if single select mode - if (!store.labelEntriesData[index].multi) { - return store.markUniqState(uniqId, { popVisible: false, selected: [item] }) - } - // push to selected if multi select mode - store.markUniqState(uniqId, { - selected: uniq(concat(store.labelEntriesData[index].selected, [item])), - }) -} - -export const getSelectedTagId = (label) => { - return store.getSelectedTagId(label) -} - -export const onVisibleChange = (uniqId, popVisible) => { - store.markUniqState(uniqId, { popVisible }) - - const index = findIndex(propEq('uniqId', uniqId))(store.labelEntriesData) - if (index < 0) return false - - const needLoad = - store.labelEntriesData[index].label === 'default' || - store.labelEntriesData[index].label === 'city' - - if (popVisible && needLoad) { - // logic.loadTagsIfNeed() - loadTags(uniqId) - } -} - -// ############################### -// Data & Error handlers -// ############################### - -const DataSolver = [ - /* - { - match: asyncRes('partialTags'), - action: ({ partialTags: tags }) => store.markUniqState({ tags }), - }, - */ -] -const ErrSolver = [] - -export const init = (_store, uniqId, options) => { - store = _store - - if (sub$) false - sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) - - store.markUniqState(uniqId, options) -} - -export const uninit = (uniqId) => store.uninit(uniqId) diff --git a/src/containers/unit/Labeler/schema.ts b/src/containers/unit/Labeler/schema.ts deleted file mode 100755 index 7b28b2bef..000000000 --- a/src/containers/unit/Labeler/schema.ts +++ /dev/null @@ -1,22 +0,0 @@ -// import gql from 'graphql-tag' - -const partialTags = ` - query($communityId: ID, $community: String, $thread: CmsThread!) { - partialTags( - communityId: $communityId - community: $community - thread: $thread - ) { - id - title - color - thread - } - } -` - -const schema = { - partialTags, -} - -export default schema diff --git a/src/containers/unit/Labeler/store.js b/src/containers/unit/Labeler/store.js deleted file mode 100755 index 1e1c32033..000000000 --- a/src/containers/unit/Labeler/store.js +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Labeler store - * - */ - -import { types as T, getParent } from 'mobx-state-tree' -import { forEach, merge, reject, findIndex, propEq, concat } from 'ramda' -import { markStates, buildLog, stripMobx } from '@/utils' -import { Tag } from '@/model' - -/* eslint-disable-next-line */ -const log = buildLog('S:Labeler') - -const RealLabel = T.model('RealLabel', { - uniqId: T.string, - popVisible: T.optional(T.boolean, false), - tags: T.optional(T.array(Tag), []), - label: T.optional( - T.enumeration([ - 'default', - 'salary', - 'city', - 'exp', - 'education', - 'finance', - 'scale', - 'field', - ]), - 'default', - ), - multi: T.optional(T.boolean, false), - selected: T.optional(T.array(T.string), []), -}) - -/* - NOTE: this is a triky modal - normaly the same container should be uniq on the viewing page, - but the label containers may occured many in same place, like job attrs selector, - this will cause serious problem, because labeler maybe lot, bug the they are all - connect to the same store in the rootStore. so i manulay ass a uniqId to store - each copy of the current labeler store. - */ -const Labeler = T.model('Labeler', { - labelEntries: T.optional(T.array(RealLabel), []), -}) - .views((self) => ({ - get root() { - return getParent(self) - }, - get curCommunity() { - return stripMobx(self.root.viewing.community) - }, - get curThread() { - return self.root.viewing.activeThread - }, - get labelEntriesData() { - return stripMobx(self.labelEntries) - }, - // TODO: refactor those shit code below - // return the label map key-value - get labelsData() { - const labelList = stripMobx(self.labelEntries) - - const mapData = { tags: [] } - forEach((label) => { - if (label.label === 'city' || label.label === 'default') { - if (label.multi) { - forEach((selectedLabel) => { - const tagId = self.root.tagsBar.getTagIdByTitle(selectedLabel) - if (tagId !== false) { - mapData.tags.push({ id: tagId }) - } - }, label.selected) - } else { - const tagId = self.root.tagsBar.getTagIdByTitle(label.selected[0]) - if (tagId !== false) { - mapData.tags.push({ id: tagId }) - } - return false - } - } - - if (label.multi) { - mapData[label.label] = label.selected - } else { - mapData[label.label] = label.selected[0] || '' - } - }, labelList) - - return mapData - }, - })) - .actions((self) => ({ - toast(type, options) { - self.root.toast(type, options) - }, - // getSelectedTagId(uniqId, label) { - getSelectedTagId(label) { - // const labelList = stripMobx(self.labelEntries) - // const index = findIndex(propEq('uniqId', uniqId))( - // self.labelEntriesData - // ) - - const tagId = self.root.tagsBar.getTagIdByTitle(label) - return tagId - }, - markUniqState(uniqId, sobj) { - sobj = merge(sobj, { uniqId }) - const index = findIndex(propEq('uniqId', uniqId))(self.labelEntriesData) - - if (index >= 0) { - self.labelEntries[index] = merge(self.labelEntriesData[index], sobj) - } else { - self.labelEntries = concat(self.labelEntriesData, [sobj]) - } - }, - uninit(uniqId) { - self.labelEntries = reject( - propEq('uniqId', uniqId), - self.labelEntriesData, - ) - }, - mark(sobj) { - markStates(sobj, self) - }, - })) - -export default Labeler diff --git a/src/containers/unit/Labeler/styles/index.ts b/src/containers/unit/Labeler/styles/index.ts deleted file mode 100755 index 31f482241..000000000 --- a/src/containers/unit/Labeler/styles/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme, css } from '@/utils' - -export const Wrapper = styled.div`` - -export const LabelItem = styled.div` - ${css.flex('align-center')}; - color: ${theme('editor.footer')}; - &:hover { - color: ${theme('banner.title')}; - } -` -export const LabelIcon = styled(Img)` - fill: ${theme('editor.content')}; - ${css.size(16)}; - margin-right: 3px; - - ${LabelItem}:hover & { - fill: ${theme('editor.footerHover')}; - } -` -export const Title = styled.div` - ${css.flex('align-center')}; - cursor: pointer; - font-size: 1rem; - margin-top: 2px; - ${LabelItem}:hover & { - color: ${theme('editor.footerHover')}; - } -` -export const PopHint = styled.div` - padding: 5px 8px; - color: ${theme('thread.articleDigest')}; -` diff --git a/src/containers/unit/Labeler/styles/options.ts b/src/containers/unit/Labeler/styles/options.ts deleted file mode 100755 index fef898a15..000000000 --- a/src/containers/unit/Labeler/styles/options.ts +++ /dev/null @@ -1,28 +0,0 @@ -import styled from 'styled-components' - -import type { TActive } from '@/spec' -import Img from '@/Img' -import { theme, css } from '@/utils' - -export const OptionWrapper = styled.div` - ${css.flexColumn()}; - padding: 10px; -` -export const OptionItem = styled.div` - ${css.flex()}; - margin-bottom: 4px; - font-size: 0.9rem; - color: ${theme('banner.desc')}; - font-weight: bold; - &:hover { - color: ${theme('banner.title')}; - cursor: pointer; - } -` -export const OptionCheckIcon = styled(Img)` - fill: ${theme('banner.title')}; - opacity: ${({ active }) => (active ? '1' : '0')}; - ${css.size(12)}; - margin-right: 3px; -` -export const OptionText = styled.div`` diff --git a/src/containers/unit/Labeler/styles/selected.ts b/src/containers/unit/Labeler/styles/selected.ts deleted file mode 100755 index 271bbc5af..000000000 --- a/src/containers/unit/Labeler/styles/selected.ts +++ /dev/null @@ -1,14 +0,0 @@ -import styled from 'styled-components' - -import { theme, css } from '@/utils' - -export const Wrapper = styled.div` - ${css.flex()}; -` -export const Item = styled.div` - ${css.flex('align-center')}; - color: ${theme('editor.footer')}; -` -export const Hightlight = styled.div` - color: ${theme('contrastFg')}; -` diff --git a/src/containers/unit/Labeler/styles/tag_list.ts b/src/containers/unit/Labeler/styles/tag_list.ts deleted file mode 100755 index 984cce5f9..000000000 --- a/src/containers/unit/Labeler/styles/tag_list.ts +++ /dev/null @@ -1,39 +0,0 @@ -import styled from 'styled-components' - -import { theme, animate, css } from '@/utils' - -export const Wrapper = styled.div` - padding: 10px; - padding-bottom: 0; -` - -export const LabelItem = styled.div` - ${css.flex()}; - color: ${theme('editor.footer')}; - &:hover { - color: #51abb2; - animation: ${animate.pulse} 0.4s linear; - } -` - -export const TagItem = styled.div` - ${css.flex('align-center')}; - margin-bottom: 8px; - &:hover { - cursor: pointer; - font-weight: bold; - } -` -export const TagDot = styled.div` - ${css.circle(12)}; - margin-right: 8px; - margin-left: 3px; - background-color: ${({ color }) => color}; - opacity: ${theme('tags.dotOpacity')}; -` -// ${props => (props.active === props.title ? 1 : 0.7)} - -export const TagTitle = styled.div` - color: ${theme('tags.text')}; - font-size: 1rem; -` diff --git a/src/containers/unit/Labeler/tests/index.test.ts b/src/containers/unit/Labeler/tests/index.test.ts deleted file mode 100755 index 04dbe6d86..000000000 --- a/src/containers/unit/Labeler/tests/index.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import React from 'react' -// import { shallow } from 'enzyme' - -// import Labeler from '../index' - -describe('TODO ', () => { - it('Expect to have unit tests specified', () => { - expect(true).toEqual(true) - }) -}) diff --git a/src/containers/unit/Labeler/tests/store.test.ts b/src/containers/unit/Labeler/tests/store.test.ts deleted file mode 100755 index c701fcd11..000000000 --- a/src/containers/unit/Labeler/tests/store.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * Labeler store test - * - */ - -// import Labeler from '../index' - -it('TODO: store test Labeler', () => { - expect(1 + 1).toBe(2) -}) diff --git a/src/containers/unit/ModeLine/TopBar/index.js b/src/containers/unit/ModeLine/TopBar/index.js index e6b3989b3..44fea6eba 100644 --- a/src/containers/unit/ModeLine/TopBar/index.js +++ b/src/containers/unit/ModeLine/TopBar/index.js @@ -1,13 +1,11 @@ import React, { useEffect } from 'react' import dynamic from 'next/dynamic' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' let CurTopBar = null const Topbar = (props) => { - const { isMobile } = useDevice() - useEffect(() => { if (isMobile) { CurTopBar = dynamic(() => import('./MobileView/index'), { ssr: false }) diff --git a/src/containers/unit/ModeLine/index.tsx b/src/containers/unit/ModeLine/index.tsx index 71a75c040..73c980129 100755 --- a/src/containers/unit/ModeLine/index.tsx +++ b/src/containers/unit/ModeLine/index.tsx @@ -7,7 +7,7 @@ import dynamic from 'next/dynamic' import type { TMetric } from '@/spec' import { METRIC } from '@/constant' -import { useDevice } from '@/hooks' +import { isMobile } from 'react-device-detect' import { pluggedIn, buildLog } from '@/utils' import type { TStore } from './store' @@ -38,7 +38,6 @@ const ModeLineContainer: FC = ({ activeMenu, isCommunityBlockExpand, } = store - const { isMobile } = useDevice() // viewing: { community, activeThread }, useEffect(() => { diff --git a/src/containers/viewer/ArticleViewer/PostViewer/index.tsx b/src/containers/viewer/ArticleViewer/PostViewer/index.tsx index 0392b8245..f96024ceb 100644 --- a/src/containers/viewer/ArticleViewer/PostViewer/index.tsx +++ b/src/containers/viewer/ArticleViewer/PostViewer/index.tsx @@ -3,11 +3,11 @@ */ import { FC, memo, Fragment, useCallback, useState } from 'react' -import { Waypoint } from 'react-waypoint' import type { TPost } from '@/spec' import { buildLog } from '@/utils' +import ViewportTracker from '@/components/ViewportTracker' import { ArticleContentLoading } from '@/components/Loading' import FixedHeader from './FixedHeader' @@ -37,7 +37,7 @@ const PostViewer: FC = ({ article, loading }) => {
{article.title} - + {loading ? ( diff --git a/src/containers/viewer/ArticleViewer/WorksViewer/index.tsx b/src/containers/viewer/ArticleViewer/WorksViewer/index.tsx index bab6b919b..22fd1befb 100644 --- a/src/containers/viewer/ArticleViewer/WorksViewer/index.tsx +++ b/src/containers/viewer/ArticleViewer/WorksViewer/index.tsx @@ -3,17 +3,17 @@ */ import { FC, memo, Fragment, useCallback, useState } from 'react' -import { Waypoint } from 'react-waypoint' import type { TPost } from '@/spec' import { buildLog } from '@/utils' +import ViewportTracker from '@/components/ViewportTracker' +import { ArticleContentLoading } from '@/components/Loading' + import FixedHeader from './FixedHeader' import Header from './Header' import ArticleInfo from './ArticleInfo' -import { ArticleContentLoading } from '@/components/Loading' - import { Wrapper, BodyWrapper, ArticleBody } from '../styles/works_viewer' /* eslint-disable-next-line */ @@ -36,7 +36,7 @@ const WorksViewer: FC = ({ article, loading }) => {
- + {loading ? ( diff --git a/src/containers/viewer/JobViewer/DigestBar.js b/src/containers/viewer/JobViewer/DigestBar.js deleted file mode 100755 index 00c6c6291..000000000 --- a/src/containers/viewer/JobViewer/DigestBar.js +++ /dev/null @@ -1,28 +0,0 @@ -import React from 'react' -import { pluck } from 'ramda' - -import { ICON_CMD } from '@/config' - -import Labeler from '@/containers/unit/Labeler' - -import { Wrapper, Divider } from './styles/digest_bar' - -const JobDigestBar = ({ data }) => ( - - - - - - - - - - - - - - - -) - -export default React.memo(JobDigestBar) diff --git a/src/containers/viewer/JobViewer/index.js b/src/containers/viewer/JobViewer/index.js deleted file mode 100755 index fdc1290a7..000000000 --- a/src/containers/viewer/JobViewer/index.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * JobViewer - * - */ - -import React from 'react' - -import { THREAD } from '@/constant' -import { pluggedIn, buildLog } from '@/utils' - -import Comments from '@/containers/unit/Comments' -import ArticleViewerHeader from '@/containers/unit/ArticleViewerHeader' -import ArticleBodyHeader from '@/containers/unit/ArticleBodyHeader' -import Maybe from '@/components/Maybe' -import MarkDownRender from '@/components/MarkDownRender' -import { ArticleContentLoading } from '@/components/Loading' - -import DigestBar from './DigestBar' - -import { - BodyWrapper, - CommentsWrapper, - ArticleTitle, - ArticleBody, -} from './styles' - -import { useInit } from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('C:JobViewer') - -const JobViewerContainer = ({ jobViewer: store, attachment }) => { - useInit(store, attachment) - - const { curCommunity, viewingData, loading } = store - - const company = { - title: viewingData.company, - link: viewingData.companyLink, - logo: viewingData.companyLogo, - } - - return ( - - - - - {viewingData.title} - }> - - - - - - - - - - - - ) -} - -export default pluggedIn(JobViewerContainer) diff --git a/src/containers/viewer/JobViewer/logic.js b/src/containers/viewer/JobViewer/logic.js deleted file mode 100755 index 771142770..000000000 --- a/src/containers/viewer/JobViewer/logic.js +++ /dev/null @@ -1,131 +0,0 @@ -import { useEffect } from 'react' -import { merge, toUpper } from 'ramda' - -import { TYPE, EVENT, ERR } from '@/constant' -import { asyncSuit, buildLog, closeDrawer, errRescue } from '@/utils' - -import S from './schema' - -/* eslint-disable-next-line */ -const log = buildLog('L:JobViewer') - -const { SR71, $solver, asyncRes, asyncErr } = asyncSuit -const sr71$ = new SR71({ - receive: [EVENT.DRAWER.CLOSE], -}) - -let sub$ = null -let store = null - -export const onTagSelect = (tagId) => { - const { id } = store.viewingData - const communityId = store.curCommunity.id - const thread = toUpper(store.activeThread) - - sr71$.mutate(S.setTag, { thread, id, tagId, communityId }) -} - -export const onTagUnselect = (tagId) => { - const { id } = store.viewingData - const communityId = store.curCommunity.id - const thread = toUpper(store.activeThread) - - sr71$.mutate(S.unsetTag, { thread, id, tagId, communityId }) -} - -const loadJob = ({ id }) => { - const userHasLogin = store.isLogin - const variables = { id, userHasLogin } - markLoading() - log('loadJob variables: ', variables) - sr71$.query(S.job, variables) -} - -const openAttachment = (att) => { - if (!att) return false - - const { type } = att - - if (type === TYPE.DRAWER.JOB_VIEW) { - loadJob(att) - store.mark({ type }) - store.setViewing({ job: att }) - } -} - -const markLoading = (maybe = true) => store.mark({ loading: maybe }) -// ############################### -// Data & Error handlers -// ############################### - -const DataSolver = [ - { - match: asyncRes('job'), - action: ({ job }) => { - store.setViewing({ job: merge(store.viewingData, job) }) - store.syncViewingItem(job) - markLoading(false) - }, - }, - { - match: asyncRes(EVENT.DRAWER.CLOSE), - action: () => { - sr71$.stop() - markLoading(false) - }, - }, - { - match: asyncRes('setTag'), - action: () => { - loadJob(store.viewingData) - closeDrawer() - store.setViewing({ job: {} }) - }, - }, - { - match: asyncRes('unsetTag'), - action: () => { - loadJob(store.viewingData) - closeDrawer() - store.setViewing({ job: {} }) - }, - }, -] -const ErrSolver = [ - { - match: asyncErr(ERR.GRAPHQL), - action: () => markLoading(false), - }, - { - match: asyncErr(ERR.TIMEOUT), - action: ({ details }) => { - markLoading(false) - errRescue({ type: ERR.TIMEOUT, details, path: 'JobViewer' }) - }, - }, - { - match: asyncErr(ERR.NETWORK), - action: () => { - markLoading(false) - errRescue({ type: ERR.NETWORK, path: 'JobViewer' }) - }, - }, -] - -// ############################### -// init & uninit -// ############################### -export const useInit = (_store, attachment) => { - useEffect(() => { - store = _store - // log('effect init') - sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) - openAttachment(attachment) - - return () => { - // log('effect uninit') - sr71$.stop() - sub$.unsubscribe() - } - }, [_store, attachment]) -} diff --git a/src/containers/viewer/JobViewer/schema.ts b/src/containers/viewer/JobViewer/schema.ts deleted file mode 100755 index 308d335d0..000000000 --- a/src/containers/viewer/JobViewer/schema.ts +++ /dev/null @@ -1,44 +0,0 @@ -import gql from 'graphql-tag' -import { F, P } from '@/schemas' - -const job = gql` - query($id: ID!, $userHasLogin: Boolean!) { - job(id: $id) { - ${F.job} - body - author { - ${F.author} - } - tags { - ${F.tag} - } - origialCommunity { - ${F.community} - } - communities { - ${F.community} - } - commentsParticipators { - ${F.author} - } - favoritedCount - viewerHasViewed @include(if: $userHasLogin) - viewerHasFavorited @include(if: $userHasLogin) - favoritedCategoryId @include(if: $userHasLogin) - } - } -` -const setTag = gql` - ${P.setTag} -` -const unsetTag = gql` - ${P.unsetTag} -` - -const schema = { - job, - setTag, - unsetTag, -} - -export default schema diff --git a/src/containers/viewer/JobViewer/store.js b/src/containers/viewer/JobViewer/store.js deleted file mode 100755 index 41872f9b5..000000000 --- a/src/containers/viewer/JobViewer/store.js +++ /dev/null @@ -1,52 +0,0 @@ -/* - * JobViewer store - * - */ - -import { types as T, getParent } from 'mobx-state-tree' - -import { markStates, buildLog, stripMobx } from '@/utils' - -/* eslint-disable-next-line */ -const log = buildLog('S:JobViewer') - -const JobViewer = T.model('JobViewer', { - loading: T.optional(T.boolean, false), -}) - .views((self) => ({ - get root() { - return getParent(self) - }, - get curRoute() { - return self.root.curRoute - }, - get isLogin() { - return self.root.account.isLogin - }, - get accountInfo() { - return self.root.account.accountInfo - }, - get viewingData() { - return self.root.viewingData - }, - get curCommunity() { - return stripMobx(self.root.viewing.community) - }, - get activeThread() { - const { activeThread } = self.root.viewing - return activeThread - }, - })) - .actions((self) => ({ - setViewing(sobj) { - self.root.setViewing(sobj) - }, - syncViewingItem(item) { - self.root.viewing.syncViewingItem(item) - }, - mark(sobj) { - markStates(sobj, self) - }, - })) - -export default JobViewer diff --git a/src/containers/viewer/JobViewer/styles/digest_bar.ts b/src/containers/viewer/JobViewer/styles/digest_bar.ts deleted file mode 100755 index 5452dc6e0..000000000 --- a/src/containers/viewer/JobViewer/styles/digest_bar.ts +++ /dev/null @@ -1,16 +0,0 @@ -import styled from 'styled-components' - -import Img from '@/Img' -import { theme, css } from '@/utils' - -export const Wrapper = styled.div` - ${css.flex('align-both')}; - margin-top: 12px; - flex-wrap: wrap; -` -export const Divider = styled(Img)` - fill: ${theme('editor.footer')}; - ${css.size(12)}; - margin-left: 4px; - margin-right: 4px; -` diff --git a/src/containers/viewer/JobViewer/styles/index.ts b/src/containers/viewer/JobViewer/styles/index.ts deleted file mode 100755 index a42782500..000000000 --- a/src/containers/viewer/JobViewer/styles/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import styled from 'styled-components' - -import { theme, css } from '@/utils' - -export const BodyWrapper = styled.div` - ${css.flexColumn()}; - - padding: 20px; - background: ${theme('drawer.articleBg')}; - min-height: 400px; - margin-top: 5px; - margin-left: 4%; - margin-right: 4%; - border-radius: 3px; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04); -` -export const CommentsWrapper = styled.div` - min-height: 400px; - margin-top: 32px; - margin-left: 4%; - margin-right: 4%; - margin-bottom: 10%; - border-radius: 5px; -` - -export const ArticleTitle = styled.div` - color: ${theme('drawer.title')}; - font-size: 1.2rem; - align-self: center; - padding-top: 10px; - padding-bottom: 5px; - padding-left: 20px; - padding-right: 20px; - - border-bottom: 1px solid; - border-bottom-color: ${theme('drawer.divider')}; -` -export const ArticleBody = styled.article` - padding: 20px; - font-size: 1.2em; - line-height: 2em; - flex-grow: 1; -` -export const Footer = styled.div` - ${css.flex('align-both')}; -` diff --git a/src/containers/viewer/JobViewer/tests/index.test.ts b/src/containers/viewer/JobViewer/tests/index.test.ts deleted file mode 100755 index cc21959aa..000000000 --- a/src/containers/viewer/JobViewer/tests/index.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -// import React from 'react' -// import { shallow } from 'enzyme' - -// import JobViewer from '../index' - -describe('TODO ', () => { - it('Expect to have unit tests specified', () => { - expect(true).toEqual(true) - }) -}) diff --git a/src/containers/viewer/JobViewer/tests/store.test.ts b/src/containers/viewer/JobViewer/tests/store.test.ts deleted file mode 100755 index 9b14d6dcf..000000000 --- a/src/containers/viewer/JobViewer/tests/store.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * JobViewer store test - * - */ - -// import JobViewer from '../index' - -it('TODO: store test JobViewer', () => { - expect(1 + 1).toBe(2) -}) diff --git a/src/containers/viewer/PostViewer/index.js b/src/containers/viewer/PostViewer/index.js deleted file mode 100755 index a8770cb4b..000000000 --- a/src/containers/viewer/PostViewer/index.js +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * PostViewer - * - */ - -import React from 'react' -import T from 'prop-types' -import { pluck } from 'ramda' - -import { THREAD } from '@/constant' -import { pluggedIn, buildLog } from '@/utils' - -import Comments from '@/containers/unit/Comments' -import Labeler from '@/containers/unit/Labeler' -import ArticleViewerHeader from '@/containers/unit/ArticleViewerHeader' -import ArticleBodyHeader from '@/containers/unit/ArticleBodyHeader' - -import Maybe from '@/components/Maybe' -import MarkDownRender from '@/components/MarkDownRender' -import { ArticleContentLoading } from '@/components/Loading' - -import { - BodyWrapper, - CommentsWrapper, - ArticleTitle, - ArticleBody, - Footer, -} from './styles' - -import { useInit, onTagSelect, onTagUnselect, onCommentCreate } from './logic' - -/* eslint-disable-next-line */ -const log = buildLog('C:PostViewer') - -const PostViewerContainer = ({ postViewer: store, attachment }) => { - useInit(store, attachment) - - const { curCommunity, viewingData, loading } = store - const tagTitleList = pluck('title', viewingData.tags) - - return ( - - - - - {viewingData.title} - }> - - - - -
- ${THREAD.POST}.tag.set`} - ownerId={viewingData.author?.id} - fallbackProps="readOnly" - onTagSelect={onTagSelect} - onTagUnselect={onTagUnselect} - selected={tagTitleList} - /> -
-
- - - - -
- ) -} - -PostViewerContainer.propTypes = { - postViewer: T.object.isRequired, - attachment: T.any, -} - -PostViewerContainer.defaultProps = { - attachment: {}, -} - -export default pluggedIn(PostViewerContainer) diff --git a/src/containers/viewer/PostViewer/logic.js b/src/containers/viewer/PostViewer/logic.js deleted file mode 100755 index b877e5f87..000000000 --- a/src/containers/viewer/PostViewer/logic.js +++ /dev/null @@ -1,133 +0,0 @@ -import { useEffect } from 'react' -import { merge, toUpper } from 'ramda' - -import { TYPE, EVENT, ERR } from '@/constant' -import { asyncSuit, buildLog, closeDrawer, errRescue } from '@/utils' - -import S from './schema' - -/* eslint-disable-next-line */ -const log = buildLog('L:PostViewer') - -const { SR71, $solver, asyncRes, asyncErr } = asyncSuit -const sr71$ = new SR71({ - receive: [EVENT.DRAWER.CLOSE], -}) - -let sub$ = null -let store = null - -export const onTagSelect = (tagId) => { - const { id } = store.viewingData - const communityId = store.curCommunity.id - const thread = toUpper(store.activeThread) - - sr71$.mutate(S.setTag, { thread, id, tagId, communityId }) -} - -export const onTagUnselect = (tagId) => { - const { id } = store.viewingData - const communityId = store.curCommunity.id - const thread = toUpper(store.activeThread) - - sr71$.mutate(S.unsetTag, { thread, id, tagId, communityId }) -} - -export const onCommentCreate = () => { - const { id } = store.viewingData - return sr71$.query(S.postComment, { id }) -} - -const loadPost = ({ id }) => { - const userHasLogin = store.isLogin - const variables = { id, userHasLogin } - markLoading() - sr71$.query(S.post, variables) -} - -const openAttachment = (att) => { - if (!att) return false - - const { type } = att - - if (type === TYPE.DRAWER.POST_VIEW) { - loadPost(att) - - store.mark({ type }) - store.setViewing({ post: att }) - } -} - -const markLoading = (maybe = true) => store.mark({ loading: maybe }) -// ############################### -// Data & Error handlers -// ############################### - -const DataSolver = [ - { - match: asyncRes('post'), - action: ({ post }) => { - store.setViewing({ post: merge(store.viewingData, post) }) - store.syncViewingItem(post) - markLoading(false) - }, - }, - { - match: asyncRes(EVENT.DRAWER.CLOSE), - action: () => { - sr71$.stop() - markLoading(false) - }, - }, - { - match: asyncRes('setTag'), - action: () => { - loadPost(store.viewingData) - closeDrawer() - store.setViewing({ post: {} }) - }, - }, - { - match: asyncRes('unsetTag'), - action: () => { - loadPost(store.viewingData) - closeDrawer() - store.setViewing({ post: {} }) - }, - }, -] -const ErrSolver = [ - { - match: asyncErr(ERR.GRAPHQL), - action: () => { - // - }, - }, - { - match: asyncErr(ERR.TIMEOUT), - action: ({ details }) => - errRescue({ type: ERR.TIMEOUT, details, path: 'PostViewer' }), - }, - { - match: asyncErr(ERR.NETWORK), - action: () => errRescue({ type: ERR.NETWORK, path: 'PostViewer' }), - }, -] - -// ############################### -// init & uninit -// ############################### -export const useInit = (_store, attachment) => { - useEffect(() => { - store = _store - // log('effect init') - sub$ = sr71$.data().subscribe($solver(DataSolver, ErrSolver)) - openAttachment(attachment) - - return () => { - // log('effect uninit') - sr71$.stop() - sub$.unsubscribe() - } - }, [_store, attachment]) -} diff --git a/src/containers/viewer/PostViewer/schema.ts b/src/containers/viewer/PostViewer/schema.ts deleted file mode 100755 index 41d90a955..000000000 --- a/src/containers/viewer/PostViewer/schema.ts +++ /dev/null @@ -1,59 +0,0 @@ -import gql from 'graphql-tag' -import { F, P } from '@/schemas' - -const post = gql` - query post($id: ID!, $userHasLogin: Boolean!) { - post(id: $id) { - ${F.post} - body - author { - ${F.author} - } - tags { - ${F.tag} - } - origialCommunity { - ${F.community} - } - commentsParticipators { - ${F.author} - } - commentsCount - linkAddr - insertedAt - favoritedCount - starredCount - viewerHasViewed @include(if: $userHasLogin) - viewerHasFavorited @include(if: $userHasLogin) - viewerHasStarred @include(if: $userHasLogin) - favoritedCategoryId @include(if: $userHasLogin) - } - } -` -const setTag = gql` - ${P.setTag} -` -const unsetTag = gql` - ${P.unsetTag} -` - -const postComment = gql` - query post($id: ID!) { - post(id: $id) { - id - commentsParticipators { - ${F.author} - } - commentsCount - } - } -` - -const schema = { - post, - setTag, - unsetTag, - postComment, -} - -export default schema diff --git a/src/containers/viewer/PostViewer/store.js b/src/containers/viewer/PostViewer/store.js deleted file mode 100755 index d330f8e9b..000000000 --- a/src/containers/viewer/PostViewer/store.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - * PostViewer store - * - */ - -import { types as T, getParent } from 'mobx-state-tree' - -import { markStates, buildLog, stripMobx } from '@/utils' - -/* eslint-disable-next-line */ -const log = buildLog('S:PostViewer') - -const PostViewer = T.model('PostViewer', { - loading: T.optional(T.boolean, false), -}) - .views((self) => ({ - get root() { - return getParent(self) - }, - get isLogin() { - return self.root.account.isLogin - }, - get accountInfo() { - return self.root.account.accountInfo - }, - get viewingData() { - return self.root.viewingData - }, - get curCommunity() { - return stripMobx(self.root.viewing.community) - }, - get activeThread() { - const { activeThread } = self.root.viewing - return activeThread - }, - })) - .actions((self) => ({ - setViewing(sobj) { - self.root.setViewing(sobj) - }, - syncViewingItem(item) { - self.root.viewing.syncViewingItem(item) - }, - mark(sobj) { - markStates(sobj, self) - }, - })) - -export default PostViewer diff --git a/src/containers/viewer/PostViewer/styles/index.ts b/src/containers/viewer/PostViewer/styles/index.ts deleted file mode 100755 index a42782500..000000000 --- a/src/containers/viewer/PostViewer/styles/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import styled from 'styled-components' - -import { theme, css } from '@/utils' - -export const BodyWrapper = styled.div` - ${css.flexColumn()}; - - padding: 20px; - background: ${theme('drawer.articleBg')}; - min-height: 400px; - margin-top: 5px; - margin-left: 4%; - margin-right: 4%; - border-radius: 3px; - box-shadow: 0 1px 4px rgba(0, 0, 0, 0.04); -` -export const CommentsWrapper = styled.div` - min-height: 400px; - margin-top: 32px; - margin-left: 4%; - margin-right: 4%; - margin-bottom: 10%; - border-radius: 5px; -` - -export const ArticleTitle = styled.div` - color: ${theme('drawer.title')}; - font-size: 1.2rem; - align-self: center; - padding-top: 10px; - padding-bottom: 5px; - padding-left: 20px; - padding-right: 20px; - - border-bottom: 1px solid; - border-bottom-color: ${theme('drawer.divider')}; -` -export const ArticleBody = styled.article` - padding: 20px; - font-size: 1.2em; - line-height: 2em; - flex-grow: 1; -` -export const Footer = styled.div` - ${css.flex('align-both')}; -` diff --git a/src/containers/viewer/PostViewer/tests/store.test.ts b/src/containers/viewer/PostViewer/tests/store.test.ts deleted file mode 100755 index 174cab913..000000000 --- a/src/containers/viewer/PostViewer/tests/store.test.ts +++ /dev/null @@ -1,10 +0,0 @@ -/* - * PostViewer store test - * - */ - -// import PostViewer from '../index' - -it('TODO: store test PostViewer', () => { - expect(1 + 1).toBe(2) -}) diff --git a/src/hooks/index.ts b/src/hooks/index.ts index abfa71294..0e613f54e 100755 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -7,7 +7,6 @@ export { default as useCustomScroll } from './useCustomScroll' export { default as useOutsideClick } from './useOutsideClick' export { default as useLangPress } from './useLangPress' export { default as useTrans } from './useTrans' -export { default as useDevice } from './useDevice' export { default as useNetwork } from 'react-use/lib/useNetwork' export { default as useCopyToClipboard } from 'react-use/lib/useCopyToClipboard' diff --git a/src/hooks/useDevice.ts b/src/hooks/useDevice.ts deleted file mode 100644 index 4bf26a388..000000000 --- a/src/hooks/useDevice.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { useEffect, useState } from 'react' -import { isMobile as detectMobile } from '@/utils' - -type TDevice = { - isMobile: boolean -} - -const useDevice = (): TDevice => { - const [isMobile, setIsMobile] = useState(false) - - useEffect(() => { - setIsMobile(detectMobile) - }, [isMobile]) // Empty array ensures that effect is only run on mount and unmount - - return { isMobile } -} - -export default useDevice diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index 095d27406..83b17dffc 100755 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -1,6 +1,4 @@ import Head from 'next/head' -import { DefaultSeo } from 'next-seo' -import * as Sentry from '@sentry/node' /** * import default seo configuration @@ -8,16 +6,10 @@ import * as Sentry from '@sentry/node' * that will apply to every page. Full info on how the default works * can be found here: https://github.com/garmeeh/next-seo#default-seo-configuration */ -import { SEO } from '@/config' -import { appWithTranslation } from '@/i18n' +// import { appWithTranslation } from '@/i18n' import CrashErrorHint from '@/components/CrashErrorHint' -Sentry.init({ - enabled: process.env.NODE_ENV === 'production', - dsn: process.env.NEXT_PUBLIC_SENTRY_TOKEN, -}) - const App = ({ Component, pageProps, err }) => { return ( <> @@ -33,7 +25,6 @@ const App = ({ Component, pageProps, err }) => { ) : ( /* render normal next.js app */ <> - )} @@ -41,4 +32,5 @@ const App = ({ Component, pageProps, err }) => { ) } -export default appWithTranslation(App) +// export default appWithTranslation(App) +export default App diff --git a/src/pages/_error.js b/src/pages/_error.js index ab45da738..b7030fb7c 100755 --- a/src/pages/_error.js +++ b/src/pages/_error.js @@ -1,7 +1,6 @@ import React from 'react' import NextErrorComponent from 'next/error' import { Provider } from 'mobx-react' -import * as Sentry from '@sentry/node' import AnalysisService from '@/services/Analysis' import ThemePalette from '@/containers/layout/ThemePalette' @@ -20,7 +19,6 @@ const Error = (props) => { // getInitialProps is not called in case of // https://github.com/vercel/next.js/issues/8592. As a workaround, we pass // err via _app.js so it can be captured - Sentry.captureException(err) } return ( @@ -69,16 +67,12 @@ Error.getInitialProps = async ({ res, err, asPath }) => { return { statusCode: 404, ...i18nConfig } } if (err) { - Sentry.captureException(err) return { ...errorInitialProps, ...i18nConfig } } // If this point is reached, getInitialProps was called without any // information about what the error might be. This is unexpected and may // indicate a bug introduced in Next.js, so record it in Sentry - Sentry.captureException( - new Error(`_error.js getInitialProps missing data at path: ${asPath}`), - ) return { ...errorInitialProps, ...i18nConfig } } diff --git a/src/pages/community.tsx b/src/pages/community.tsx index 1ffdcd37a..add08482c 100755 --- a/src/pages/community.tsx +++ b/src/pages/community.tsx @@ -147,7 +147,7 @@ export const getServerSideProps: GetServerSideProps = async (props) => { return { props: { errorCode: null, ...initProps } } } -const CommunityPage = (props) => { +const CommunityPage = (props = {}) => { const store = useStore(props) const { errorCode, viewing } = store diff --git a/src/spec/utils.ts b/src/spec/utils.ts index 061ae5a13..b38323976 100644 --- a/src/spec/utils.ts +++ b/src/spec/utils.ts @@ -17,10 +17,10 @@ export type TActive = { } export type TSpace = { - top?: number - bottom?: number - left?: number - right?: number + top?: number | string + bottom?: number | string + left?: number | string + right?: number | string } // google analytis format diff --git a/src/stores/RootStore/index.ts b/src/stores/RootStore/index.ts index 34df920d1..4ecff54a8 100755 --- a/src/stores/RootStore/index.ts +++ b/src/stores/RootStore/index.ts @@ -48,8 +48,6 @@ import { // footer FooterStore, // viewers - PostViewerStore, - JobViewerStore, ArticleViewerHeader, ArticleBodyHeaderStore, RepoViewerStore, @@ -61,18 +59,15 @@ import { DrawerStore, SidebarStore, PostEditorStore, - JobEditorStore, RepoEditorStore, AccountEditorStore, MailBoxStore, - LabelerStore, DocUploaderStore, AvatarAdderStore, TagsBarStore, UserListerStore, GirlVerifierStore, CashierStore, - ArticleAuthorCardStore, CommunitySetterStore, // user page UserPublishedStore, @@ -135,12 +130,10 @@ const rootStore = T.model({ sidebar: T.optional(SidebarStore, { menuItems: [] }), drawer: T.optional(DrawerStore, { visible: false }), doraemon: T.optional(DoraemonStore, {}), - jobEditor: T.optional(JobEditorStore, {}), postEditor: T.optional(PostEditorStore, {}), repoEditor: T.optional(RepoEditorStore, {}), accountEditor: T.optional(AccountEditorStore, {}), mailBox: T.optional(MailBoxStore, {}), - labeler: T.optional(LabelerStore, {}), docUploader: T.optional(DocUploaderStore, {}), avatarAdder: T.optional(AvatarAdderStore, {}), // toolbox end @@ -176,14 +169,11 @@ const rootStore = T.model({ userLister: T.optional(UserListerStore, {}), girlVerifier: T.optional(GirlVerifierStore, {}), cashier: T.optional(CashierStore, {}), - articleAuthorCard: T.optional(ArticleAuthorCardStore, {}), communitySetter: T.optional(CommunitySetterStore, {}), articleViewerHeader: T.optional(ArticleViewerHeader, {}), articleBodyHeader: T.optional(ArticleBodyHeaderStore, {}), // viewers (for drawer usage) - postViewer: T.optional(PostViewerStore, {}), - jobViewer: T.optional(JobViewerStore, {}), repoViewer: T.optional(RepoViewerStore, {}), mailsViewer: T.optional(MailsViewerStore, {}), diff --git a/src/stores/index.ts b/src/stores/index.ts index 99ac541f7..5c1d94803 100755 --- a/src/stores/index.ts +++ b/src/stores/index.ts @@ -30,7 +30,6 @@ export { default as UserListerStore } from '@/containers/user/UserLister/store' export { default as GirlVerifierStore } from '@/containers/tool/GirlVerifier/store' export { default as CashierStore } from '@/containers/tool/Cashier/store' -export { default as ArticleAuthorCardStore } from '@/containers/unit/ArticleAuthorCard/store' // // pages banners store @@ -56,17 +55,13 @@ export { default as TagsBarStore } from '@/containers/unit/TagsBar/store' // toolbox export { default as DocUploaderStore } from '@/containers/tool/DocUploader/store' -export { default as JobEditorStore } from '@/containers/editor/JobEditor/store' export { default as PostEditorStore } from '@/containers/editor/PostEditor/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' -export { default as LabelerStore } from '@/containers/unit/Labeler/store' export { default as CommunitySetterStore } from '@/containers/tool/CommunitySetter/store' // viewers store -export { default as PostViewerStore } from '@/containers/viewer/PostViewer/store' -export { default as JobViewerStore } from '@/containers/viewer/JobViewer/store' export { default as RepoViewerStore } from '@/containers/viewer/RepoViewer/store' export { default as MailsViewerStore } from '@/containers/viewer/MailsViewer/store' diff --git a/tsconfig.json b/tsconfig.json index 4a2a5ce54..945b87b2c 100755 --- a/tsconfig.json +++ b/tsconfig.json @@ -31,6 +31,7 @@ "@/spec": ["src/spec"], "@/Img": ["src/components/Img"], "@/SvgIcons/*": ["src/components/SvgIcons/*"], + "@/icons/*": ["src/components/Icons/*"], "@/i18n": ["i18n"] }, "plugins": [ diff --git a/utils/constant/index.ts b/utils/constant/index.ts index 44d0ace1c..5eefa588e 100755 --- a/utils/constant/index.ts +++ b/utils/constant/index.ts @@ -24,6 +24,7 @@ export { default as URL_QUERY } from './url_query' export { PAYMENT_USAGE, PAYMENT_METHOD } from './payment' export { REPORT, REPORT_TYPE } from './report' +export { default as SVG } from './svg' /* some svg icon are sensitive to fill color */ /* some community svg need fill color, like city etc.. */ diff --git a/utils/constant/svg.ts b/utils/constant/svg.ts new file mode 100755 index 000000000..84804bb2b --- /dev/null +++ b/utils/constant/svg.ts @@ -0,0 +1,23 @@ +const SVG = { + // article + UPVOTE: 'upvote', + COLLECTION: 'collection', + SHARE: 'share', + VIEW: 'view', + COMMENT: 'comment', + PIN: 'pin', + + // comment + EMOTION: 'emotion', + LOCK: 'lock', + TIMELINE_MODE: 'timeline_mode', + REPLY_MODE: 'reply_mode', + EXPAND: 'expand', + FOLD: 'fold', + + // utils + MORE: 'more', + MOREL: 'more-l', +} + +export default SVG diff --git a/utils/device.ts b/utils/device.ts deleted file mode 100644 index 29c6fbac0..000000000 --- a/utils/device.ts +++ /dev/null @@ -1,4 +0,0 @@ -// see details in https://github.com/duskload/mobile-device-detect -export { isMobileOnly as isMobile } from 'mobile-device-detect' - -export const holder = 1 diff --git a/utils/index.ts b/utils/index.ts index ba4bb4e29..6da69408a 100755 --- a/utils/index.ts +++ b/utils/index.ts @@ -146,6 +146,4 @@ export { default as BStore } from './bstore' export { Trans } from './i18n' export { default as GA } from './analytics' -export { isMobile } from './device' - export { mockImage, mockImages, mockNaviCatalogMenu, mockWorks } from './mock' diff --git a/yarn.lock b/yarn.lock index 439526078..ccfe3d687 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8004,10 +8004,6 @@ mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5: dependencies: minimist "^1.2.5" -mobile-device-detect@^0.4.3: - version "0.4.3" - resolved "https://registry.npm.taobao.org/mobile-device-detect/download/mobile-device-detect-0.4.3.tgz#05d73b4bde7ccb5beda1c4bd0ea0986ce30b1f3f" - mobx-react-lite@3.2.0, mobx-react-lite@^3.2.0: version "3.2.0" resolved "https://registry.npm.taobao.org/mobx-react-lite/download/mobx-react-lite-3.2.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmobx-react-lite%2Fdownload%2Fmobx-react-lite-3.2.0.tgz#331d7365a6b053378dfe9c087315b4e41c5df69f" @@ -8182,10 +8178,6 @@ next-offline@4.0.6: webpack "^4.19.1" workbox-webpack-plugin "^4.3.1" -next-seo@4.4.0: - version "4.4.0" - resolved "https://registry.nlark.com/next-seo/download/next-seo-4.4.0.tgz#490f1064e89af55043559459c9cd04220e4d651d" - next-tick@1, next-tick@^1.1.0: version "1.1.0" resolved "https://registry.npm.taobao.org/next-tick/download/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" @@ -9374,6 +9366,12 @@ react-copy-to-clipboard@^5.0.3: copy-to-clipboard "^3" prop-types "^15.5.8" +react-device-detect@^1.17.0: + version "1.17.0" + resolved "https://registry.npm.taobao.org/react-device-detect/download/react-device-detect-1.17.0.tgz#a00b4fd6880cebfab3fd8a42a79dc0290cdddca9" + dependencies: + ua-parser-js "^0.7.24" + react-dom@17.0.2: version "17.0.2" resolved "https://registry.nlark.com/react-dom/download/react-dom-17.0.2.tgz#ecffb6845e3ad8dbfcdc498f0d0a939736502c23" @@ -11258,7 +11256,7 @@ typescript@^4.2.3: version "4.3.5" resolved "https://registry.nlark.com/typescript/download/typescript-4.3.5.tgz?cache=0&sync_timestamp=1627111237668&other_urls=https%3A%2F%2Fregistry.nlark.com%2Ftypescript%2Fdownload%2Ftypescript-4.3.5.tgz#4d1c37cc16e893973c45a06886b7113234f119f4" -ua-parser-js@^0.7.18: +ua-parser-js@^0.7.18, ua-parser-js@^0.7.24: version "0.7.28" resolved "https://registry.nlark.com/ua-parser-js/download/ua-parser-js-0.7.28.tgz#8ba04e653f35ce210239c64661685bf9121dec31"