Merge pull request #1615 from urbit/publish-fixes

Publish: various fixes and improvements
This commit is contained in:
ixv 2019-08-13 16:17:52 -07:00 committed by GitHub
commit 55d8fe978a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 243 additions and 131 deletions

View File

@ -1268,7 +1268,13 @@
::
%read
=. unread.sat (~(del in unread.sat) who.act coll.act post.act)
[make-tile-moves this]
:_ this
%+ welp make-tile-moves
::
%+ turn (prey:pubsub:userlib /primary bol)
|= [b=bone *]
^- move
[b %diff %publish-update %unread %.n (sy [who.act coll.act post.act] ~)]
::
==
::

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -84,6 +84,11 @@
[%base %talk]
[%base %dojo]
[%base %modulo]
[%home %launch]
[%home %chat]
[%home %publish]
[%home %clock]
[%home %weather]
==
:~ [%home %lens]
[%home %acme]

View File

@ -47,7 +47,7 @@
::
++ new-collection
%- ot:dejs
:~ name+(su:dejs sym)
:~ name+so:dejs
title+so:dejs
comments+comment-config
allow-edit+edit-config
@ -57,8 +57,8 @@
++ new-post
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
name+(su:dejs sym)
coll+so:dejs
name+so:dejs
title+so:dejs
comments+comment-config
perm+perm-config
@ -68,40 +68,40 @@
++ new-comment
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
coll+so:dejs
name+(su:dejs sym)
content+so:dejs
==
::
++ delete-collection
%- ot:dejs
:~ coll+(su:dejs sym)
:~ coll+so:dejs
==
::
++ delete-post
%- ot:dejs
:~ coll+(su:dejs sym)
post+(su:dejs sym)
:~ coll+so:dejs
post+so:dejs
==
::
++ delete-comment
%- ot:dejs
:~ coll+(su:dejs sym)
post+(su:dejs sym)
comment+(su:dejs sym)
:~ coll+so:dejs
post+so:dejs
comment+so:dejs
==
::
++ edit-collection
%- ot:dejs
:~ name+(su:dejs sym)
:~ name+so:dejs
title+so:dejs
==
::
++ edit-post
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
name+(su:dejs sym)
coll+so:dejs
name+so:dejs
title+so:dejs
comments+comment-config
perm+perm-config
@ -110,9 +110,9 @@
::
++ edit-comment
%- ot:dejs
:~ coll+(su:dejs sym)
name+(su:dejs sym)
id+(su:dejs sym)
:~ coll+so:dejs
name+so:dejs
id+so:dejs
content+so:dejs
==
::
@ -147,7 +147,7 @@
::
++ invite
%- ot:dejs
:~ coll+(su:dejs sym)
:~ coll+so:dejs
title+so:dejs
who+(ar:dejs (su:dejs fed:ag))
==
@ -155,36 +155,36 @@
++ reject-invite
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
coll+so:dejs
==
::
++ serve
%- ot:dejs
:~ coll+(su:dejs sym)
:~ coll+so:dejs
==
::
++ unserve
%- ot:dejs
:~ coll+(su:dejs sym)
:~ coll+so:dejs
==
::
++ subscribe
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
coll+so:dejs
==
::
++ unsubscribe
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
coll+so:dejs
==
::
++ read
%- ot:dejs
:~ who+(su:dejs fed:ag)
coll+(su:dejs sym)
post+(su:dejs sym)
coll+so:dejs
post+so:dejs
==
::
--

View File

@ -19,6 +19,21 @@
[%coll s+col.upd]
[%title s+title.upd]
==
::
%unread
%- pairs
:~ [%add b+add.upd]
:+ %posts
%a
%+ turn ~(tap in keys.upd)
|= [who=@p coll=@tas post=@tas]
^- ^json
%- pairs
:~ [%who (ship who)]
[%coll s+coll]
[%post s+post]
==
==
::
==
::

