Merge branch 'master' of github.com:umputun/remark

This commit is contained in:
Umputun
2018-03-04 02:03:06 -06:00
27 changed files with 142 additions and 85 deletions
+5 -3
View File
@@ -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")
}
-6
View File
@@ -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
@@ -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;
}
}
@@ -1,7 +1,7 @@
.comment__action {
margin-left: 8px;
font-weight: 700;
color: #777;
color: #0aa;
cursor: pointer;
&:hover {
@@ -8,5 +8,4 @@
height: $avatarSize;
margin-right: $avatarOffset;
border-radius: 4px;
background: #eee;
}
@@ -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;
}
@@ -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;
}
}
@@ -1,3 +1,4 @@
.comment__username {
color: #06c5c5;
color: #777;
font-weight: 700;
}
@@ -1,6 +1,5 @@
.comment_view_admin {
.comment__username {
font-weight: 700;
color: #ff4700;
};
}
+2 -2
View File
@@ -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 {
<div className="comment__content">
<div className="comment__info">
{/* TODO: add link to user's profile in social if we have it */}
<span className="comment__username">{o.user.name}</span>
<span className="comment__score">
@@ -195,7 +195,7 @@ export default class Comment extends Component {
<span className="comment__time">{o.time}</span>
{
!mods.disabled && (
!mods.disabled && !isGuest && (
<span className="comment__controls">
<span className="comment__action" onClick={this.onReplyClick}>reply</span>
</span>
+1 -2
View File
@@ -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;
}
}
@@ -8,6 +8,7 @@
bottom: 0;
box-sizing: border-box;
width: $buttonWidth;
height: 100%;
padding: 0 10px;
font-size: 16px;
border: 0;
@@ -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);
}
}
}
+5
View File
@@ -0,0 +1,5 @@
export { default } from './preloader';
require('./preloader.scss');
require('./__bounce/preloader__bounce.scss');
@@ -0,0 +1,13 @@
import { h, Component } from 'preact';
export default class Preloader extends Component {
render(props, state) {
return (
<div className={b('preloader', props)}>
<div className="preloader__bounce"/>
<div className="preloader__bounce"/>
<div className="preloader__bounce"/>
</div>
);
}
}
@@ -0,0 +1,5 @@
.preloader {
width: 60px;
text-align: center;
font-size: 0;
}
@@ -1,3 +0,0 @@
.root__auth-panel {
margin-bottom: 4px;
}
@@ -1,3 +1,3 @@
.root__input {
margin-bottom: 24px;
margin-top: 4px;
}
@@ -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;
@@ -0,0 +1,6 @@
.root__preloader {
position: absolute;
left: 0;
right: 0;
margin: 0 auto;
}
@@ -0,0 +1,3 @@
.root__threads {
margin-top: 24px;
}
@@ -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.';
}
}
}
+2 -3
View File
@@ -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');
+28 -15
View File
@@ -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 (
<div id={NODE_ID}>
<div className="root root_loading"/>
<div className="root">
<Preloader mix="root__preloader"/>
</div>
</div>
);
}
// TODO: i think we should do it on backend
const pinnedComments = store.getPinnedComments();
const isGuest = !Object.keys(user).length;
return (
<div id={NODE_ID}>
<div className="root root__loading">
<div className="root">
<AuthPanel
mix="root__auth-panel"
user={user}
providers={config.auth_providers}
onSignIn={this.onSignIn}
onSignOut={this.onSignOut}
/>
<Input
mix="root__input"
onSubmit={this.addComment}
/>
{
!isGuest && (
<Input
mix="root__input"
onSubmit={this.addComment}
/>
)
}
{
!!pinnedComments.length && (
@@ -132,14 +139,20 @@ export default class Root extends Component {
}
{
comments.map(thread => (
<Thread
mix="root__thread"
mods={{ level: 0 }}
data={thread}
onReply={this.addComment}
/>
))
!!comments.length && (
<div className="root__threads">
{
comments.map(thread => (
<Thread
mix="root__thread"
mods={{ level: 0 }}
data={thread}
onReply={this.addComment}
/>
))
}
</div>
)
}
</div>
</div>
+1
View File
@@ -1,3 +1,4 @@
.root {
position: relative;
font-family: 'PT Sans', Helvetica, Arial, sans-serif;
}
+1 -1
View File
@@ -1,5 +1,5 @@
@import 'common/variables';
.thread {
margin-bottom: $offset;
margin-bottom: $offset / 2;
}
+1 -1
View File
@@ -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'),
]
}