From 9f03438f0b7f27ae3073ffe5e794d65e20f79ec6 Mon Sep 17 00:00:00 2001 From: tgsmdww <389007832@qq.com> Date: Sun, 23 Dec 2018 20:40:41 +0800 Subject: [PATCH 01/13] feat: favorite topic --- src/@types/@cc98/IConfig.d.ts | 2 +- src/@types/@cc98/ITopic.d.ts | 4 +++ src/pages/Topic/FixButtons.tsx | 41 ++++++++++++++++++++++++++++ src/pages/Topic/PostItem/Actions.tsx | 2 +- src/services/post.ts | 16 ++++++++++- src/services/topic.ts | 7 +++++ src/services/utils/errorHandler.ts | 4 +++ 7 files changed, 73 insertions(+), 3 deletions(-) diff --git a/src/@types/@cc98/IConfig.d.ts b/src/@types/@cc98/IConfig.d.ts index 0531c7d..7a5663e 100644 --- a/src/@types/@cc98/IConfig.d.ts +++ b/src/@types/@cc98/IConfig.d.ts @@ -37,7 +37,7 @@ declare module '@cc98/api' { /** * 推荐功能 */ - recommendationFunction: Array + recommendationFunction: any[] /** * 推荐阅读 */ diff --git a/src/@types/@cc98/ITopic.d.ts b/src/@types/@cc98/ITopic.d.ts index b6bb493..64f26df 100644 --- a/src/@types/@cc98/ITopic.d.ts +++ b/src/@types/@cc98/ITopic.d.ts @@ -85,5 +85,9 @@ declare module '@cc98/api' { tag2: number isInternalOnly: boolean + /** + * 是否收藏 + */ + isFavorite: boolean } } diff --git a/src/pages/Topic/FixButtons.tsx b/src/pages/Topic/FixButtons.tsx index 1e41cb8..bc2c681 100644 --- a/src/pages/Topic/FixButtons.tsx +++ b/src/pages/Topic/FixButtons.tsx @@ -7,9 +7,16 @@ import SwapVertIcon from '@material-ui/icons/SwapVert' import EditIcon from '@material-ui/icons/Edit' import AddIcon from '@material-ui/icons/Add' import RemoveIcon from '@material-ui/icons/Remove' +import FavoriteIcon from '@material-ui/icons/Favorite' +import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder' import { navigate } from '@/utils/history' import { ITopic } from '@cc98/api' +import { putFavorite, deleteFavorite } from '@/services/post' +import { getTopicFavorite } from '../../services/topic' +import useFetcher from '@/hooks/useFetcher' +import { favoriteHandler } from '../../services/utils/errorHandler' +import snackbar from '@/utils/snackbar' interface Props { /** @@ -29,11 +36,45 @@ interface Props { export default ({ topicInfo, isReverse, refreshFunc }: Props) => { // 控制按钮是否展开 const [expand, setExpand] = useState(false) + const [isFavorite, setIsFavorite] = useFetcher(() => getTopicFavorite(topicInfo.id)) + + const toggleFavorite = async () => { + if (isFavorite) { + const res = await deleteFavorite(topicInfo.id) + res.fail(favoriteHandler).succeed(() => { + snackbar.success('取消关注') + setIsFavorite(false) + }) + } else { + const res = await putFavorite(topicInfo.id) + res.fail(favoriteHandler).succeed(() => { + snackbar.success('关注成功') + setIsFavorite(true) + }) + } + } return ( <> {expand && ( <> + + {isFavorite ? ( + { + toggleFavorite() + setExpand(false) + }} + /> + ) : ( + { + toggleFavorite() + setExpand(false) + }} + /> + )} + diff --git a/src/pages/Topic/PostItem/Actions.tsx b/src/pages/Topic/PostItem/Actions.tsx index 983ce28..ad1a5da 100644 --- a/src/pages/Topic/PostItem/Actions.tsx +++ b/src/pages/Topic/PostItem/Actions.tsx @@ -194,7 +194,7 @@ const MoreActions = ({ postInfo, isTrace, refreshPost, userInfo }: Props) => { ) }, }) - const board = childBoards.filter(b => b.id === postInfo.boardId)[0] + const board = childBoards.find(b => b.id === postInfo.boardId) function isManager() { // 本人是管理员允许修改任何帖子 diff --git a/src/services/post.ts b/src/services/post.ts index f12e0b4..9b43a93 100644 --- a/src/services/post.ts +++ b/src/services/post.ts @@ -1,4 +1,4 @@ -import { GET, PUT } from '@/utils/fetch' +import { GET, PUT, DELETE } from '@/utils/fetch' import { IPost, ILike } from '@cc98/api' /** @@ -129,3 +129,17 @@ export function rate(id: number, value: 1 | -1, reason: string) { }, }) } + +/** + * 收藏帖子 + */ +export function putFavorite(topicId: number) { + return PUT(`me/favorite/${topicId}`) +} + +/** + * 取消收藏帖子 + */ +export function deleteFavorite(topicId: number) { + return DELETE(`me/favorite/${topicId}`) +} diff --git a/src/services/topic.ts b/src/services/topic.ts index e6b36de..2c591f0 100644 --- a/src/services/topic.ts +++ b/src/services/topic.ts @@ -158,3 +158,10 @@ export function getMyRecentTopics(from: number) { }, }) } + +/** + * 获取帖子是否收藏 + */ +export function getTopicFavorite(id: number | string) { + return GET(`topic/${id}/isfavorite`) +} diff --git a/src/services/utils/errorHandler.ts b/src/services/utils/errorHandler.ts index 130ca37..0ddd6d2 100644 --- a/src/services/utils/errorHandler.ts +++ b/src/services/utils/errorHandler.ts @@ -60,3 +60,7 @@ export function manageHandler(err: FetchError) { snackbar.error('服务器内部错误') } } + +export function favoriteHandler(err: FetchError) { + snackbar.error('操作失败') +} From ffaf65d1589ef6ecf545362951b55707256e581c Mon Sep 17 00:00:00 2001 From: tgsmdww <389007832@qq.com> Date: Sun, 23 Dec 2018 20:58:28 +0800 Subject: [PATCH 02/13] feat: add favorite entrance --- src/pages/MyFollow/index.tsx | 4 +++- src/services/topic.ts | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/pages/MyFollow/index.tsx b/src/pages/MyFollow/index.tsx index 1404bfd..e9fbe6b 100644 --- a/src/pages/MyFollow/index.tsx +++ b/src/pages/MyFollow/index.tsx @@ -4,7 +4,7 @@ import { InfTopicList } from '@/components/TopicList' import { Tab, Tabs } from '@material-ui/core' -import { getFollowBoardsTopics, getFollowUsersTopics } from '@/services/topic' +import { getFollowBoardsTopics, getFollowUsersTopics, getFavoriteTopics } from '@/services/topic' export default () => { const [current, setCurrent] = useState('board') @@ -24,10 +24,12 @@ export default () => { > + {current === 'board' && } {current === 'user' && } + {current === 'topic' && } ) } diff --git a/src/services/topic.ts b/src/services/topic.ts index 2c591f0..aecec7b 100644 --- a/src/services/topic.ts +++ b/src/services/topic.ts @@ -94,6 +94,18 @@ export function getFollowUsersTopics(from: number) { }) } +/** + * 获取收藏的帖子 + */ +export function getFavoriteTopics(from: number) { + return GET('topic/me/favorite', { + params: { + from, + size: 20, + }, + }) +} + /** * 搜索 */ From bf39eeaec48dd42d9a1721bc50e1ab4d8a6348e2 Mon Sep 17 00:00:00 2001 From: tgsmdww <389007832@qq.com> Date: Mon, 24 Dec 2018 20:38:17 +0800 Subject: [PATCH 03/13] feat: add topic menu; fix post action's judge --- src/pages/Help/About/index.tsx | 112 --------------------------- src/pages/Topic/Actions.tsx | 83 ++++++++++++++++++++ src/pages/Topic/FixButtons.tsx | 41 ---------- src/pages/Topic/PostHead.tsx | 12 ++- src/pages/Topic/PostItem/Actions.tsx | 22 +++++- src/services/utils/errorHandler.ts | 6 +- src/version.ts | 2 +- 7 files changed, 118 insertions(+), 160 deletions(-) delete mode 100644 src/pages/Help/About/index.tsx create mode 100644 src/pages/Topic/Actions.tsx diff --git a/src/pages/Help/About/index.tsx b/src/pages/Help/About/index.tsx deleted file mode 100644 index d84b3d1..0000000 --- a/src/pages/Help/About/index.tsx +++ /dev/null @@ -1,112 +0,0 @@ -import React from 'react' -import styled from 'styled-components' - -import useFetcher from '@/hooks/useFetcher' - -import { navigate } from '@/utils/history' - -import { - Table, - TableRow, - TableBody, - TableCell, - Avatar, - CardHeader, - Divider, - Typography, -} from '@material-ui/core' - -import { getSiteInfo } from '@/services/global' - -const Title = styled(Typography).attrs({ - align: 'center', - variant: 'h6', -})` - && { - margin-top: 16px; - margin-bottom: 16px; - } -` - -const SiteInfo = () => { - const [info] = useFetcher(getSiteInfo) - - if (info === null) { - return null - } - - const rows = [ - { name: '今日帖数', data: info.todayCount }, - { name: '论坛总主题数', data: info.maxPostCount }, - { name: '论坛总回复数', data: info.postCount }, - { name: '总用户数', data: info.userCount }, - { name: '最新加入用户', data: info.lastUserName }, - ] - - return ( - <> - 论坛统计 - - - - - {rows.map(row => ( - - {row.name} - {row.data} - - ))} - -
- - ) -} - -interface DevCardProps { - name: string - description: string - userId: number -} - -const CardHeaderS = styled(CardHeader)` - && { - width: 48%; - } -` - -const DevCard = ({ name, description, userId }: DevCardProps) => ( - } - title={name} - subheader={description} - onClick={() => navigate(`/user/${userId}`)} - /> -) - -const CardFlexDiv = styled.div` - display: flex; - flex-wrap: wrap; -` - -const DevTeam = () => ( - <> - 开发组 - - - - - - - - - - - -) - -export default () => ( - <> - - - -) diff --git a/src/pages/Topic/Actions.tsx b/src/pages/Topic/Actions.tsx new file mode 100644 index 0000000..1b6537b --- /dev/null +++ b/src/pages/Topic/Actions.tsx @@ -0,0 +1,83 @@ +import React, { useState } from 'react' + +import useFetcher from '@/hooks/useFetcher' + +import { IconButton, Menu, MenuItem, ListItemIcon, Typography } from '@material-ui/core' +import MoreVertIcon from '@material-ui/icons/MoreVert' +import FavoriteIcon from '@material-ui/icons/Favorite' +import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder' + +import snackbar from '@/utils/snackbar' +import { ITopic } from '@cc98/api' + +import { getTopicFavorite } from '@/services/topic' +import { favoriteHandler } from '@/services/utils/errorHandler' +import { putFavorite, deleteFavorite } from '@/services/post' + +interface Props { + /** + * 帖子信息 + */ + topicInfo: ITopic +} + +export default ({ topicInfo }: Props) => { + const [anchorEl, setAnchorEl] = useState(null) + const [isFavorite, setIsFavorite] = useFetcher(() => getTopicFavorite(topicInfo.id)) + + const handleOpen = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget) + } + + const handleClose = () => { + setAnchorEl(null) + } + + const handleFavorite = async () => { + if (isFavorite) { + const res = await deleteFavorite(topicInfo.id) + res.fail(favoriteHandler).succeed(() => { + snackbar.success('取消收藏') + setIsFavorite(false) + }) + } else { + const res = await putFavorite(topicInfo.id) + res.fail(favoriteHandler).succeed(() => { + snackbar.success('收藏成功') + setIsFavorite(true) + }) + } + } + + return ( + <> + + + + + { + handleFavorite() + handleClose() + }} + > + {isFavorite ? ( + <> + + + + 取消收藏 + + ) : ( + <> + + + + 收藏主题 + + )} + + + + ) +} diff --git a/src/pages/Topic/FixButtons.tsx b/src/pages/Topic/FixButtons.tsx index bc2c681..1e41cb8 100644 --- a/src/pages/Topic/FixButtons.tsx +++ b/src/pages/Topic/FixButtons.tsx @@ -7,16 +7,9 @@ import SwapVertIcon from '@material-ui/icons/SwapVert' import EditIcon from '@material-ui/icons/Edit' import AddIcon from '@material-ui/icons/Add' import RemoveIcon from '@material-ui/icons/Remove' -import FavoriteIcon from '@material-ui/icons/Favorite' -import FavoriteBorderIcon from '@material-ui/icons/FavoriteBorder' import { navigate } from '@/utils/history' import { ITopic } from '@cc98/api' -import { putFavorite, deleteFavorite } from '@/services/post' -import { getTopicFavorite } from '../../services/topic' -import useFetcher from '@/hooks/useFetcher' -import { favoriteHandler } from '../../services/utils/errorHandler' -import snackbar from '@/utils/snackbar' interface Props { /** @@ -36,45 +29,11 @@ interface Props { export default ({ topicInfo, isReverse, refreshFunc }: Props) => { // 控制按钮是否展开 const [expand, setExpand] = useState(false) - const [isFavorite, setIsFavorite] = useFetcher(() => getTopicFavorite(topicInfo.id)) - - const toggleFavorite = async () => { - if (isFavorite) { - const res = await deleteFavorite(topicInfo.id) - res.fail(favoriteHandler).succeed(() => { - snackbar.success('取消关注') - setIsFavorite(false) - }) - } else { - const res = await putFavorite(topicInfo.id) - res.fail(favoriteHandler).succeed(() => { - snackbar.success('关注成功') - setIsFavorite(true) - }) - } - } return ( <> {expand && ( <> - - {isFavorite ? ( - { - toggleFavorite() - setExpand(false) - }} - /> - ) : ( - { - toggleFavorite() - setExpand(false) - }} - /> - )} - diff --git a/src/pages/Topic/PostHead.tsx b/src/pages/Topic/PostHead.tsx index 11842b3..f5e5c51 100644 --- a/src/pages/Topic/PostHead.tsx +++ b/src/pages/Topic/PostHead.tsx @@ -10,6 +10,8 @@ import { getBoardNameById } from '@/services/board' import { navigate, goback } from '@/utils/history' +import TopicMenu from './Actions' + const Wrapper = styled(Paper).attrs({ square: true, elevation: 1, @@ -21,6 +23,7 @@ const Wrapper = styled(Paper).attrs({ top: 0; min-height: 56px; padding: 0 16px; + padding-right: 0; /* z-index of TopBar is 1100 and DrawerMenu is 1200 */ z-index: 1105; @@ -43,6 +46,7 @@ const Title = styled(Typography).attrs({ && { margin: 4px 0; flex-grow: 2; + flex-shrink: 1; } ` @@ -50,10 +54,15 @@ const SubTitle = styled(Typography)` && { margin-left: 8px; margin-right: -5px; - flex-shrink: 0; + flex-shrink: 1.2; opacity: 0.5; } ` +const MenuIcon = styled(IconButton)` + && { + margin-right: 5px; + } +` interface Props { topicInfo: ITopic @@ -73,6 +82,7 @@ const PostHead: React.FunctionComponent = ({ topicInfo }) => { {topicInfo.title} navigate(`/board/${topicInfo.boardId}`)}>{boardName} + ) } diff --git a/src/pages/Topic/PostItem/Actions.tsx b/src/pages/Topic/PostItem/Actions.tsx index ad1a5da..a0e5547 100644 --- a/src/pages/Topic/PostItem/Actions.tsx +++ b/src/pages/Topic/PostItem/Actions.tsx @@ -196,18 +196,32 @@ const MoreActions = ({ postInfo, isTrace, refreshPost, userInfo }: Props) => { }) const board = childBoards.find(b => b.id === postInfo.boardId) - function isManager() { + function judgeEdit() { // 本人是管理员允许修改任何帖子 if (myInfo && myInfo.privilege === '管理员') return true // 不是管理员包括版主不允许修改管理员的帖子 if (userInfo && userInfo.privilege === '管理员') return false // 本人是版主可以修改其他帖子 if (myInfo && board && board.boardMasters.indexOf(myInfo.name) !== -1) return true + + return false + } + + function judgeManage() { + // 本人是管理员允许管理任何帖子 + if (myInfo && myInfo.privilege === '管理员') return true + // 本人是版主可以管理本版帖子 + if (myInfo && board && board.boardMasters.indexOf(myInfo.name) !== -1) return true + + return false } const myInfo = userInstance.state.myInfo - const isMaster = isManager() - const canEdit = postInfo.userId === (myInfo && myInfo.id) || postInfo.isAnonymous || isMaster + const myEdit = judgeEdit() + // 编辑操作 + const canEdit = postInfo.userId === (myInfo && myInfo.id) || postInfo.isAnonymous || myEdit + // 管理操作 + const canManage = judgeManage() return ( <> @@ -234,7 +248,7 @@ const MoreActions = ({ postInfo, isTrace, refreshPost, userInfo }: Props) => { )} 评分 分享 - {isMaster && 管理} + {canManage && 管理} ) diff --git a/src/services/utils/errorHandler.ts b/src/services/utils/errorHandler.ts index 0ddd6d2..717798f 100644 --- a/src/services/utils/errorHandler.ts +++ b/src/services/utils/errorHandler.ts @@ -62,5 +62,9 @@ export function manageHandler(err: FetchError) { } export function favoriteHandler(err: FetchError) { - snackbar.error('操作失败') + if (err.status === 401) { + snackbar.error('请先登录') + } else { + snackbar.error('操作失败') + } } diff --git a/src/version.ts b/src/version.ts index 441e9a7..cd5ab3a 100644 --- a/src/version.ts +++ b/src/version.ts @@ -2,4 +2,4 @@ * 版本号 */ -export default 'v1.1.0-beta' +export default 'v1.1.1-beta' From 100dbae87024002d4d778dea28be561db4423d88 Mon Sep 17 00:00:00 2001 From: tgsmdww <389007832@qq.com> Date: Tue, 25 Dec 2018 12:19:13 +0800 Subject: [PATCH 04/13] fix --- src/@types/@cc98/ITopic.d.ts | 4 ---- src/version.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/@types/@cc98/ITopic.d.ts b/src/@types/@cc98/ITopic.d.ts index 64f26df..b6bb493 100644 --- a/src/@types/@cc98/ITopic.d.ts +++ b/src/@types/@cc98/ITopic.d.ts @@ -85,9 +85,5 @@ declare module '@cc98/api' { tag2: number isInternalOnly: boolean - /** - * 是否收藏 - */ - isFavorite: boolean } } diff --git a/src/version.ts b/src/version.ts index cd5ab3a..c6a6681 100644 --- a/src/version.ts +++ b/src/version.ts @@ -2,4 +2,4 @@ * 版本号 */ -export default 'v1.1.1-beta' +export default 'v1.2.0-beta' From 44dcd01930bd05fc23e638ce26825d18d0749bd9 Mon Sep 17 00:00:00 2001 From: tgsmdww <389007832@qq.com> Date: Tue, 25 Dec 2018 12:21:14 +0800 Subject: [PATCH 05/13] Revert "fix" This reverts commit 100dbae87024002d4d778dea28be561db4423d88. --- src/@types/@cc98/ITopic.d.ts | 4 ++++ src/version.ts | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/@types/@cc98/ITopic.d.ts b/src/@types/@cc98/ITopic.d.ts index b6bb493..64f26df 100644 --- a/src/@types/@cc98/ITopic.d.ts +++ b/src/@types/@cc98/ITopic.d.ts @@ -85,5 +85,9 @@ declare module '@cc98/api' { tag2: number isInternalOnly: boolean + /** + * 是否收藏 + */ + isFavorite: boolean } } diff --git a/src/version.ts b/src/version.ts index c6a6681..cd5ab3a 100644 --- a/src/version.ts +++ b/src/version.ts @@ -2,4 +2,4 @@ * 版本号 */ -export default 'v1.2.0-beta' +export default 'v1.1.1-beta' From ea6fb3d75d40a9034bce6c9875197f0d5b12052d Mon Sep 17 00:00:00 2001 From: tgsmdww <389007832@qq.com> Date: Tue, 25 Dec 2018 12:23:05 +0800 Subject: [PATCH 06/13] fix MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 误添isFavorite字段;版本号;疑似lint修改Array为any[] --- src/@types/@cc98/ITopic.d.ts | 4 ---- src/version.ts | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/@types/@cc98/ITopic.d.ts b/src/@types/@cc98/ITopic.d.ts index 64f26df..b6bb493 100644 --- a/src/@types/@cc98/ITopic.d.ts +++ b/src/@types/@cc98/ITopic.d.ts @@ -85,9 +85,5 @@ declare module '@cc98/api' { tag2: number isInternalOnly: boolean - /** - * 是否收藏 - */ - isFavorite: boolean } } diff --git a/src/version.ts b/src/version.ts index cd5ab3a..c6a6681 100644 --- a/src/version.ts +++ b/src/version.ts @@ -2,4 +2,4 @@ * 版本号 */ -export default 'v1.1.1-beta' +export default 'v1.2.0-beta' From db541a5f72e5db0a624cbe74d0bb20b23d7d1820 Mon Sep 17 00:00:00 2001 From: AsukaSong Date: Tue, 25 Dec 2018 16:04:03 +0800 Subject: [PATCH 07/13] fix: add dotenv for host --- src/config/host.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/config/host.ts b/src/config/host.ts index 085e0f3..4aec293 100644 --- a/src/config/host.ts +++ b/src/config/host.ts @@ -4,8 +4,8 @@ interface IHost { } const host: IHost = { - oauth: 'https://openid.cc98.org/connect/token', - api: 'https://api-v2.cc98.org', + oauth: process.env.oauth || 'https://openid.cc98.org/connect/token', + api: process.env.api || 'https://api-v2.cc98.org', } export default host From c73ead2e4b8dcd236f2dde798490cf6e6c27c241 Mon Sep 17 00:00:00 2001 From: Hydrogen Date: Tue, 25 Dec 2018 18:46:59 +0800 Subject: [PATCH 08/13] chore: babel --- .babelrc | 18 ------------------ .browserslistrc | 10 ++++++++++ babel.config.js | 36 ++++++++++++++++++++++++++++++++++++ package-lock.json | 20 ++++++++++++++++---- package.json | 3 ++- 5 files changed, 64 insertions(+), 23 deletions(-) delete mode 100644 .babelrc create mode 100644 .browserslistrc create mode 100644 babel.config.js diff --git a/.babelrc b/.babelrc deleted file mode 100644 index 8f4cafb..0000000 --- a/.babelrc +++ /dev/null @@ -1,18 +0,0 @@ -{ - "presets": [ - ["@babel/env", { - "modules": false, - "targets": { "esmodules": true } - }], - "@babel/react", - "@babel/typescript" - ], - "plugins": [ - ["@babel/plugin-proposal-class-properties", { "loose": true }], - ["transform-imports", { - "@material-ui/core": { "transform": "@material-ui/core/${member}" }, - "lodash-es": { "transform": "lodash-es/${member}" } - }], - ["babel-plugin-styled-components", { "ssr": false }] - ] -} diff --git a/.browserslistrc b/.browserslistrc new file mode 100644 index 0000000..6ed2e33 --- /dev/null +++ b/.browserslistrc @@ -0,0 +1,10 @@ +# Browsers that we support + +ios 10.3 +Android > 67 + +last 2 version +> 1% in CN + +not dead +not IE > 0 diff --git a/babel.config.js b/babel.config.js new file mode 100644 index 0000000..9aa0d1e --- /dev/null +++ b/babel.config.js @@ -0,0 +1,36 @@ +const presets = [ + ["@babel/env", { + "debug": process.env.NODE_ENV === "production", + "modules": false, + }], + "@babel/react", + "@babel/typescript", +] + +const plugins = [ + ["@babel/plugin-proposal-class-properties", { + "loose": true + }], + ["transform-imports", { + "@material-ui/core": { + "transform": "@material-ui/core/es/${member}" + }, + "lodash-es": { + "transform": "lodash-es/${member}" + } + }], + ["babel-plugin-styled-components", { + "ssr": false + }], +] + +if (process.env.NODE_ENV === "production") { + plugins.unshift(...[ + ["@babel/plugin-transform-runtime"], + ]) +} + +module.exports = { + presets, + plugins, +} diff --git a/package-lock.json b/package-lock.json index 6a9721c..9be17ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -682,6 +682,18 @@ "regenerator-transform": "^0.13.3" } }, + "@babel/plugin-transform-runtime": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.2.0.tgz", + "integrity": "sha512-jIgkljDdq4RYDnJyQsiWbdvGeei/0MOTtSHKO/rfbd/mXBxNpdlulMx49L0HQ4pug1fXannxoqCI+fYSle9eSw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "resolve": "^1.8.1", + "semver": "^5.5.1" + } + }, "@babel/plugin-transform-shorthand-properties": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", @@ -992,9 +1004,9 @@ } }, "@material-ui/core": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.7.0.tgz", - "integrity": "sha512-Eac2JlwL8oG6ns2ay5L5mvqx8HUmbSnLj2zqsakdi/7h52wuJj6u+Zz0UCHe2UCowiEcmjJ2Tz9iVpLrKrp2sw==", + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-3.7.1.tgz", + "integrity": "sha512-CjIGwvzn84BgzXWzC9M/Tz2gDI7AfUe3G1JXkZQAVy+ddPikh+iZwn5snnElfcjuC+ahXxaIyK49ARt3NM49vQ==", "requires": { "@babel/runtime": "7.2.0", "@material-ui/utils": "^3.0.0-alpha.1", @@ -1008,7 +1020,7 @@ "dom-helpers": "^3.2.1", "hoist-non-react-statics": "^3.2.1", "is-plain-object": "^2.0.4", - "jss": "^9.3.3", + "jss": "^9.8.7", "jss-camel-case": "^6.0.0", "jss-default-unit": "^8.0.2", "jss-global": "^3.0.0", diff --git a/package.json b/package.json index 1178918..1629050 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "dependencies": { "@aspnet/signalr": "^1.1.0", "@cc98/ubb-core": "1.1.0", - "@material-ui/core": "^3.7.0", + "@material-ui/core": "^3.7.1", "@material-ui/icons": "^3.0.1", "@reach/router": "^1.2.1", "@sentry/browser": "^4.4.2", @@ -34,6 +34,7 @@ "devDependencies": { "@babel/core": "^7.2.2", "@babel/plugin-proposal-class-properties": "^7.2.3", + "@babel/plugin-transform-runtime": "^7.2.0", "@babel/preset-env": "^7.2.3", "@babel/preset-react": "^7.0.0", "@babel/preset-typescript": "^7.1.0", From 2cef9dbe39b41b8a69fdd48ce14fbf184d176a3c Mon Sep 17 00:00:00 2001 From: Hydrogen Date: Tue, 25 Dec 2018 19:34:04 +0800 Subject: [PATCH 09/13] fix: babel dev conifg --- babel.config.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/babel.config.js b/babel.config.js index 9aa0d1e..a02f2ca 100644 --- a/babel.config.js +++ b/babel.config.js @@ -8,6 +8,7 @@ const presets = [ ] const plugins = [ + ["@babel/plugin-transform-runtime"], ["@babel/plugin-proposal-class-properties", { "loose": true }], @@ -24,12 +25,6 @@ const plugins = [ }], ] -if (process.env.NODE_ENV === "production") { - plugins.unshift(...[ - ["@babel/plugin-transform-runtime"], - ]) -} - module.exports = { presets, plugins, From f7011507b6fd79f85f3d2d3d4fe66490388f262b Mon Sep 17 00:00:00 2001 From: AsukaSong Date: Tue, 25 Dec 2018 20:08:11 +0800 Subject: [PATCH 10/13] =?UTF-8?q?fix=20#22=20=E7=83=AD=E9=97=A8=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E6=A0=87=E7=AD=BE=E5=8D=A1=E9=A1=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 加载热门列表时延时300ms * 添加了一个useDelay --- src/components/TopicList/index.tsx | 12 ++++++++++-- src/hooks/useDelay.ts | 20 ++++++++++++++++++++ src/pages/HotTopic/index.tsx | 20 +++++++++++++------- 3 files changed, 43 insertions(+), 9 deletions(-) create mode 100644 src/hooks/useDelay.ts diff --git a/src/components/TopicList/index.tsx b/src/components/TopicList/index.tsx index eacbb22..ee93e4e 100644 --- a/src/components/TopicList/index.tsx +++ b/src/components/TopicList/index.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components' import useInfList, { Service as InfService } from '@/hooks/useInfList' import useFetcher, { Service as FinService } from '@/hooks/useFetcher' +import useDelay from '@/hooks/useDelay' import TopicList from './TopicList' import { Place } from './TopicListItem' @@ -58,12 +59,19 @@ interface FinProps { service: FinService noLoading?: boolean place: Place + delay?: number } -const FinTopicList: React.FunctionComponent = ({ service, noLoading, place }) => { +const FinTopicList: React.FunctionComponent = ({ + service, + noLoading, + place, + delay = 0, +}) => { const [topics] = useFetcher(service, { fail: navigateHandler }) + const isResolve = useDelay(delay) - if (topics === null) { + if (topics === null || !isResolve) { return noLoading ? null : } diff --git a/src/hooks/useDelay.ts b/src/hooks/useDelay.ts new file mode 100644 index 0000000..d16afcd --- /dev/null +++ b/src/hooks/useDelay.ts @@ -0,0 +1,20 @@ +import { useState, useEffect } from 'react' + +/** + * 返回一个boolean + * 在指定的时间后其值为true + * @returns {boolean} 是否超过了延迟时间 + * @param time 延迟时间 + */ +export default function useDelay(time: number): boolean { + const [isResolve, setIsResolve] = useState(time <= 0) + + useEffect(() => { + if (time <= 0) return + const timer = setTimeout(() => setIsResolve(true), time) + + return () => clearTimeout(timer) + }, []) + + return isResolve +} diff --git a/src/pages/HotTopic/index.tsx b/src/pages/HotTopic/index.tsx index 7f39d1c..580bb5b 100644 --- a/src/pages/HotTopic/index.tsx +++ b/src/pages/HotTopic/index.tsx @@ -1,6 +1,7 @@ import React, { useState } from 'react' import useFetcher from '@/hooks/useFetcher' +import useDelay from '@/hooks/useDelay' import { FinTopicList } from '@/components/TopicList' import { List, Tab, Tabs } from '@material-ui/core' @@ -18,14 +19,16 @@ import { notificationHandler } from '@/services/utils/errorHandler' interface Props { service: typeof getHotTopics + delay?: number } -export const HotTopicList: React.FunctionComponent = ({ service }) => { +export const HotTopicList: React.FunctionComponent = ({ service, delay = 0 }) => { const [topics] = useFetcher(service, { fail: notificationHandler, }) + const isResolve = useDelay(delay) - if (topics === null) { + if (topics === null || !isResolve) { return } @@ -60,11 +63,14 @@ export default () => { - {current === 'day' && } - - {current === 'week' && } - {current === 'month' && } - {current === 'history' && } + {current === 'day' && } + {current === 'week' && } + {current === 'month' && ( + + )} + {current === 'history' && ( + + )} ) } From 9d65f0e9c0938ec64b403af8f5c59cce47fee21b Mon Sep 17 00:00:00 2001 From: Hydrogen Date: Wed, 26 Dec 2018 01:07:06 +0800 Subject: [PATCH 11/13] feat: router animate fix: markdown pre overflow fix: scroll when goback --- config/webpack.dev.js | 1 + package-lock.json | 8 ++ package.json | 1 + src/pages/Editor/Editor/MainContent.tsx | 2 +- src/pages/Topic/PostItem/Content.tsx | 5 ++ src/router/index.tsx | 102 +++++++++++++++++++----- src/version.ts | 2 +- 7 files changed, 98 insertions(+), 23 deletions(-) diff --git a/config/webpack.dev.js b/config/webpack.dev.js index 3f815ea..8b8d317 100644 --- a/config/webpack.dev.js +++ b/config/webpack.dev.js @@ -17,6 +17,7 @@ module.exports = merge(common, { devtool: 'eval-source-map', devServer: { + disableHostCheck: true, historyApiFallback: true, port: 9898, host: '0.0.0.0', diff --git a/package-lock.json b/package-lock.json index 9be17ab..654cf50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7894,6 +7894,14 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-spring": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/react-spring/-/react-spring-7.2.5.tgz", + "integrity": "sha512-J14PEJmkTOKLqN03+y7nM9szUrnQhZnapyQu4Tr8Ncq5wpKUB4ASZ4pRU/amNVKf0WVPkYeD62FqZFIrDjELJg==", + "requires": { + "@babel/runtime": "^7.0.0" + } + }, "react-transition-group": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.5.2.tgz", diff --git a/package.json b/package.json index 1629050..aa822ba 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "lodash-es": "^4.17.11", "react": "16.7.0-alpha.2", "react-dom": "16.7.0-alpha.2", + "react-spring": "^7.2.5", "remark": "^10.0.1", "remark-react": "^5.0.1", "styled-components": "^4.1.3", diff --git a/src/pages/Editor/Editor/MainContent.tsx b/src/pages/Editor/Editor/MainContent.tsx index 8b00b7b..7d84263 100644 --- a/src/pages/Editor/Editor/MainContent.tsx +++ b/src/pages/Editor/Editor/MainContent.tsx @@ -10,7 +10,7 @@ const InputArea = styled(InputBase).attrs({ multiline: true, autoFocus: true, rows: 6, - rowsMax: 12, + rowsMax: 10, })` && { margin-top: 8px; diff --git a/src/pages/Topic/PostItem/Content.tsx b/src/pages/Topic/PostItem/Content.tsx index ece3e2e..9b5acfe 100644 --- a/src/pages/Topic/PostItem/Content.tsx +++ b/src/pages/Topic/PostItem/Content.tsx @@ -24,6 +24,11 @@ const TypographyS = styled(Typography)` img { max-width: 100%; } + + pre, + code { + white-space: pre-wrap; + } } ` diff --git a/src/router/index.tsx b/src/router/index.tsx index 5dc91b9..fb8d735 100644 --- a/src/router/index.tsx +++ b/src/router/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import React, { useEffect, useRef } from 'react' // https://reach.tech/router/api/Router import { Location, WindowLocation } from '@reach/router' import Router, { ILocation } from './Router' @@ -8,8 +8,14 @@ import settingInstance from '@/containers/setting' import './gesture' +interface LocationState { + href: string + location: WindowLocation + scrollTop: number +} + interface State { - locations: WindowLocation[] + locationStates: LocationState[] MAX_CACHE_SIZE: number } @@ -18,7 +24,7 @@ interface State { */ class RouterCacheContainer extends Container { state: State = { - locations: [], + locationStates: [], MAX_CACHE_SIZE: settingInstance.state.routerCacheSize, } @@ -27,22 +33,26 @@ class RouterCacheContainer extends Container { * @param location */ push(location: WindowLocation) { - const { locations, MAX_CACHE_SIZE } = this.state - const index = locations.findIndex(backLoc => backLoc.href === location.href) + const { locationStates, MAX_CACHE_SIZE } = this.state + const index = locationStates.findIndex(locState => locState.href === location.href) if (index !== -1) { - const loc = locations[index] - locations.splice(index, 1) - locations.push(loc) + const loc = locationStates[index] + locationStates.splice(index, 1) + locationStates.push(loc) } else { - locations.push({ ...location }) + locationStates.push({ + href: location.href, + location: { ...location }, + scrollTop: 0, + }) // 超过最大缓存数 - if (locations.length > MAX_CACHE_SIZE) { - locations.shift() + if (locationStates.length > MAX_CACHE_SIZE) { + locationStates.shift() } } - this.setState({ locations }) + this.setState({ locationStates }) } } @@ -65,8 +75,63 @@ export function bindURL(func: Function, href: string) { } } -const CacheRouter: React.FunctionComponent = ({ location }) => { - const { locations } = useContainer(ROUTER_CACHE).state +// https://majido.github.io/scroll-restoration-proposal/history-based-api.html#web-idl +history.scrollRestoration = 'manual' + +// @ts-ignore FIXME: no animated export from d.ts +import { useSpring, animated } from 'react-spring/hooks' +import { config } from 'react-spring' + +interface ScrollDivProps { + show: boolean + locState: LocationState +} + +const ScrollDiv = ({ show, locState }: ScrollDivProps) => { + const lastShow = useRef(false) + const [props, set] = useSpring(() => ({ + opacity: 0, + config: config.gentle, + })) + + if (lastShow.current !== show) { + if (show) { + // @ts-ignore + set({ opacity: 1 }) + + setTimeout(() => { + if (!locState.scrollTop) { + return + } + window.scrollTo({ + left: 0, + top: locState.scrollTop, + // behavior: 'smooth', + }) + // FIXME: choose a better delay + }, 300) + } + + if (!show) { + // @ts-ignore + set({ opacity: 0 }) + locState.scrollTop = window.scrollY + } + + lastShow.current = show + } + + const style = show ? props : { display: 'none' } + + return ( + + + + ) +} + +const CacheRouter: React.FC = ({ location }) => { + const { locationStates } = useContainer(ROUTER_CACHE).state useEffect( () => { @@ -77,13 +142,8 @@ const CacheRouter: React.FunctionComponent = ({ location }) => { return ( <> - {locations.map(backLoc => ( -
- -
+ {locationStates.map(locState => ( + ))} ) diff --git a/src/version.ts b/src/version.ts index c6a6681..0404c53 100644 --- a/src/version.ts +++ b/src/version.ts @@ -2,4 +2,4 @@ * 版本号 */ -export default 'v1.2.0-beta' +export default 'v1.2.1-beta' From 4b07a9eb69c7945ef309f5e5d33baa354fa80d89 Mon Sep 17 00:00:00 2001 From: Hydrogen Date: Wed, 26 Dec 2018 17:31:14 +0800 Subject: [PATCH 12/13] style: Topic SubTitle --- .../handlerHub/specificTagHandlers/bili.tsx | 11 +------- src/UBB/style.css | 4 +-- src/components/FixFab/index.tsx | 9 ++++--- src/components/TopicList/TopicListItem.tsx | 27 +++++++++---------- src/pages/Topic/FixButtons.tsx | 6 ++--- .../Topic/{Actions.tsx => PostActions.tsx} | 20 +++----------- src/pages/Topic/PostHead.tsx | 14 +++++----- src/router/index.tsx | 2 +- src/services/board.ts | 2 +- 9 files changed, 36 insertions(+), 59 deletions(-) rename src/pages/Topic/{Actions.tsx => PostActions.tsx} (77%) diff --git a/src/UBB/handlerHub/specificTagHandlers/bili.tsx b/src/UBB/handlerHub/specificTagHandlers/bili.tsx index e8ee400..046d93e 100644 --- a/src/UBB/handlerHub/specificTagHandlers/bili.tsx +++ b/src/UBB/handlerHub/specificTagHandlers/bili.tsx @@ -12,20 +12,11 @@ const handler: ITagHandler = { const { bili } = node.tagData const partNumber = parseInt(bili, 10) || 1 - const props = { - border: 0, - frameborder: 'no', - framespacing: 0, - allowfullscreen: true, - } - return (