From 8aa09c0742ab1ff33d9de3bc132ea0f22112ede6 Mon Sep 17 00:00:00 2001 From: Shiny Lee Date: Mon, 18 Dec 2017 21:32:45 +0800 Subject: [PATCH] [Release 1.4.0] * remove jQuery / Blaze dependencies * upgrade material-ui * fix CommentList user avatar bug * improve TopImages layout --- .meteor/packages | 3 - .meteor/versions | 11 -- imports/startup/client/accounts-config.js | 16 +- imports/startup/server/cdn-config.js | 144 ++++++++++++++++++ imports/startup/server/index.js | 2 + imports/ui/components/CollList/CollHolder.js | 16 +- .../ui/components/CommentList/CommentList.js | 38 ++--- .../components/CommentList/CommentListItem.js | 74 +++++++++ .../ui/components/ImageHolder/ImageHolder.js | 1 - imports/ui/components/ImageHolder/index.js | 5 +- .../components/ToolBar/index.js | 8 +- imports/ui/components/Modal/index.js | 10 +- .../NavHeader/Primary/components/Drawer.js | 14 +- .../ui/components/NavHeader/Primary/index.js | 4 +- .../components/NavHeader/Secondary/index.js | 2 +- imports/ui/components/SnackBar/index.js | 6 +- .../pages/Diary/components/DiaryViewer.js | 8 +- imports/ui/pages/Note/pages/Notes/index.js | 2 +- .../ui/pages/Recycle/components/Content.js | 14 +- imports/ui/pages/Recycle/styles/index.js | 6 + .../pages/Emails/components/Content.js | 2 +- .../pages/Setting/components/Content.js | 48 +++--- .../Sign/pages/Login/components/Content.js | 8 + .../User/pages/User/components/Content.js | 6 +- package-lock.json | 105 +++++-------- package.json | 6 +- 26 files changed, 365 insertions(+), 194 deletions(-) create mode 100644 imports/startup/server/cdn-config.js create mode 100644 imports/ui/components/CommentList/CommentListItem.js create mode 100644 imports/ui/pages/Recycle/styles/index.js diff --git a/.meteor/packages b/.meteor/packages index 831a397..530a784 100644 --- a/.meteor/packages +++ b/.meteor/packages @@ -37,13 +37,10 @@ deanius:promise didericis:callpromise-mixin # production -nitrolabs:cdn # TODO remove jQuery / Blaze dependencies percolate:migrations # testing dburles:factory -practicalmeteor:mocha # TODO remove jQuery / Blaze dependencies -practicalmeteor:chai practicalmeteor:sinon johanbrook:publication-collector dispatch:mocha-phantomjs diff --git a/.meteor/versions b/.meteor/versions index 1adf120..bb45456 100644 --- a/.meteor/versions +++ b/.meteor/versions @@ -11,7 +11,6 @@ babel-compiler@6.24.7 babel-runtime@1.1.1 base64@1.0.10 binary-heap@1.0.10 -blaze@2.3.2 blaze-tools@1.0.10 boilerplate-generator@1.3.0 caching-compiler@1.1.9 @@ -49,7 +48,6 @@ htmljs@1.0.11 http@1.3.0 id-map@1.0.9 johanbrook:publication-collector@1.0.10 -jquery@1.11.10 launch-screen@1.1.1 less@2.7.11 livedata@1.0.18 @@ -69,15 +67,11 @@ modules-runtime@0.9.0 mongo@1.3.0 mongo-dev-server@1.1.0 mongo-id@1.0.6 -nitrolabs:cdn@1.3.0 npm-bcrypt@0.9.3 npm-mongo@2.2.33 -observe-sequence@1.0.16 ordered-dict@1.0.9 percolate:migrations@0.9.8 practicalmeteor:chai@2.1.0_1 -practicalmeteor:loglevel@1.2.0_2 -practicalmeteor:mocha@2.4.5_6 practicalmeteor:mocha-core@1.0.1 practicalmeteor:sinon@1.14.1_2 promise@0.10.0 @@ -93,18 +87,13 @@ routepolicy@1.0.12 service-configuration@1.0.11 sha@1.0.9 shell-server@0.3.0 -spacebars@1.0.15 spacebars-compiler@1.1.3 srp@1.0.10 standard-minifier-css@1.3.5 standard-minifier-js@2.2.3 static-html@1.2.2 -templating@1.3.2 -templating-compiler@1.3.3 -templating-runtime@1.3.2 templating-tools@1.1.2 tmeasday:check-npm-versions@0.2.0 -tmeasday:test-reporter-helpers@0.2.1 tracker@1.1.3 underscore@1.0.10 url@1.1.0 diff --git a/imports/startup/client/accounts-config.js b/imports/startup/client/accounts-config.js index 91a70d5..356c65d 100644 --- a/imports/startup/client/accounts-config.js +++ b/imports/startup/client/accounts-config.js @@ -1,14 +1,12 @@ import { Accounts } from 'meteor/accounts-base'; import history from '/imports/utils/history'; -Accounts.onLogout(() => { - history.replace('/login'); -}); +Accounts.onLogout(() => history.replace('/login')); Accounts.onEmailVerificationLink((token) => { Accounts.verifyEmail(token, (err) => { if (err) { - console.log(err); + console.warn(err); return history.replace({ pathname: `/${err.error || 500}`, state: { message: `服务器内部错误 ${err.reason}` }, @@ -18,9 +16,7 @@ Accounts.onEmailVerificationLink((token) => { }); }); -Accounts.onResetPasswordLink((token) => { - history.replace({ - pathname: '/accounts/resetPassword', - state: { token }, - }); -}); +Accounts.onResetPasswordLink((token) => history.replace({ + pathname: '/accounts/resetPassword', + state: { token }, +})); diff --git a/imports/startup/server/cdn-config.js b/imports/startup/server/cdn-config.js new file mode 100644 index 0000000..a2cc879 --- /dev/null +++ b/imports/startup/server/cdn-config.js @@ -0,0 +1,144 @@ + +import url from 'url'; +import path from 'path'; +import { Meteor } from 'meteor/meteor'; +import { WebApp, WebAppInternals } from 'meteor/webapp'; + +// From https://github.com/Nitrolabs/meteor-cdn/blob/master/lib/server.js +// Minimal cdn config which remove blaze and jQuery dependencies + +const FONTS = ['.ttf', '.eot', '.otf', '.svg', '.woff', '.woff2']; +const ALLOWED_PROTOCOLS = ['http:', 'https:']; + +/* stripSlashes + * + * Strip the trailing slash from a url + */ +function stripSlashes(slashUrl) { + if (slashUrl) { + return slashUrl.replace(/\/$/, ''); + } + return slashUrl; +} + +function validateSettings(rootUrl, cdnUrl) { + // Return True if the ROOT_URL and CDN_URL settings are valid + // Return False if the settings are invalid, but the server can continue + // Throw an error if the settings are fatally incorrect + if (!rootUrl) { + console.warn('ROOT_URL is not set. Using default Meteor behaviour'); + return false; + } else if (!cdnUrl) { + console.warn('CDN_URL is not set. Using default Meteor behaviour'); + return false; + } + const cdn = url.parse(cdnUrl); + const root = url.parse(rootUrl); + + if (root.hostname === 'localhost') { + return false; + } + + // Make sure that the CDN_URL is different from the ROOT_URL + // If these are the same, we can't detect requests from the CDN + if (cdn.host === root.host) { + console.warn('CDN: CDN HOST === ROOT HOST. Using default Meteor behaviour'); + return false; + } + + // Ensure that the CDN_URL and ROOT_URL are correctly formed + if (ALLOWED_PROTOCOLS.indexOf(root.protocol) < 0) { + throw new Meteor.Error(`ROOT_URL must use http or https protocol, not ${root.protocol}`); + } else if (ALLOWED_PROTOCOLS.indexOf(cdn.protocol) < 0) { + throw new Meteor.Error(`CDN_URL must use http or https protocol, not ${cdn.protocol}`); + } + + // Return true if the settings are valid + return true; +} + + +function setClientCdnUrl(cdnUrl) { + // Make the CDN_URL available on the client + // console.log("Setting BundledJsCssPrefix to "+cdnUrl); + const hasQuestionMark = new RegExp('[?]'); + WebAppInternals.setBundledJsCssUrlRewriteHook((bundlePath) => { + // This code fixes an issue in Galaxy where you can end up getting served + // stale code after deployments + const galaxyVersionId = process.env.GALAXY_APP_VERSION_ID; + let rewrittenUrl = cdnUrl + bundlePath; + if (galaxyVersionId) { + const separator = hasQuestionMark.test(bundlePath) ? '&' : '?'; + rewrittenUrl += `${separator}_g_app_v_=${galaxyVersionId}`; + } + return rewrittenUrl; + }); + // WebAppInternals.setBundledJsCssPrefix(cdnUrl); + // eslint-disable-next-line no-undef + __meteor_runtime_config__.CDN_URL = cdnUrl; +} + +function configureBrowserPolicy(cdnUrl) { + console.log('Attemping to configure BrowserPolicy'); + if (Package['browser-policy']) { // eslint-disable-line no-undef + BrowserPolicy.content.allowOriginForAll(cdnUrl); // eslint-disable-line no-undef + console.log(`Configure BrowserPolicy allowOriginForAll(${cdnUrl})`); + } +} + +function CdnController() { + const rootUrl = stripSlashes(process.env.ROOT_URL); + const cdnUrl = stripSlashes(process.env.CDN_URL); + + const CORSconnectHandler = (req, res, next) => { + // Set CORS headers on webfonts to avoid issue with chrome and firefox + const ext = path.extname(url.parse(req.url).pathname); + if (FONTS.indexOf(ext) > -1) { + res.setHeader('Strict-Transport-Security', 'max-age=2592000; includeSubDomains'); // 2592000s / 30 days + res.setHeader('Access-Control-Allow-Origin', '*'); + } + next(); + }; + + const static404connectHandler = (req, res, next) => { + // Return 404 if a non-existent static file is requested + // If REQUEST_HOST === CDN_URL then a 404 is returned for all non-static files + const pathname = url.parse(req.url).pathname; + // const ext = path.extname(pathname); + const root = url.parse(rootUrl); + const cdn = url.parse(cdnUrl); + + const isFromCDN = (req.headers.host === cdn.host && req.headers.host !== root.host); + + // Cloudfront removes all headers by default + // We need the HOST header to determine where this request came from + if (!req.headers.host) { + console.warn('HOST header is not set'); + console.warn('Unable to determine if this request came via the CDN'); + } else if (isFromCDN && !(pathname in WebAppInternals.staticFiles)) { + console.warn(`Static resource not found: ${pathname}`); + res.writeHead(404); + res.write('Static File Not Found'); + res.end(); + return res; + } else if (isFromCDN) { + console.log(`Serving to CDN: ${pathname}`); + } + next(); + }; + + // Initialize the CDN + if (validateSettings(rootUrl, cdnUrl)) { + setClientCdnUrl(cdnUrl); + configureBrowserPolicy(cdnUrl); + WebApp.rawConnectHandlers.use(static404connectHandler); + WebApp.rawConnectHandlers.use(CORSconnectHandler); + console.info(`Using CDN: ${cdnUrl}`); + } +} + +Meteor.startup(() => { + if (process.env.NODE_ENV === 'production') { + CdnController(); + } +}); diff --git a/imports/startup/server/index.js b/imports/startup/server/index.js index aecd45f..9580367 100644 --- a/imports/startup/server/index.js +++ b/imports/startup/server/index.js @@ -1,3 +1,5 @@ +import './cdn-config'; + // This defines a starting set of data to be loaded if the app is loaded with an empty db. import './fixtures'; diff --git a/imports/ui/components/CollList/CollHolder.js b/imports/ui/components/CollList/CollHolder.js index 82afd52..8d1286b 100644 --- a/imports/ui/components/CollList/CollHolder.js +++ b/imports/ui/components/CollList/CollHolder.js @@ -48,19 +48,19 @@ class CollHolder extends Component { anchorEl: undefined, } - _handleRequestClose = () => { + _handleClose = () => { this.setState({ menuOpen: false }); } _handleToggleLock = () => { const { coll } = this.props; - this._handleRequestClose(); + this._handleClose(); this.props.onToggleLock(coll); } _handleToggleRemove = () => { const { coll } = this.props; - this._handleRequestClose(); + this._handleClose(); this.props.onRemove(coll); } @@ -84,11 +84,9 @@ class CollHolder extends Component { : `${coll.cover}?imageView2/2/w/${rWidth}`; return ( - - - - - + + + {coll.name} @@ -111,7 +109,7 @@ class CollHolder extends Component { key="actionMenu" open={this.state.menuOpen} anchorEl={this.state.anchorEl} - onRequestClose={this._handleRequestClose} + onClose={this._handleClose} > {/* } diff --git a/imports/ui/components/CommentList/CommentList.js b/imports/ui/components/CommentList/CommentList.js index a744a3a..59d85eb 100644 --- a/imports/ui/components/CommentList/CommentList.js +++ b/imports/ui/components/CommentList/CommentList.js @@ -1,9 +1,6 @@ import get from 'lodash/get'; import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import TimeAgo from 'react-timeago'; -import CNStrings from 'react-timeago/lib/language-strings/zh-CN'; -import buildFormatter from 'react-timeago/lib/formatters/buildFormatter'; +import React, { PureComponent } from 'react'; import Avatar from 'material-ui/Avatar'; import Button from 'material-ui/Button'; import Collapse from 'material-ui/transitions/Collapse'; @@ -11,14 +8,12 @@ import Popover from 'material-ui/Popover'; import Input from 'material-ui/Input'; import List, { ListItem, - ListItemAvatar, ListItemText, } from 'material-ui/List'; import { insertComment, removeComment } from '/imports/api/comments/methods'; import settings from '/imports/utils/settings'; +import CommentListItem from './CommentListItem'; import { - CommentsContent, - CommentsTime, PublishSection, PublishContent, PublishFooter, @@ -26,12 +21,9 @@ import { const { sourceDomain } = settings; -const formatter = buildFormatter(CNStrings); - -export default class CommentList extends Component { +export default class CommentList extends PureComponent { static propTypes = { open: PropTypes.bool.isRequired, - owner: PropTypes.object.isRequired, discId: PropTypes.string.isRequired, comments: PropTypes.array.isRequired, User: PropTypes.object, // not required bc guest can visit it @@ -51,7 +43,7 @@ export default class CommentList extends Component { return User ? User.profile.avatar : defaultAvatar; } - _handleCommentClick(e, comment) { + _handleCommentClick = (e, comment) => { this.setState({ [comment._id]: true, popoverAnchor: e.currentTarget }); } @@ -115,7 +107,6 @@ export default class CommentList extends Component { render() { const { open, - owner, comments, User, classes, @@ -129,27 +120,16 @@ export default class CommentList extends Component { { comments.length > 0 && comments.map((comment) => ( - this._handleCommentClick(e, comment)} - button - > - - - - -

