diff --git a/app/store/bolt.go b/app/store/bolt.go index 448ad9b6..81393e2f 100644 --- a/app/store/bolt.go +++ b/app/store/bolt.go @@ -39,6 +39,8 @@ const ( userLimit = 50 ) +const tsNano = "2006-01-02T15:04:05.000000000Z07:00" + // BoltSite defines single site param type BoltSite struct { FileName string // full path to boltdb @@ -117,7 +119,7 @@ func (b *BoltDB) Create(comment Comment) (commentID string, err error) { // add reference to comment to "last" bucket lastBkt := tx.Bucket([]byte(lastBucketName)) ref := b.makeRef(comment) - commentTs := []byte(comment.Timestamp.Format(time.RFC3339Nano)) + commentTs := []byte(comment.Timestamp.Format(tsNano)) e = lastBkt.Put(commentTs, ref) if e != nil { return errors.Wrapf(e, "can't put reference %s to %s", ref, lastBucketName) @@ -288,7 +290,7 @@ func (b *BoltDB) SetBlock(siteID string, userID string, status bool) error { bucket := tx.Bucket([]byte(blocksBucketName)) switch status { case true: - if e := bucket.Put([]byte(userID), []byte(time.Now().Format(time.RFC3339Nano))); e != nil { + if e := bucket.Put([]byte(userID), []byte(time.Now().Format(tsNano))); e != nil { return errors.Wrapf(e, "failed to put %s to %s", userID, blocksBucketName) } case false: @@ -328,7 +330,7 @@ func (b *BoltDB) Blocked(siteID string) (users []BlockedUser, err error) { err = bdb.View(func(tx *bolt.Tx) error { bucket := tx.Bucket([]byte(blocksBucketName)) return bucket.ForEach(func(k []byte, v []byte) error { - ts, e := time.ParseInLocation(time.RFC3339Nano, string(v), time.Local) + ts, e := time.ParseInLocation(tsNano, string(v), time.Local) if e != nil { return errors.Wrap(e, "can't parse block ts") } diff --git a/web/TODO.md b/web/TODO.md index 27c0714c..d2a48ea9 100644 --- a/web/TODO.md +++ b/web/TODO.md @@ -1,15 +1,9 @@ major features: - improve design - - add true preloader - - disable inputs for guests - - hide reply links for guests - check mobile ui - add icons for social networks - - remove grey avatars 'cause we have default img - add time format 'X hours ago' - - use static buttons 'reply', 'pin', etc instead of dynamic - - maybe we should change layout: vote buttons | avatar | info; info: (top: name, points, time), (center: text), (bottom: controls) - edit comment - `PUT /api/v1/comment/{id}?site=site-id&url=post-url` - add description of web part to readme diff --git a/web/app/components/auth-panel/__pseudo-link/auth-panel__pseudo-link.scss b/web/app/components/auth-panel/__pseudo-link/auth-panel__pseudo-link.scss index d81c8d3a..fa9a37f0 100644 --- a/web/app/components/auth-panel/__pseudo-link/auth-panel__pseudo-link.scss +++ b/web/app/components/auth-panel/__pseudo-link/auth-panel__pseudo-link.scss @@ -1,6 +1,11 @@ .auth-panel__pseudo-link { display: inline-block; + font-weight: 700; white-space: nowrap; cursor: pointer; - color: #06c5c5; + color: #0aa; + + &:hover { + color: #06c5c5; + } } diff --git a/web/app/components/comment/__action/comment__action.scss b/web/app/components/comment/__action/comment__action.scss index fb24d978..3cd88b8a 100644 --- a/web/app/components/comment/__action/comment__action.scss +++ b/web/app/components/comment/__action/comment__action.scss @@ -1,7 +1,7 @@ .comment__action { margin-left: 8px; font-weight: 700; - color: #777; + color: #0aa; cursor: pointer; &:hover { diff --git a/web/app/components/comment/__avatar/comment__avatar.scss b/web/app/components/comment/__avatar/comment__avatar.scss index 44e08462..124aeaa5 100644 --- a/web/app/components/comment/__avatar/comment__avatar.scss +++ b/web/app/components/comment/__avatar/comment__avatar.scss @@ -8,5 +8,4 @@ height: $avatarSize; margin-right: $avatarOffset; border-radius: 4px; - background: #eee; } diff --git a/web/app/components/comment/__controls/comment__controls.scss b/web/app/components/comment/__controls/comment__controls.scss index 5e41f63c..f8f97d0d 100644 --- a/web/app/components/comment/__controls/comment__controls.scss +++ b/web/app/components/comment/__controls/comment__controls.scss @@ -3,8 +3,6 @@ user-select: none; @media (hover: hover) { - margin-left: 0; - transition: transform .2s .1s ease-out, opacity .2s .1s ease-out; font-weight: 700; opacity: 0; } diff --git a/web/app/components/comment/__text/comment__text.scss b/web/app/components/comment/__text/comment__text.scss index c0f50581..bc03e370 100644 --- a/web/app/components/comment/__text/comment__text.scss +++ b/web/app/components/comment/__text/comment__text.scss @@ -5,7 +5,28 @@ margin: 0; + p { - margin-top: 5px; + margin-top: 8px; + } + + // imported comments have br instead of p + br { + content: ''; + display: block; + margin-top: 8px; } } + + a { + color: #0aa; + + &:hover { + color: #06c5c5; + text-decoration: none; + } + } + + img { + max-width: 100%; + max-height: 300px; + } } diff --git a/web/app/components/comment/__username/comment__username.scss b/web/app/components/comment/__username/comment__username.scss index 1546489b..75f1b9ed 100644 --- a/web/app/components/comment/__username/comment__username.scss +++ b/web/app/components/comment/__username/comment__username.scss @@ -1,3 +1,4 @@ .comment__username { - color: #06c5c5; + color: #777; + font-weight: 700; } diff --git a/web/app/components/comment/_view/_admin/comment_view_admin.scss b/web/app/components/comment/_view/_admin/comment_view_admin.scss index 5ab3a17c..9d24f9da 100644 --- a/web/app/components/comment/_view/_admin/comment_view_admin.scss +++ b/web/app/components/comment/_view/_admin/comment_view_admin.scss @@ -1,6 +1,5 @@ .comment_view_admin { .comment__username { - font-weight: 700; color: #ff4700; }; } diff --git a/web/app/components/comment/comment.jsx b/web/app/components/comment/comment.jsx index eb50fc25..9df571cf 100644 --- a/web/app/components/comment/comment.jsx +++ b/web/app/components/comment/comment.jsx @@ -141,6 +141,7 @@ export default class Comment extends Component { render(props, { userBlocked, pinned, score, scoreIncreased, scoreDecreased, isInputVisible }) { const { data, mix, mods = {} } = props; const isAdmin = store.get('user').admin; + const isGuest = !Object.keys(store.get('user')).length; const time = new Date(data.time); // TODO: which format for datetime should we choose? @@ -176,7 +177,6 @@ export default class Comment extends Component {
- {/* TODO: add link to user's profile in social if we have it */} {o.user.name} @@ -195,7 +195,7 @@ export default class Comment extends Component { {o.time} { - !mods.disabled && ( + !mods.disabled && !isGuest && ( reply diff --git a/web/app/components/comment/comment.scss b/web/app/components/comment/comment.scss index 9fd079b8..bf3711e0 100644 --- a/web/app/components/comment/comment.scss +++ b/web/app/components/comment/comment.scss @@ -3,14 +3,13 @@ .comment { position: relative; overflow: hidden; - margin-bottom: $offset; + margin-bottom: $offset / 2; font-size: 16px; line-height: 1.2; @media (hover: hover) { &:hover { .comment__controls { - transform: translateX(8px); opacity: 1; } } diff --git a/web/app/components/input/__button/input__button.scss b/web/app/components/input/__button/input__button.scss index 6cf3f2c8..ffd4c323 100644 --- a/web/app/components/input/__button/input__button.scss +++ b/web/app/components/input/__button/input__button.scss @@ -8,6 +8,7 @@ bottom: 0; box-sizing: border-box; width: $buttonWidth; + height: 100%; padding: 0 10px; font-size: 16px; border: 0; diff --git a/web/app/components/preloader/__bounce/preloader__bounce.scss b/web/app/components/preloader/__bounce/preloader__bounce.scss new file mode 100644 index 00000000..009c0c7d --- /dev/null +++ b/web/app/components/preloader/__bounce/preloader__bounce.scss @@ -0,0 +1,35 @@ +.preloader__bounce { + display: inline-block; + width: 10px; + height: 10px; + margin-right: 3px; + background-color: #333; + border-radius: 100%; + animation: preloaderBounce 1.4s infinite ease-in-out both; + + &:first-child { + animation-delay: -.32s; + } + + &:nth-child(2) { + animation-delay: -.16s; + } + + &:last-child { + margin-right: 0; + } + + @keyframes preloaderBounce { + 0% { + transform: scale(0); + } + + 40% { + transform: scale(1); + } + + 80%, 100% { + transform: scale(0); + } + } +} diff --git a/web/app/components/preloader/index.js b/web/app/components/preloader/index.js new file mode 100644 index 00000000..74d4e5b1 --- /dev/null +++ b/web/app/components/preloader/index.js @@ -0,0 +1,5 @@ +export { default } from './preloader'; + +require('./preloader.scss'); + +require('./__bounce/preloader__bounce.scss'); diff --git a/web/app/components/preloader/preloader.jsx b/web/app/components/preloader/preloader.jsx new file mode 100644 index 00000000..e2ab0ed5 --- /dev/null +++ b/web/app/components/preloader/preloader.jsx @@ -0,0 +1,13 @@ +import { h, Component } from 'preact'; + +export default class Preloader extends Component { + render(props, state) { + return ( +
+
+
+
+
+ ); + } +} diff --git a/web/app/components/preloader/preloader.scss b/web/app/components/preloader/preloader.scss new file mode 100644 index 00000000..932b616b --- /dev/null +++ b/web/app/components/preloader/preloader.scss @@ -0,0 +1,5 @@ +.preloader { + width: 60px; + text-align: center; + font-size: 0; +} diff --git a/web/app/components/root/__auth-panel/root__auth-panel.scss b/web/app/components/root/__auth-panel/root__auth-panel.scss deleted file mode 100644 index 1bda3eb6..00000000 --- a/web/app/components/root/__auth-panel/root__auth-panel.scss +++ /dev/null @@ -1,3 +0,0 @@ -.root__auth-panel { - margin-bottom: 4px; -} diff --git a/web/app/components/root/__input/root__input.scss b/web/app/components/root/__input/root__input.scss index 2440c942..cfa788fd 100644 --- a/web/app/components/root/__input/root__input.scss +++ b/web/app/components/root/__input/root__input.scss @@ -1,3 +1,3 @@ .root__input { - margin-bottom: 24px; + margin-top: 4px; } diff --git a/web/app/components/root/__pinned-comments/root__pinned-comments.scss b/web/app/components/root/__pinned-comments/root__pinned-comments.scss index 7ffef917..547c776a 100644 --- a/web/app/components/root/__pinned-comments/root__pinned-comments.scss +++ b/web/app/components/root/__pinned-comments/root__pinned-comments.scss @@ -1,7 +1,7 @@ @import 'common/variables'; .root__pinned-comments { - margin-bottom: $offset * 2; + margin-top: 24px; padding: ($offset / 3) ($offset / 2); border: 2px solid #0aa; border-radius: 4px; diff --git a/web/app/components/root/__preloader/root__preloader.scss b/web/app/components/root/__preloader/root__preloader.scss new file mode 100644 index 00000000..77af553b --- /dev/null +++ b/web/app/components/root/__preloader/root__preloader.scss @@ -0,0 +1,6 @@ +.root__preloader { + position: absolute; + left: 0; + right: 0; + margin: 0 auto; +} diff --git a/web/app/components/root/__threads/root__threads.scss b/web/app/components/root/__threads/root__threads.scss new file mode 100644 index 00000000..b3e37227 --- /dev/null +++ b/web/app/components/root/__threads/root__threads.scss @@ -0,0 +1,3 @@ +.root__threads { + margin-top: 24px; +} diff --git a/web/app/components/root/_loading/root_loading.scss b/web/app/components/root/_loading/root_loading.scss deleted file mode 100644 index 4674958e..00000000 --- a/web/app/components/root/_loading/root_loading.scss +++ /dev/null @@ -1,39 +0,0 @@ -// TODO: add true preloader - -.root_loading { - position: relative; - height: 3em; - - &::after { - content: 'Loading..'; - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - margin: auto; - animation: rootLoading 1s infinite; - } - - @keyframes rootLoading { - 0% { - content: 'Loading..'; - } - - 25% { - content: 'Loading...'; - } - - 50% { - content: 'Loading..'; - } - - 75% { - content: 'Loading.'; - } - - 100% { - content: 'Loading.'; - } - } -} diff --git a/web/app/components/root/index.js b/web/app/components/root/index.js index 387778d4..b2eef646 100644 --- a/web/app/components/root/index.js +++ b/web/app/components/root/index.js @@ -2,10 +2,9 @@ export { default } from './root'; require('./root.scss'); -require('./__auth-panel/root__auth-panel.scss'); require('./__input/root__input.scss'); +require('./__preloader/root__preloader.scss'); require('./__pinned-comment/root__pinned-comment.scss'); require('./__pinned-comments/root__pinned-comments.scss'); require('./__thread/root__thread.scss'); - -require('./_loading/root_loading.scss'); +require('./__threads/root__threads.scss'); diff --git a/web/app/components/root/root.jsx b/web/app/components/root/root.jsx index e7c280e4..52a0f1a7 100644 --- a/web/app/components/root/root.jsx +++ b/web/app/components/root/root.jsx @@ -8,6 +8,7 @@ import store from 'common/store'; import AuthPanel from 'components/auth-panel'; import Comment from 'components/comment'; import Input from 'components/input'; +import Preloader from 'components/preloader'; import Thread from 'components/thread'; export default class Root extends Component { @@ -91,29 +92,35 @@ export default class Root extends Component { if (!loaded) { return (
-
+
+ +
); } // TODO: i think we should do it on backend const pinnedComments = store.getPinnedComments(); + const isGuest = !Object.keys(user).length; return (
-
+
- + { + !isGuest && ( + + ) + } { !!pinnedComments.length && ( @@ -132,14 +139,20 @@ export default class Root extends Component { } { - comments.map(thread => ( - - )) + !!comments.length && ( +
+ { + comments.map(thread => ( + + )) + } +
+ ) }
diff --git a/web/app/components/root/root.scss b/web/app/components/root/root.scss index f5122fac..848f0443 100644 --- a/web/app/components/root/root.scss +++ b/web/app/components/root/root.scss @@ -1,3 +1,4 @@ .root { + position: relative; font-family: 'PT Sans', Helvetica, Arial, sans-serif; } diff --git a/web/app/components/thread/thread.scss b/web/app/components/thread/thread.scss index 59307364..a8149d32 100644 --- a/web/app/components/thread/thread.scss +++ b/web/app/components/thread/thread.scss @@ -1,5 +1,5 @@ @import 'common/variables'; .thread { - margin-bottom: $offset; + margin-bottom: $offset / 2; } diff --git a/web/webpack.config.js b/web/webpack.config.js index bffb9ec3..33bcf282 100644 --- a/web/webpack.config.js +++ b/web/webpack.config.js @@ -21,7 +21,7 @@ const commonStyleLoaders = [ plugins: [ require('autoprefixer')({ browsers: ['> 1%'] }), require('postcss-url')({ url: 'inline', maxSize: 5 }), - require('postcss-wrap')({ selector: `#${NODE_ID}` }), + require('postcss-wrap')({ selector: `#${NODE_ID}` , skip: /^html|body$/}), require('postcss-csso'), ] }