View File

@ -108,5 +108,6 @@
::
+$ update
$% [%invite add=? who=@p col=@tas title=@t]
[%unread add=? keys=(set [who=@p coll=@tas post=@tas])]
==
--

View File

@ -1,6 +1,5 @@
import React, { Component } from 'react';
import classnames from 'classnames';
import { PostPreview } from '/components/lib/post-preview';
import _ from 'lodash';
import { PathControl } from '/components/lib/path-control';
import { BlogData } from '/components/lib/blog-data';
@ -82,8 +81,8 @@ export class Blog extends Component {
let blogId = this.props.blogId;
let blog = (ship === window.ship)
? _.get(this.props, `pubs[${blogId}]`, false)
: _.get(this.props, `subs[${ship}][${blogId}]`, false);
? _.get(this.props, `pubs["${blogId}"]`, false)
: _.get(this.props, `subs["${ship}"]["${blogId}"]`, false);
if (!(blog) && (ship === window.ship)) {
@ -110,8 +109,8 @@ export class Blog extends Component {
let ship = this.props.ship;
let blogId = this.props.blogId;
let blog = (ship == window.ship)
? _.get(this.props, `pubs[${blogId}]`, false)
: _.get(this.props, `subs[${ship}][${blogId}]`, false);
? _.get(this.props, `pubs["${blogId}"]`, false)
: _.get(this.props, `subs["${ship}"]["${blogId}"]`, false);
if (!(blog) && (ship === window.ship)) {
this.setState({notFound: true});
@ -158,6 +157,13 @@ export class Blog extends Component {
}
buildPostPreviewProps(post, blog, pinned){
let unread = (-1 === _.findIndex(this.props.unread, {
post: post.post.info.filename,
coll: blog.info.filename,
who: blog.info.owner.slice(1),
}))
? false: true;
return {
postTitle: post.post.info.title,
postName: post.post.info.filename,
@ -169,13 +175,14 @@ export class Blog extends Component {
blogOwner: blog.info.owner,
date: post.post.info["date-created"],
pinned: pinned,
unread: unread,
}
}
buildData(){
let blog = (this.props.ship == window.ship)
? _.get(this.props, `pubs[${this.props.blogId}]`, false)
: _.get(this.props, `subs[${this.props.ship}][${this.props.blogId}]`, false);
? _.get(this.props, `pubs["${this.props.blogId}"]`, false)
: _.get(this.props, `subs["${this.props.ship}"]["${this.props.blogId}"]`, false);
if (this.state.temporary) {
return {
@ -228,17 +235,14 @@ export class Blog extends Component {
}
viewSubs() {
console.log("view subs");
this.setState({view: 'subs'});
}
viewSettings() {
console.log("view settings");
this.setState({view: 'settings'});
}
viewNotes() {
console.log("view notes");
this.setState({view: 'notes'});
}
@ -259,7 +263,7 @@ export class Blog extends Component {
let subNum = _.get(data.blog, 'subscribers.length', 0);
let foreign = _.get(this.props,
`subs[${this.props.ship}][${this.props.blogId}]`, false);
`subs["${this.props.ship}"]["${this.props.blogId}"]`, false);
let actionType = false;
if (this.state.temporary) {

View File

@ -6,9 +6,6 @@ export class Sigil extends Component {
render() {
const { props } = this;
console.log("sigil ship", props.ship);
if (props.ship.length > 14) {
return (
<div className="bg-black" style={{width: 44, height: 44}}>

View File

@ -64,13 +64,14 @@ class Preview extends Component {
return (
<div className="w-336">
<Link className="ml2 mr2 gray-50 body-regular" to={prevUrl}>
<Link className="ml2 mr2 gray-50 body-regular db mb3" to={prevUrl}>
{this.props.text}
</Link>
<div className="w-336 relative"
style={{height:195}}>
<Link to={postLink}>
<TitleSnippet title={previewProps.postTitle}/>
style={{height:210}}>
<Link to={postLink} className="db">
<TitleSnippet badge={false} title={previewProps.postTitle} />
<div className="w-100" style={{height:16}}></div>
<PostSnippet
body={previewProps.postBody}
/>

View File

@ -31,9 +31,9 @@ export class PathControl extends Component {
if ((last.lastMatch === '/~publish/:ship/:blog/:post') ||
(last.lastMatch === '/~publish/:ship/:blog')){
blog = (last.lastParams.ship.slice(1) == window.ship)
? _.get(this.props, `pubs[${last.lastParams.blog}]`, false)
? _.get(this.props, `pubs["${last.lastParams.blog}"]`, false)
: _.get(this.props,
`subs[${last.lastParams.ship.slice(1)}][${last.lastParams.blog}]`, false);
`subs["${last.lastParams.ship.slice(1)}"]["${last.lastParams.blog}"]`, false);
}
}

View File

@ -59,6 +59,11 @@ export class PostBody extends Component {
return element;
}
renderHR(what, node, attr, parentNode) {
const element = React.createElement(node, attr);
return element;
}
renderDefault(what, node, attr, parentNode) {
let dStyle = {
wordWrap: "break-word",
@ -84,6 +89,8 @@ export class PostBody extends Component {
return this.renderIMG(what, node, attr, parentNode);
case "p":
return this.renderP(what, node, attr, parentNode);
case "hr":
return this.renderHR(what, node, attr, parentNode);
default:
return this.renderDefault(what, node, attr, parentNode);
}

View File

@ -47,7 +47,7 @@ export class PostPreview extends Component {
<div className="w-336 relative"
style={{height:195, marginBottom: 72, marginRight:16}}>
<Link to={postLink}>
<TitleSnippet title={this.props.post.postTitle}/>
<TitleSnippet badge={this.props.post.unread} title={this.props.post.postTitle}/>
<PostSnippet
body={this.props.post.postBody}
/>

View File

@ -47,7 +47,7 @@ export class RecentPreview extends Component {
<div className="w-336 relative"
style={{height:240, marginBottom: 72, marginRight: 16}}>
<Link to={postLink}>
<TitleSnippet title={this.props.post.postTitle}/>
<TitleSnippet badge={this.props.post.unread} title={this.props.post.postTitle}/>
<PostSnippet
body={this.props.post.postBody}
/>

View File

@ -7,12 +7,24 @@ export class TitleSnippet extends Component {
}
render() {
return (
<p className="body-large b two-lines"
style={{WebkitBoxOrient: "vertical"}}>
{this.props.title}
</p>
);
if (this.props.badge) {
return (
<div className="body-large two-lines b"
style={{WebkitBoxOrient: "vertical"}}>
<span className="h2 green-medium"></span>
<span>
{this.props.title}
</span>
</div>
);
} else {
return (
<p className="body-large b two-lines"
style={{WebkitBoxOrient: "vertical"}}>
{this.props.title}
</p>
);
}
}
}

View File

@ -4,6 +4,7 @@ import { Link } from 'react-router-dom';
import { PathControl } from '/components/lib/path-control';
import { withRouter } from 'react-router';
import urbitOb from 'urbit-ob';
import { stringToSymbol } from '/lib/util';
const PC = withRouter(PathControl);
@ -39,30 +40,14 @@ export class NewBlog extends Component {
this.returnHome = this.returnHome.bind(this);
this.addInvites = this.addInvites.bind(this);
this.blogSubmit = this.blogSubmit.bind(this);
}
stringToSymbol(str){
let result = '';
for (var i=0; i<str.length; i++){
var n = str.charCodeAt(i);
if (( (n >= 97) && (n <= 122) ) ||
( (n >= 48) && (n <= 57) ))
{
result += str[i];
} else if ( (n >= 65) && (n <= 90) )
{
result += String.fromCharCode(n + 32);
} else {
result += '-';
}
}
return result.replace(/^\-+|\-+$/g, '');
this.titleHeight = 52;
}
blogSubmit() {
let ship = window.ship;
let blogTitle = this.state.title;
let blogId = this.stringToSymbol(blogTitle);
let blogId = stringToSymbol(blogTitle);
let permissions = {
read: {
@ -126,6 +111,11 @@ export class NewBlog extends Component {
}
titleChange(evt){
this.titleInput.style.height = 'auto';
this.titleInput.style.height = (this.titleInput.scrollHeight < 52)
? 52 : this.titleInput.scrollHeight;
this.titleHeight = this.titleInput.style.height;
this.setState({title: evt.target.value});
}
@ -172,13 +162,16 @@ export class NewBlog extends Component {
style={{height: 'calc(100% - 124px)', top: 124}}>
<div className="h-inner dt center mw-688 w-100">
<div className="flex-col dtc v-mid">
<input autoFocus
className="header-2 b--none"
<textarea autoFocus
ref={(el) => {this.titleInput = el}}
className="header-2 b--none w-100"
style={{resize:"none", height: this.titleHeight}}
rows={1}
type="text"
name="blogName"
placeholder="Add a Title"
onChange={this.titleChange}
/>
onChange={this.titleChange}>
</textarea>
<hr className="gray-30" style={{marginTop:32, marginBottom: 32}}/>
@ -219,13 +212,16 @@ export class NewBlog extends Component {
style={{height: 'calc(100% - 124px)', top: 124}}>
<div className="h-inner dt center mw-688 w-100">
<div className="flex-col dtc v-mid">
<input autoFocus
className="header-2 b--none"
<textarea autoFocus
ref={(el) => {this.titleInput = el}}
className="header-2 b--none w-100"
style={{resize:"none", height: this.titleHeight}}
rows={1}
type="text"
name="blogName"
placeholder="Add a Title"
onChange={this.titleChange}
/>
onChange={this.titleChange}>
</textarea>
<p className="body-regular-400" style={{marginTop:25, marginBottom:27}}>
Who is invited to read this notebook?

View File

@ -4,6 +4,7 @@ import { Link } from 'react-router-dom';
import _ from 'lodash';
import { PathControl } from '/components/lib/path-control';
import { withRouter } from 'react-router';
import { stringToSymbol } from '/lib/util';
const PC = withRouter(PathControl);
@ -67,8 +68,6 @@ export class NewPost extends Component {
constructor(props){
super(props);
console.log("props", this.props);
this.state = {
title: "",
body: "",
@ -92,24 +91,6 @@ export class NewPost extends Component {
this.comments = false;
}
stringToSymbol(str){
let result = '';
for (var i=0; i<str.length; i++){
var n = str.charCodeAt(i);
if (( (n >= 97) && (n <= 122) ) ||
( (n >= 48) && (n <= 57) ))
{
result += str[i];
} else if ( (n >= 65) && (n <= 90) )
{
result += String.fromCharCode(n + 32);
} else {
result += '-';
}
}
return result.replace(/^\-+|\-+$/g, '');
}
postSubmit() {
let last = _.get(this.props, 'location.state', false);
let ship = window.ship;
@ -121,7 +102,7 @@ export class NewPost extends Component {
}
let postTitle = this.state.title;
let postId = this.stringToSymbol(postTitle);
let postId = stringToSymbol(postTitle);
let awaiting = Object.assign({}, {
ship: ship,
@ -202,17 +183,17 @@ export class NewPost extends Component {
if (ship == window.ship) {
post =
_.get(this.props,
`pubs[${blogId}].posts[${postId}].post`, false) || false;
`pubs["${blogId}"].posts["${postId}"].post`, false) || false;
comments =
_.get(this.props,
`pubs[${blogId}].posts[${postId}].comments`, false) || false;
`pubs["${blogId}"].posts["${postId}"].comments`, false) || false;
} else {
post =
_.get(this.props,
`subs[${ship}][${blogId}].posts[${postId}].post`, false) || false;
`subs["${ship}"]["${blogId}"].posts["${postId}"].post`, false) || false;
comments =
_.get(this.props,
`subs[${ship}][${blogId}].posts[${postId}].comments`, false) || false;
`subs["${ship}"]["${blogId}"].posts["${postId}"].comments`, false) || false;
}
if (!_.isEqual(this.post, post)) {

View File

@ -1,6 +1,5 @@
import React, { Component } from 'react';
import classnames from 'classnames';
import { PostPreview } from '/components/lib/post-preview';
import moment from 'moment';
import { Link } from 'react-router-dom';
import { PostBody } from '/components/lib/post-body';
@ -159,11 +158,11 @@ export class Post extends Component {
if (ship !== window.ship) {
let blog = _.get(this.props, `subs[${ship}][${blogId}]`, false);
let blog = _.get(this.props, `subs["${ship}"]["${blogId}"]`, false);
if (blog) {
let post = _.get(blog, `posts[${postId}].post`, false);
let comments = _.get(blog, `posts[${postId}].comments`, false);
let post = _.get(blog, `posts["${postId}"].post`, false);
let comments = _.get(blog, `posts["${postId}"].comments`, false);
let blogUrl = `/~publish/${blog.info.owner}/${blog.info.filename}`;
let postUrl = `${blogUrl}/${post.info.filename}`;
@ -208,9 +207,9 @@ export class Post extends Component {
this.handleError.bind(this));
}
} else {
let blog = _.get(this.props, `pubs[${blogId}]`, false);
let post = _.get(blog, `posts[${postId}].post`, false);
let comments = _.get(blog, `posts[${postId}].comments`, false);
let blog = _.get(this.props, `pubs["${blogId}"]`, false);
let post = _.get(blog, `posts["${postId}"].post`, false);
let comments = _.get(blog, `posts["${postId}"].comments`, false);
if (!blog || !post) {
this.setState({notFound: true});
@ -303,13 +302,13 @@ export class Post extends Component {
let blog;
if (ship === window.ship) {
blog = _.get(this.props, `pubs[${blogId}]`, false);
post = _.get(blog, `posts[${postId}].post`, false);
comments = _.get(blog, `posts[${postId}].comments`, false);
blog = _.get(this.props, `pubs["${blogId}"]`, false);
post = _.get(blog, `posts["${postId}"].post`, false);
comments = _.get(blog, `posts["${postId}"].comments`, false);
} else {
blog = _.get(this.props, `subs[${ship}][${blogId}]`, false);
post = _.get(blog, `posts[${postId}].post`, false);
comments = _.get(blog, `posts[${postId}].comments`, false);
blog = _.get(this.props, `subs["${ship}"]["${blogId}"]`, false);
post = _.get(blog, `posts["${postId}"].post`, false);
comments = _.get(blog, `posts["${postId}"].comments`, false);
}
@ -329,6 +328,9 @@ export class Post extends Component {
((post.info.title != oldPost.info.title) ||
(post.raw != oldPost.raw))) {
let blogUrl = `/~publish/${blog.info.owner}/${blog.info.filename}`;
let postUrl = `${blogUrl}/${post.info.filename}`;
this.setState({
mode: 'view',
titleOriginal: post.info.title,
@ -337,18 +339,49 @@ export class Post extends Component {
body: post.raw,
awaitingEdit: false,
post: post,
pathData: [
{ text: "Home", url: "/~publish/recent" },
{ text: blog.info.title, url: blogUrl },
{ text: post.info.title, url: postUrl },
],
});
this.props.setSpinner(false);
let read = {
read: {
who: ship,
coll: blogId,
post: postId,
}
};
this.props.api.action("publish", "publish-action", read);
}
if (!this.state.temporary){
if (oldPost != post) {
let blogUrl = `/~publish/${blog.info.owner}/${blog.info.filename}`;
let postUrl = `${blogUrl}/${post.info.filename}`;
this.setState({
titleOriginal: post.info.title,
bodyOriginal: post.raw,
post: post,
pathData: [
{ text: "Home", url: "/~publish/recent" },
{ text: blog.info.title, url: blogUrl },
{ text: post.info.title, url: postUrl },
],
});
let read = {
read: {
who: ship,
coll: blogId,
post: postId,
}
};
this.props.api.action("publish", "publish-action", read);
}
if (oldComments != comments) {
this.setState({comments: comments});

View File

@ -51,6 +51,13 @@ export class Recent extends Component {
let col = this.retrieveColl(coll, who);
let com = this.retrieveComments(post, coll, who);
let unread = (-1 === _.findIndex(this.props.unread, {
post: post,
coll: coll,
who: who,
}))
? false: true;
return {
postTitle: pos.info.title,
postName: post,
@ -60,7 +67,8 @@ export class Recent extends Component {
collectionName: coll,
author: pos.info.creator.slice(1),
blogOwner: who,
date: pos.info["date-created"]
date: pos.info["date-created"],
unread: unread,
}
}

View File

@ -1,9 +1,6 @@
import React, { Component } from 'react';
import { BrowserRouter, Route } from "react-router-dom";
import Mousetrap from 'mousetrap';
import classnames from 'classnames';
import _ from 'lodash';
import { api } from '/api';
import { store } from '/store';
import { Recent } from '/components/recent';

View File

@ -0,0 +1,38 @@
export function stringToSymbol(str) {
let result = '';
for (var i=0; i<str.length; i++){
var n = str.charCodeAt(i);
if (( (n >= 97) && (n <= 122) ) ||
( (n >= 48) && (n <= 57) ))
{
result += str[i];
} else if ( (n >= 65) && (n <= 90) )
{
result += String.fromCharCode(n + 32);
} else {
result += '-';
}
}
result = result.replace(/^[\-\d]+|\-+/g, '-');
result = result.replace(/^\-+|\-+$/g, '');
if (result === ''){
return dateToDa(new Date());
}
return result;
}
export function dateToDa(d, mil) {
  var fil = function(n) {
    return n >= 10 ? n : "0" + n;
  };
  return (
    `~${d.getUTCFullYear()}.` +
    `${(d.getUTCMonth() + 1)}.` +
    `${fil(d.getUTCDate())}..` +
    `${fil(d.getUTCHours())}.` +
    `${fil(d.getUTCMinutes())}.` +
    `${fil(d.getUTCSeconds())}` +
`${mil ? "..0000" : ""}`
  );
}

View File

@ -3,22 +3,34 @@ import _ from 'lodash';
export class UpdateReducer {
reduce(json, state){
if (json.invite) {
this.reduceInvite(json, state);
this.reduceInvite(json.invite, state);
} else if (json.unread) {
this.reduceUnread(json.unread, state);
}
}
reduceInvite(json, state) {
let val = {
title: json.invite.title,
coll: json.invite.coll,
who: json.invite.who,
title: json.title,
coll: json.coll,
who: json.who,
};
if (json.invite.add) {
if (json.add) {
state.invites.push(val);
} else {
let idx = _.findIndex(state.invites, val)
_.pullAt(state.invites, [idx]);
}
}
reduceUnread(json, state) {
if (json.add) {
state.unread = _.uniq(state.unread.concat(json.posts));
} else {
let idx = json.posts.map((val) => {
return _.findIndex(state.unread, val);
});
_.pullAt(state.unread, idx);
}
}
}

View File

@ -1,5 +1,4 @@
import { api } from '/api';
import _ from 'lodash';
import { store } from '/store';