{comment.user}

-
- - - - - + this.setState({ [comment._id]: false })} + onClose={() => this.setState({ [comment._id]: false })} > this._handleReplyComment(comment)}> diff --git a/imports/ui/components/CommentList/CommentListItem.js b/imports/ui/components/CommentList/CommentListItem.js new file mode 100644 index 0000000..0ddd20b --- /dev/null +++ b/imports/ui/components/CommentList/CommentListItem.js @@ -0,0 +1,74 @@ +import get from 'lodash/get'; +import PropTypes from 'prop-types'; +import React, { PureComponent } from 'react'; +import TimeAgo from 'react-timeago'; +import CNStrings from 'react-timeago/lib/language-strings/zh-CN'; +import buildFormatter from 'react-timeago/lib/formatters/buildFormatter'; +import { compose } from 'redux'; +import { connect } from 'react-redux'; +import { Meteor } from 'meteor/meteor'; +import { withTracker } from 'meteor/react-meteor-data'; +import Avatar from 'material-ui/Avatar'; +import { ListItem, ListItemAvatar } from 'material-ui/List'; +import { + CommentsContent, + CommentsTime, +} from './CommentList.style'; + +const formatter = buildFormatter(CNStrings); + +class CommentListItem extends PureComponent { + static propTypes = { + comment: PropTypes.object.isRequired, + commenter: PropTypes.object.isRequired, + onClick: PropTypes.func.isRequired, + } + + render() { + const { + comment, + commenter, + onClick, + } = this.props; + return ( + onClick(e, comment)} + button + > + + + + +

{comment.user}

+
+ + + + + + ); + } +} + +const mapStateToProps = ({ sessions }) => ({ + isLoggedIn: sessions.isLoggedIn, + User: sessions.User, +}); + +const trackHandler = ({ isLoggedIn, User, comment }) => { + let commenter; + if (isLoggedIn && User.username === comment.user) { + commenter = User; + } else { + Meteor.subscribe('Users.all'); + commenter = Meteor.users.findOne({ username: comment.user }) || {}; + } + return { + commenter, + }; +}; + +export default compose( + connect(mapStateToProps), + withTracker(trackHandler), +)(CommentListItem); diff --git a/imports/ui/components/ImageHolder/ImageHolder.js b/imports/ui/components/ImageHolder/ImageHolder.js index 562c6a2..e6b6a41 100644 --- a/imports/ui/components/ImageHolder/ImageHolder.js +++ b/imports/ui/components/ImageHolder/ImageHolder.js @@ -132,7 +132,6 @@ export default class ImageHolder extends PureComponent { diff --git a/imports/ui/components/ImageHolder/index.js b/imports/ui/components/ImageHolder/index.js index 1d95b31..7552f79 100644 --- a/imports/ui/components/ImageHolder/index.js +++ b/imports/ui/components/ImageHolder/index.js @@ -26,6 +26,7 @@ const styles = { const mapStateToProps = ({ sessions, device }) => ({ device, + isLoggedIn: sessions.isLoggedIn, User: sessions.User, }); @@ -33,7 +34,7 @@ const mapDispatchToProps = (dispatch) => bindActionCreators({ snackBarOpen, }, dispatch); -const trackHandler = ({ User, image }) => { +const trackHandler = ({ isLoggedIn, User, image }) => { // discussion_id from comment const imageId = image._id; @@ -41,7 +42,7 @@ const trackHandler = ({ User, image }) => { Meteor.subscribe('Comments.inImage', imageId); let owner; - if (User && User.username === image.user) { + if (isLoggedIn && User.username === image.user) { owner = User; } else { Meteor.subscribe('Users.all'); diff --git a/imports/ui/components/JustifiedLayout/components/ToolBar/index.js b/imports/ui/components/JustifiedLayout/components/ToolBar/index.js index f0d5c7b..a4c591f 100644 --- a/imports/ui/components/JustifiedLayout/components/ToolBar/index.js +++ b/imports/ui/components/JustifiedLayout/components/ToolBar/index.js @@ -44,7 +44,7 @@ export default class JustifiedToolBar extends PureComponent { this.setState({ anchorEl: evt.currentTarget }); } - _handleRequestClose = () => { + _handleClose = () => { this.setState({ anchorEl: null }); } @@ -67,10 +67,10 @@ export default class JustifiedToolBar extends PureComponent {
onLayoutChange('group')}> - + onLayoutChange('grid')}> - + @@ -78,7 +78,7 @@ export default class JustifiedToolBar extends PureComponent { diff --git a/imports/ui/components/Modal/index.js b/imports/ui/components/Modal/index.js index 3a6fb65..2196432 100644 --- a/imports/ui/components/Modal/index.js +++ b/imports/ui/components/Modal/index.js @@ -62,10 +62,10 @@ class Modal extends PureComponent { return Store.dispatch(modalClose()); } - _handleRequestClose = () => { - const onRequestClose = get(this, 'props.ops.onRequestClose'); - if (onRequestClose) { - onRequestClose(); + _handleClose = () => { + const onClose = get(this, 'props.ops.onClose'); + if (onClose) { + onClose(); } else { this.props.modalClose(); } @@ -77,7 +77,7 @@ class Modal extends PureComponent { { !!title && {title} } diff --git a/imports/ui/components/NavHeader/Primary/components/Drawer.js b/imports/ui/components/NavHeader/Primary/components/Drawer.js index 93cdac1..5426b3a 100644 --- a/imports/ui/components/NavHeader/Primary/components/Drawer.js +++ b/imports/ui/components/NavHeader/Primary/components/Drawer.js @@ -36,7 +36,7 @@ const { sourceDomain } = settings; class NavHeaderDrawer extends PureComponent { static propTypes = { visible: PropTypes.bool.isRequired, - onRequestClose: PropTypes.func.isRequired, + onClose: PropTypes.func.isRequired, isLoggedIn: PropTypes.bool.isRequired, User: PropTypes.object, match: PropTypes.object.isRequired, @@ -67,7 +67,7 @@ class NavHeaderDrawer extends PureComponent { _navTo = (to) => () => { const { location: { pathname } } = this.props; if (pathname === to) { - this.props.onRequestClose(); + this.props.onClose(); } if (to === '/login') { this.props.snackBarOpen('您还尚未登录'); @@ -76,7 +76,7 @@ class NavHeaderDrawer extends PureComponent { } _handleLogout = async () => { - this.props.onRequestClose(); + this.props.onClose(); await Modal.showLoader('登出中'); await this.props.userLogout(); Modal.close(); @@ -96,7 +96,7 @@ class NavHeaderDrawer extends PureComponent { User, match, classes, - onRequestClose, + onClose, } = this.props; const isIndexPage = match.path === '/'; const isUserPage = !!match.params.username; @@ -104,7 +104,7 @@ class NavHeaderDrawer extends PureComponent { {get(User, 'emails[0].address') || User.username} - + this.setState({ popover: false })} + onClose={() => this.setState({ popover: false })} > diff --git a/imports/ui/components/NavHeader/Primary/index.js b/imports/ui/components/NavHeader/Primary/index.js index 4a8ed60..2509f29 100644 --- a/imports/ui/components/NavHeader/Primary/index.js +++ b/imports/ui/components/NavHeader/Primary/index.js @@ -43,7 +43,7 @@ class PrimaryNavHeader extends PureComponent { this.setState(prevState => ({ drawer: !prevState.drawer })); } - _handleRequestClose = () => { + _handleClose = () => { this.setState({ drawer: false }); } @@ -68,7 +68,7 @@ class PrimaryNavHeader extends PureComponent { diff --git a/imports/ui/components/NavHeader/Secondary/index.js b/imports/ui/components/NavHeader/Secondary/index.js index 047524f..78b8826 100644 --- a/imports/ui/components/NavHeader/Secondary/index.js +++ b/imports/ui/components/NavHeader/Secondary/index.js @@ -84,7 +84,7 @@ class SecondaryNavHeader extends PureComponent { color="inherit" onClick={() => scrollTo(0, 1500)} > - {title} + {title || '返回'} diff --git a/imports/ui/components/SnackBar/index.js b/imports/ui/components/SnackBar/index.js index e5c2bdf..fd3bd1f 100644 --- a/imports/ui/components/SnackBar/index.js +++ b/imports/ui/components/SnackBar/index.js @@ -41,7 +41,7 @@ class SnackBar extends Component { } } - _handleRequestClose = () => { + _handleClose = () => { this.props.snackBarClose(); } @@ -52,8 +52,8 @@ class SnackBar extends Component { open={this.state.open} message={this.state.message} autoHideDuration={autoHideDuration} - onRequestClose={this._handleRequestClose} - onExited={this._handleRequestClose} + onClose={this._handleClose} + onExited={this._handleClose} /> ); } diff --git a/imports/ui/pages/Diary/pages/Diary/components/DiaryViewer.js b/imports/ui/pages/Diary/pages/Diary/components/DiaryViewer.js index 6fd31bd..62276ff 100644 --- a/imports/ui/pages/Diary/pages/Diary/components/DiaryViewer.js +++ b/imports/ui/pages/Diary/pages/Diary/components/DiaryViewer.js @@ -117,16 +117,16 @@ class DiaryViewer extends PureComponent { } _handleEditing = () => { - this._handleRequestClose(); + this._handleClose(); this.setState({ isEditing: true }); } - _handleRequestClose = () => { + _handleClose = () => { this.setState({ menuOpen: false }); } renderPrompt = () => { - this._handleRequestClose(); + this._handleClose(); Modal.showPrompt({ message: '您是否确认删除此日记?', onCancel: Modal.close, @@ -175,7 +175,7 @@ class DiaryViewer extends PureComponent { key="moreMenu" open={this.state.menuOpen} anchorEl={this.state.anchorEl} - onRequestClose={this._handleRequestClose} + onClose={this._handleClose} > 编辑 删除 diff --git a/imports/ui/pages/Note/pages/Notes/index.js b/imports/ui/pages/Note/pages/Notes/index.js index f27aed8..c74056e 100644 --- a/imports/ui/pages/Note/pages/Notes/index.js +++ b/imports/ui/pages/Note/pages/Notes/index.js @@ -78,7 +78,7 @@ export default class NotesPage extends Component { anchorEl={this.state.popoverAnchor} anchorOrigin={{ horizontal: 'left', vertical: 'top' }} transformOrigin={{ horizontal: 'left', vertical: 'top' }} - onRequestClose={() => this.setState({ popover: false })} + onClose={() => this.setState({ popover: false })} > diff --git a/imports/ui/pages/Recycle/components/Content.js b/imports/ui/pages/Recycle/components/Content.js index 71102ac..5eb53df 100644 --- a/imports/ui/pages/Recycle/components/Content.js +++ b/imports/ui/pages/Recycle/components/Content.js @@ -7,7 +7,12 @@ import { Toolbar, ToolbarLeft, } from '/imports/ui/components/JustifiedLayout/components/ToolBar/ToolBar.style'; -import { Header, Title, SubTitle } from '../../Collection/pages/Collection/styles'; +import { + Header, + Title, + SubTitle, +} from '../../Collection/pages/Collection/styles'; +import { Wrapper } from '../styles'; export default class RecycleContent extends PureComponent { static propTypes = { @@ -47,10 +52,11 @@ export default class RecycleContent extends PureComponent { render() { const { images } = this.props; - return images.length === 0 + const isEmpty = images.length === 0; + return isEmpty ? : ( -
+
回收站 回收站中的内容会在 30 天后永久删除 @@ -65,7 +71,7 @@ export default class RecycleContent extends PureComponent { images={images} isEditing /> -
+ ); } } diff --git a/imports/ui/pages/Recycle/styles/index.js b/imports/ui/pages/Recycle/styles/index.js new file mode 100644 index 0000000..7b89018 --- /dev/null +++ b/imports/ui/pages/Recycle/styles/index.js @@ -0,0 +1,6 @@ +import styled from 'styled-components'; + +export const Wrapper = styled.div` + flex: 1; + overflow-x: hidden; +`; diff --git a/imports/ui/pages/Setting/pages/Emails/components/Content.js b/imports/ui/pages/Setting/pages/Emails/components/Content.js index 1d98879..38fbfa4 100644 --- a/imports/ui/pages/Setting/pages/Emails/components/Content.js +++ b/imports/ui/pages/Setting/pages/Emails/components/Content.js @@ -107,7 +107,7 @@ export default class EmailsContent extends PureComponent { this.setState({ [`email_${i}`]: false })} + onClose={() => this.setState({ [`email_${i}`]: false })} > { !email.verified && ( diff --git a/imports/ui/pages/Setting/pages/Setting/components/Content.js b/imports/ui/pages/Setting/pages/Setting/components/Content.js index 68b23d4..9081a5f 100644 --- a/imports/ui/pages/Setting/pages/Setting/components/Content.js +++ b/imports/ui/pages/Setting/pages/Setting/components/Content.js @@ -28,7 +28,7 @@ import { Username, } from '../styles'; -const { domain } = settings; +const { imageDomain } = settings; const uploadURL = window.location.protocol === 'https:' ? 'https://up.qbox.me/' : 'http://upload.qiniu.com'; @@ -70,7 +70,7 @@ export default class SettingContent extends PureComponent { }); Modal.close(); this.props.snackBarOpen('上传封面成功'); - this.updateProfile({ cover: `${domain}/${data.key}` }); + this.updateProfile({ cover: `${imageDomain}/${data.key}` }); } catch (err) { console.warn(err); Modal.close(); @@ -79,35 +79,27 @@ export default class SettingContent extends PureComponent { } _handleSetAvatar = async (e) => { + const { User, token } = this.props; + const avatar = e.target.files[0]; + if (!avatar) { + return; + } try { await Modal.showLoader('上传头像中'); - const avatar = e.target.files[0]; - const size = Math.round(avatar.size / 1024); - if (size < 200) { - const reader = new FileReader(); - reader.onload = (evt) => { - Modal.close(); - this.props.snackBarOpen('上传头像成功'); - this.updateProfile({ avatar: evt.target.result }); - }; - reader.readAsDataURL(avatar); - } else { - const { User, token } = this.props; - const key = `${User.username}/setting/avatar/${avatar.name}`; - const formData = new FormData(); - formData.append('file', avatar); - formData.append('key', key); - formData.append('token', token); + const key = `${User.username}/setting/avatar/${avatar.name}`; + const formData = new FormData(); + formData.append('file', avatar); + formData.append('key', key); + formData.append('token', token); - const { data } = await axios({ - method: 'POST', - url: uploadURL, - data: formData, - }); - Modal.close(); - this.props.snackBarOpen('上传头像成功'); - this.updateProfile({ avatar: `${domain}/${data.key}?imageView2/1/w/240/h/240` }); - } + const { data } = await axios({ + method: 'POST', + url: uploadURL, + data: formData, + }); + Modal.close(); + this.props.snackBarOpen('上传头像成功'); + this.updateProfile({ avatar: `${imageDomain}/${data.key}?imageView2/1/w/240/h/240` }); } catch (err) { console.warn(err); Modal.close(); diff --git a/imports/ui/pages/Sign/pages/Login/components/Content.js b/imports/ui/pages/Sign/pages/Login/components/Content.js index 0fcec3a..4e91bba 100644 --- a/imports/ui/pages/Sign/pages/Login/components/Content.js +++ b/imports/ui/pages/Sign/pages/Login/components/Content.js @@ -63,6 +63,14 @@ export default class LoginContent extends Component { _handleLogin = async () => { const { account, password } = this.state; + if (!account) { + this.props.snackBarOpen('请输入账号'); + return; + } + if (!password) { + this.props.snackBarOpen('请输入密码'); + return; + } await Modal.showLoader('登录中'); await this.props.userLogin({ account, password }); Modal.close(); diff --git a/imports/ui/pages/User/pages/User/components/Content.js b/imports/ui/pages/User/pages/User/components/Content.js index dbda61d..3b712a5 100644 --- a/imports/ui/pages/User/pages/User/components/Content.js +++ b/imports/ui/pages/User/pages/User/components/Content.js @@ -145,9 +145,9 @@ export default class UserContent extends PureComponent { key="Popover" open={this.state.popover} anchorEl={this.state.anchorEl} - anchorOrigin={{ horizontal: 'top', vertical: 'left' }} - transformOrigin={{ horizontal: 'bottom', vertical: 'left' }} - onRequestClose={() => this.setState({ popover: false })} + anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }} + transformOrigin={{ horizontal: 'center', vertical: 'top' }} + onClose={() => this.setState({ popover: false })} > diff --git a/package-lock.json b/package-lock.json index 8b422ac..50d9fd7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "galleryplus", - "version": "1.4.0-rc.16", + "version": "1.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -2260,21 +2260,6 @@ "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" }, - "is-observable": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/is-observable/-/is-observable-0.2.0.tgz", - "integrity": "sha1-s2ExHYPG5dcmyr9eJQsCNxBvWuI=", - "requires": { - "symbol-observable": "0.2.4" - }, - "dependencies": { - "symbol-observable": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-0.2.4.tgz", - "integrity": "sha1-lag9smGG1q9+ehjb2XYKL4bQj0A=" - } - } - }, "is-path-cwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", @@ -2443,13 +2428,20 @@ } }, "jss": { - "version": "9.3.3", - "resolved": "https://registry.npmjs.org/jss/-/jss-9.3.3.tgz", - "integrity": "sha512-hr/x3wHZrk5k6GEMVvxvdajYZ8cx2FeII+dRfsbehcNT9bV5hctXATS45ckDjVGJzBqaKtxhRh+FE/qo05Q1eg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-9.4.0.tgz", + "integrity": "sha512-ckJpElL5CimehboeLDQoHeY7mlxn0KPnPn2EZVbn6pomhfbTXiQJ6fAJXSp9rUM2hPtE0PG8Swzdy9vhB2v82w==", "requires": { "is-in-browser": "1.1.3", - "symbol-observable": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", + "symbol-observable": "1.1.0", "warning": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz" + }, + "dependencies": { + "symbol-observable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.1.0.tgz", + "integrity": "sha512-dQoid9tqQ+uotGhuTKEY11X4xhyYePVnqGSoSm3OGKh2E8LZ6RPULp1uXTctk33IeERlrRJYoVSBglsL05F5Uw==" + } } }, "jss-camel-case": { @@ -2466,27 +2458,20 @@ } }, "jss-default-unit": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.0.tgz", - "integrity": "sha512-tzYgFePQL0neV3Z/oZlbv7XT9Oj2wd3DMjtRYtLGeExSz/SMyVyMhnVtuX01dWUAvA94RhkddvotpdpNDj2Y8g==", - "requires": { - "is-observable": "0.2.0" - } + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/jss-default-unit/-/jss-default-unit-8.0.2.tgz", + "integrity": "sha512-WxNHrF/18CdoAGw2H0FqOEvJdREXVXLazn7PQYU7V6/BWkCV0GkmWsppNiExdw8dP4TU1ma1dT9zBNJ95feLmg==" }, "jss-expand": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.0.0.tgz", - "integrity": "sha512-ndsp+OnIeIc5XIHRFZlLeKNZZW25xqgohhMAyBSUZNZDuUAI9pdod3psHGRaQzyNrU3aMupyBvHnIglBHHgNTg==", - "requires": { - "is-observable": "0.2.0" - } + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/jss-expand/-/jss-expand-5.1.0.tgz", + "integrity": "sha512-WTxmNipgj0V8kr8gc8Gc6Et7uQZH60H7FFNG9zZHjR6TPJoj7TDK+/EBxwRHtCRQD4B8RTwoa7MyEKD4ReKfXw==" }, "jss-extend": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.0.1.tgz", - "integrity": "sha512-PgJRg6zkILmgiA4Ye6P33rTjHAVDx+/dN3syT2JE6EhylfmOYs/2d+MsMxXH+Fkh9wjlvNUiinlu7Mljl+TuXA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jss-extend/-/jss-extend-6.1.0.tgz", + "integrity": "sha512-bSNwLDOZnMxABsUqvq2lwLJ/MMFs8ThligiLZBOUeyoZCoHqAbcTghvunk2QDVxiOhRTDS57VvhXVJZETW58Bw==", "requires": { - "is-observable": "0.2.0", "warning": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz" } }, @@ -2510,9 +2495,9 @@ "requires": { "jss-camel-case": "6.0.0", "jss-compose": "5.0.0", - "jss-default-unit": "8.0.0", - "jss-expand": "5.0.0", - "jss-extend": "6.0.1", + "jss-default-unit": "8.0.2", + "jss-expand": "5.1.0", + "jss-extend": "6.1.0", "jss-global": "3.0.0", "jss-nested": "6.0.1", "jss-props-sort": "6.0.0", @@ -2659,9 +2644,9 @@ } }, "material-ui": { - "version": "1.0.0-beta.22", - "resolved": "https://registry.npmjs.org/material-ui/-/material-ui-1.0.0-beta.22.tgz", - "integrity": "sha512-6P+QssiDdVaHtYNO6wFoEFPzbjS98vsLuBTIuj8Whso7FTqle5Z16GpEsxibbC+MCrC72KECwaew0aR09tWMig==", + "version": "1.0.0-beta.24", + "resolved": "https://registry.npmjs.org/material-ui/-/material-ui-1.0.0-beta.24.tgz", + "integrity": "sha512-tPKQeR9RXXSJFj/QIhU5+mAnnZm5Gk6WcTufbVBDd0946wpfMJA2NY2J+M/SK9NXe+BTTVUCnWY92UCw5YA9tA==", "requires": { "babel-runtime": "6.26.0", "brcast": "3.0.1", @@ -2669,14 +2654,13 @@ "deepmerge": "2.0.1", "dom-helpers": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.2.1.tgz", "hoist-non-react-statics": "2.3.1", - "jss": "9.3.3", + "jss": "9.4.0", "jss-preset-default": "4.0.1", "keycode": "2.1.9", "lodash": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", "normalize-scroll-left": "0.1.2", "prop-types": "15.6.0", - "react-event-listener": "0.5.1", - "react-flow-types": "0.2.0-beta.6", + "react-event-listener": "0.5.2", "react-jss": "8.1.0", "react-popper": "0.7.4", "react-scrollbar-size": "2.0.2", @@ -2692,7 +2676,7 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", - "regenerator-runtime": "0.11.0" + "regenerator-runtime": "0.11.1" } }, "hoist-non-react-statics": { @@ -2701,9 +2685,9 @@ "integrity": "sha1-ND24TGAYxlB3iJgkATWhQg7iLOA=" }, "regenerator-runtime": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" } } }, @@ -3785,9 +3769,9 @@ } }, "react-event-listener": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.5.1.tgz", - "integrity": "sha1-ujYHbke8N8Wmf/XM1Kn/DxViEEA=", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/react-event-listener/-/react-event-listener-0.5.2.tgz", + "integrity": "sha512-E22Sc/PtzVWw/fRidkEy1ZNnpSMJARUVV/5LymsDe4NjIHzNcVpNLV/R2Kt40NN8X6tu/X5p2inCny7vqd97mg==", "requires": { "babel-runtime": "6.26.0", "fbjs": "0.8.16", @@ -3801,7 +3785,7 @@ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", "requires": { "core-js": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz", - "regenerator-runtime": "0.11.0" + "regenerator-runtime": "0.11.1" } }, "fbjs": { @@ -3826,17 +3810,12 @@ } }, "regenerator-runtime": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" } } }, - "react-flow-types": { - "version": "0.2.0-beta.6", - "resolved": "https://registry.npmjs.org/react-flow-types/-/react-flow-types-0.2.0-beta.6.tgz", - "integrity": "sha512-I4f8oJFGxVJYrJLxG4sCPW7vWedNB8Eee1U2v+xBzRPlF7X5IBelqaDIKxBDLzDFb++AzpoU+uu1jFaKy1QssQ==" - }, "react-infinite": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/react-infinite/-/react-infinite-0.12.1.tgz", @@ -3860,7 +3839,7 @@ "integrity": "sha512-AQNM9/desndTeQuvtGp2kkGT2Fy0FeiI1+jkU0ND6vGHbwPKaEnX+RqCkjzgoPdpjmfTa70y8RMp3rao9w25Eg==", "requires": { "hoist-non-react-statics": "2.3.1", - "jss": "9.3.3", + "jss": "9.4.0", "jss-preset-default": "4.0.1", "prop-types": "15.6.0", "theming": "1.2.1" @@ -4006,7 +3985,7 @@ "requires": { "babel-runtime": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz", "prop-types": "15.6.0", - "react-event-listener": "0.5.1" + "react-event-listener": "0.5.2" } }, "react-swipeable-views": { diff --git a/package.json b/package.json index 3e36af6..d22b3c6 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { - "version": "1.4.0-rc.16", + "version": "1.4.0", "name": "galleryplus", - "private": true, + "private": false, "repository": "git@github.com:ShinyLeee/meteor-album-app.git", "author": "shinylee ", "scripts": { @@ -23,7 +23,7 @@ "jsonp": "^0.2.1", "justified-layout": "^2.1.0", "lodash": "^4.17.4", - "material-ui": "^1.0.0-beta.22", + "material-ui": "^1.0.0-beta.24", "material-ui-icons": "^1.0.0-beta.15", "meteor-node-stubs": "~0.2.0", "moment": "^2.15.1",