mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-14 17:41:33 +03:00
commit
1f7bcdb7ef
4
.gitignore
vendored
4
.gitignore
vendored
@ -74,8 +74,8 @@ apps/*/dist/
|
||||
*.swn
|
||||
|
||||
# built js and css files
|
||||
apps/publish/urbit/app/write/js/*
|
||||
apps/publish/urbit/app/write/css/*
|
||||
apps/publish/urbit/app/publish/js/*
|
||||
apps/publish/urbit/app/publish/css/*
|
||||
apps/chat/urbit/app/chat/js/*
|
||||
apps/chat/urbit/app/chat/css/*
|
||||
apps/clock/urbit/app/clock/js/*
|
||||
|
@ -4,6 +4,25 @@ p, h1, h2, h3, h4, h5, h6, a, input, textarea, button {
|
||||
font-family: Inter, sans-serif;
|
||||
}
|
||||
|
||||
button {
|
||||
background: none;
|
||||
color: inherit;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
outline: inherit;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 8px;
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
|
||||
a {
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
@ -130,6 +149,10 @@ h4 {
|
||||
width: 688px;
|
||||
}
|
||||
|
||||
.mw-336 {
|
||||
max-width: 336px;
|
||||
}
|
||||
|
||||
.mw-688 {
|
||||
max-width: 688px;
|
||||
}
|
||||
@ -228,7 +251,7 @@ h4 {
|
||||
background-color: #B1B2B3;
|
||||
}
|
||||
|
||||
.title-preview {
|
||||
.two-lines {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
@ -236,10 +259,17 @@ h4 {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.body-preview {
|
||||
.five-lines {
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
word-wrap: break-word;
|
||||
-webkit-line-clamp: 5;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.one-line {
|
||||
word-wrap: break-word;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
@ -3,44 +3,26 @@ 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';
|
||||
import { BlogNotes } from '/components/lib/blog-notes';
|
||||
import { BlogSubs } from '/components/lib/blog-subs';
|
||||
import { BlogSettings } from '/components/lib/blog-settings';
|
||||
import { withRouter } from 'react-router';
|
||||
import { NotFound } from '/components/not-found';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const PC = withRouter(PathControl);
|
||||
const NF = withRouter(NotFound);
|
||||
const BN = withRouter(BlogNotes);
|
||||
const BS = withRouter(BlogSettings)
|
||||
|
||||
class Subscribe extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.actionType === 'subscribe') {
|
||||
return (
|
||||
<p className="label-small-2 b pointer"
|
||||
onClick={this.props.subscribe}>
|
||||
Subscribe
|
||||
</p>
|
||||
);
|
||||
} else if (this.props.actionType === 'unsubscribe') {
|
||||
return (
|
||||
<p className="label-small-2 b pointer"
|
||||
onClick={this.props.unsubscribe}>
|
||||
Unsubscribe
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Blog extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
view: 'notes',
|
||||
awaiting: false,
|
||||
postProps: [],
|
||||
blogTitle: '',
|
||||
@ -54,11 +36,17 @@ export class Blog extends Component {
|
||||
|
||||
this.subscribe = this.subscribe.bind(this);
|
||||
this.unsubscribe = this.unsubscribe.bind(this);
|
||||
this.viewSubs = this.viewSubs.bind(this);
|
||||
this.viewSettings = this.viewSettings.bind(this);
|
||||
this.viewNotes = this.viewNotes.bind(this);
|
||||
|
||||
this.blog = null;
|
||||
}
|
||||
|
||||
handleEvent(diff) {
|
||||
if (diff.data.total) {
|
||||
let blog = diff.data.total.data;
|
||||
this.blog = blog;
|
||||
this.setState({
|
||||
postProps: this.buildPosts(blog),
|
||||
blog: blog,
|
||||
@ -74,8 +62,11 @@ export class Blog extends Component {
|
||||
|
||||
this.props.setSpinner(false);
|
||||
} else if (diff.data.remove) {
|
||||
if (diff.data.remove.post) {
|
||||
// XX TODO
|
||||
|
||||
} else {
|
||||
this.props.history.push("/~publish/recent");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -94,10 +85,16 @@ export class Blog extends Component {
|
||||
? _.get(this.props, `pubs[${blogId}]`, false)
|
||||
: _.get(this.props, `subs[${ship}][${blogId}]`, false);
|
||||
|
||||
|
||||
if (!(blog) && (ship === window.ship)) {
|
||||
this.setState({notFound: true});
|
||||
return;
|
||||
};
|
||||
} else if (this.blog && !blog) {
|
||||
this.props.history.push("/~publish/recent");
|
||||
return;
|
||||
}
|
||||
|
||||
this.blog = blog;
|
||||
|
||||
if (this.state.awaitingSubscribe && blog) {
|
||||
this.setState({
|
||||
@ -138,6 +135,8 @@ export class Blog extends Component {
|
||||
this.props.api.bind(`/collection/${blogId}`, "PUT", ship, "publish",
|
||||
this.handleEvent.bind(this),
|
||||
this.handleError.bind(this));
|
||||
} else {
|
||||
this.blog = blog;
|
||||
}
|
||||
}
|
||||
|
||||
@ -228,6 +227,21 @@ export class Blog extends Component {
|
||||
this.props.history.push("/~publish/recent");
|
||||
}
|
||||
|
||||
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'});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
||||
if (this.state.notFound) {
|
||||
@ -239,50 +253,11 @@ export class Blog extends Component {
|
||||
} else {
|
||||
let data = this.buildData();
|
||||
|
||||
let posts = data.postProps.map((post, key) => {
|
||||
return (
|
||||
<PostPreview
|
||||
post={post}
|
||||
key={key}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
if ((posts.length === 0) && (this.props.ship === window.ship)) {
|
||||
let link = {
|
||||
pathname: "/~publish/new-post",
|
||||
state: {
|
||||
lastPath: this.props.location.pathname,
|
||||
lastMatch: this.props.match.path,
|
||||
lastParams: this.props.match.params,
|
||||
}
|
||||
}
|
||||
posts.push(
|
||||
<div key={0} className="w-336 relative">
|
||||
<hr className="gray-10" style={{marginBottom:18}}/>
|
||||
<Link to={link}>
|
||||
<p className="body-large b">
|
||||
-> Create First Post
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let contributors = `~${this.props.ship}`;
|
||||
let create = (this.props.ship === window.ship);
|
||||
|
||||
let subscribers = 'None';
|
||||
let subNum = _.get(data.blog, 'subscribers.length', 0);
|
||||
|
||||
if (subNum === 1) {
|
||||
subscribers = `~${data.blog.subscribers[0]}`;
|
||||
} else if (subNum === 2) {
|
||||
subscribers = `~${data.blog.subscribers[0]} and 1 other`;
|
||||
} else if (subNum > 2) {
|
||||
subscribers = `~${data.blog.subscribers[0]} and ${subNum-1} others`;
|
||||
}
|
||||
|
||||
let foreign = _.get(this.props,
|
||||
`subs[${this.props.ship}][${this.props.blogId}]`, false);
|
||||
|
||||
@ -293,39 +268,102 @@ export class Blog extends Component {
|
||||
actionType = 'unsubscribe';
|
||||
}
|
||||
|
||||
let viewSubs = (this.props.ship === window.ship)
|
||||
? this.viewSubs
|
||||
: null;
|
||||
|
||||
let viewSettings = (this.props.ship === window.ship)
|
||||
? this.viewSettings
|
||||
: null;
|
||||
|
||||
if (this.state.view === 'notes') {
|
||||
return (
|
||||
<div>
|
||||
<PC pathData={data.pathData} create={create}/>
|
||||
<div className="absolute w-100"
|
||||
style={{top:124, marginLeft: 16, marginRight: 16, marginTop: 32}}>
|
||||
style={{top:124, paddingLeft: 16, paddingRight: 16, paddingTop: 32}}>
|
||||
<div className="flex-col">
|
||||
<h2>{data.blogTitle}</h2>
|
||||
<h2 style={{wordBreak: "break-word"}}>
|
||||
{data.blogTitle}
|
||||
</h2>
|
||||
<div className="flex" style={{marginTop: 22}}>
|
||||
<div className="flex-col" style={{flexBasis: 160, marginRight:16}}>
|
||||
<p className="gray-50 label-small-2 b">Host</p>
|
||||
<p className="label-small-2">{data.blogHost}</p>
|
||||
</div>
|
||||
<div style={{flexBasis: 160, marginRight:16}}>
|
||||
<p className="gray-50 label-small-2 b">Contributors</p>
|
||||
<p className="label-small-2">{contributors}</p>
|
||||
</div>
|
||||
<div style={{flexBasis: 160, marginRight: 16}}>
|
||||
<p className="gray-50 label-small-2 b">Subscribers</p>
|
||||
<p className="label-small-2">{subscribers}</p>
|
||||
<Subscribe actionType={actionType}
|
||||
<BlogData
|
||||
host={this.props.ship}
|
||||
viewSubs={viewSubs}
|
||||
subNum={subNum}
|
||||
viewSettings={viewSettings}
|
||||
subscribeAction={actionType}
|
||||
subscribe={this.subscribe}
|
||||
unsubscribe={this.unsubscribe}
|
||||
/>
|
||||
</div>
|
||||
<BN ship={this.props.ship} posts={data.postProps} />
|
||||
</div>
|
||||
<div className="flex flex-wrap" style={{marginTop: 48}}>
|
||||
{posts}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (this.state.view === 'subs') {
|
||||
let subscribers = _.get(data, 'blog.subscribers', []);
|
||||
return (
|
||||
<div>
|
||||
<PC pathData={data.pathData} create={create}/>
|
||||
<div className="absolute w-100"
|
||||
style={{top:124, paddingLeft: 16, paddingRight: 16, paddingTop: 32}}>
|
||||
<div className="flex-col">
|
||||
<h2 style={{wordBreak: "break-word"}}>
|
||||
{data.blogTitle}
|
||||
</h2>
|
||||
<div className="flex" style={{marginTop: 22}}>
|
||||
<BlogData
|
||||
host={this.props.ship}
|
||||
viewSubs={viewSubs}
|
||||
subNum={subNum}
|
||||
viewSettings={viewSettings}
|
||||
subscribeAction={actionType}
|
||||
subscribe={this.subscribe}
|
||||
unsubscribe={this.unsubscribe}
|
||||
/>
|
||||
</div>
|
||||
<BlogSubs back={this.viewNotes}
|
||||
subs={subscribers}
|
||||
blogId={this.props.blogId}
|
||||
title={data.blogTitle}
|
||||
api={this.props.api}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
} else if (this.state.view === 'settings') {
|
||||
return (
|
||||
<div>
|
||||
<PC pathData={data.pathData} create={create}/>
|
||||
<div className="absolute w-100"
|
||||
style={{top:124, paddingLeft: 16, paddingRight: 16, paddingTop: 32}}>
|
||||
<div className="flex-col">
|
||||
<h2 style={{wordBreak: "break-word"}}>
|
||||
{data.blogTitle}
|
||||
</h2>
|
||||
<div className="flex" style={{marginTop: 22}}>
|
||||
<BlogData
|
||||
host={this.props.ship}
|
||||
viewSubs={viewSubs}
|
||||
subNum={subNum}
|
||||
viewSettings={viewSettings}
|
||||
subscribeAction={actionType}
|
||||
subscribe={this.subscribe}
|
||||
unsubscribe={this.unsubscribe}
|
||||
/>
|
||||
</div>
|
||||
<BS back={this.viewNotes}
|
||||
blogId={this.props.blogId}
|
||||
title={data.blogTitle}
|
||||
api={this.props.api}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
90
apps/publish/src/js/components/lib/blog-data.js
Normal file
90
apps/publish/src/js/components/lib/blog-data.js
Normal file
@ -0,0 +1,90 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
class Subscribe extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.actionType === 'subscribe') {
|
||||
return (
|
||||
<p className="label-small b pointer"
|
||||
onClick={this.props.subscribe}>
|
||||
Subscribe
|
||||
</p>
|
||||
);
|
||||
} else if (this.props.actionType === 'unsubscribe') {
|
||||
return (
|
||||
<p className="label-small b pointer"
|
||||
onClick={this.props.unsubscribe}>
|
||||
Unsubscribe
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Subscribers extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let subscribers = (this.props.subNum === 1)
|
||||
? `${this.props.subNum} Subscriber`
|
||||
: `${this.props.subNum} Subscribers`;
|
||||
|
||||
if (this.props.action !== null) {
|
||||
return (
|
||||
<p className="label-small b pointer" onClick={this.props.action}>
|
||||
{subscribers}
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<p className="label-small b">{subscribers}</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Settings extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.action !== null) {
|
||||
return (
|
||||
<p className="label-small b pointer" onClick={this.props.action}>
|
||||
Settings
|
||||
</p>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BlogData extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="flex-col">
|
||||
<p className="label-small">By ~{this.props.host}</p>
|
||||
<Subscribers action={this.props.viewSubs} subNum={this.props.subNum}/>
|
||||
<Settings action={this.props.viewSettings}/>
|
||||
<Subscribe actionType={this.props.subscribeAction}
|
||||
subscribe={this.props.subscribe}
|
||||
unsubscribe={this.props.unsubscribe}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
50
apps/publish/src/js/components/lib/blog-notes.js
Normal file
50
apps/publish/src/js/components/lib/blog-notes.js
Normal file
@ -0,0 +1,50 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { PostPreview } from '/components/lib/post-preview';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
export class BlogNotes extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.posts ||
|
||||
((this.props.posts.length === 0) &&
|
||||
(this.props.ship === window.ship))) {
|
||||
let link = {
|
||||
pathname: "/~publish/new-post",
|
||||
state: {
|
||||
lastPath: this.props.location.pathname,
|
||||
lastMatch: this.props.match.path,
|
||||
lastParams: this.props.match.params,
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap">
|
||||
<div className="w-336 relative">
|
||||
<hr className="gray-10" style={{marginTop: 48, marginBottom:25}}/>
|
||||
<Link to={link}>
|
||||
<p className="body-large b">
|
||||
-> Create First Post
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let posts = this.props.posts.map((post, key) => {
|
||||
return (
|
||||
<PostPreview post={post} key={key}/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="flex flex-wrap" style={{marginTop: 48}}>
|
||||
{posts}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
122
apps/publish/src/js/components/lib/blog-settings.js
Normal file
122
apps/publish/src/js/components/lib/blog-settings.js
Normal file
@ -0,0 +1,122 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
class SaveLink extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.enabled) {
|
||||
return (
|
||||
<button className="label-regular b"
|
||||
onClick={this.props.action}>
|
||||
-> Save
|
||||
</button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<p className="label-regular b gray-50">
|
||||
-> Save
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BlogSettings extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
title: '',
|
||||
awaitingTitleChange: false,
|
||||
}
|
||||
|
||||
this.rename = this.rename.bind(this);
|
||||
this.titleChange = this.titleChange.bind(this);
|
||||
this.deleteBlog = this.deleteBlog.bind(this);
|
||||
}
|
||||
|
||||
rename() {
|
||||
let edit = {
|
||||
"edit-collection": {
|
||||
name: this.props.blogId,
|
||||
title: this.state.title,
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
awaitingTitleChange: true,
|
||||
}, () => {
|
||||
this.props.api.action("publish", "publish-action", edit);
|
||||
});
|
||||
}
|
||||
|
||||
titleChange(evt) {
|
||||
this.setState({title: evt.target.value});
|
||||
}
|
||||
|
||||
deleteBlog() {
|
||||
let del = {
|
||||
"delete-collection": {
|
||||
coll: this.props.blogId,
|
||||
}
|
||||
}
|
||||
this.props.api.action("publish", "publish-action", del);
|
||||
this.props.history.push("/~publish/recent");
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (this.state.awaitingTitleChange) {
|
||||
if (prevProps.title !== this.props.title){
|
||||
this.titleInput.value = '';
|
||||
this.setState({
|
||||
awaitingTitleChange: false,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
let back = '<- Back to notes'
|
||||
let enableSave = ((this.state.title !== '') &&
|
||||
(this.state.title !== this.props.title) &&
|
||||
!this.state.awaitingTitleChange);
|
||||
return (
|
||||
<div className="flex-col mw-688" style={{marginTop:48}}>
|
||||
<hr className="gray-30" style={{marginBottom:25}}/>
|
||||
<p className="label-regular pointer b" onClick={this.props.back}>
|
||||
{back}
|
||||
</p>
|
||||
<p className="body-large b" style={{marginTop:16, marginBottom: 20}}>
|
||||
Settings
|
||||
</p>
|
||||
<div className="flex">
|
||||
<div className="flex-col w-100">
|
||||
<p className="body-regular-400">Delete Notebook</p>
|
||||
<p className="gray-50 label-small-2" style={{marginTop:12, marginBottom:8}}>
|
||||
Permanently delete this notebook
|
||||
</p>
|
||||
<button className="red label-regular b" onClick={this.deleteBlog}>
|
||||
-> Delete
|
||||
</button>
|
||||
</div>
|
||||
<div className="flex-col w-100">
|
||||
<p className="body-regular-400">Rename</p>
|
||||
<p className="gray-50 label-small-2" style={{marginTop:12, marginBottom:23}}>
|
||||
Change the name of this notebook
|
||||
</p>
|
||||
<p className="label-small-2">Notebook Name</p>
|
||||
<input className="body-regular-400 w-100"
|
||||
ref={(el) => {this.titleInput = el}}
|
||||
style={{marginBottom:8}}
|
||||
placeholder={this.props.title}
|
||||
onChange={this.titleChange}
|
||||
disabled={this.state.awaitingTitleChange}/>
|
||||
<SaveLink action={this.rename} enabled={enableSave}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
140
apps/publish/src/js/components/lib/blog-subs.js
Normal file
140
apps/publish/src/js/components/lib/blog-subs.js
Normal file
@ -0,0 +1,140 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import urbitOb from 'urbit-ob';
|
||||
|
||||
class InviteLink extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.props.enabled) {
|
||||
return (
|
||||
<button className="label-regular b underline"
|
||||
onClick={this.props.action}>
|
||||
Invite
|
||||
</button>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<p className="label-regular b underline gray-50">
|
||||
Invite
|
||||
</p>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class BlogSubs extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
validInvites: false,
|
||||
invites: [],
|
||||
}
|
||||
this.inviteHeight = 133;
|
||||
this.invite = this.invite.bind(this);
|
||||
this.inviteChange = this.inviteChange.bind(this);
|
||||
}
|
||||
|
||||
inviteChange(evt) {
|
||||
this.inviteInput.style.height = 'auto';
|
||||
let newHeight = (this.inviteInput.scrollHeight < 133)
|
||||
? 133 : this.inviteInput.scrollHeight + 2;
|
||||
this.inviteInput.style.height = newHeight+'px';
|
||||
this.inviteHeight = this.inviteInput.style.height;;
|
||||
|
||||
|
||||
let tokens = evt.target.value
|
||||
.trim()
|
||||
.split(/[\s,]+/)
|
||||
.map(t => t.trim());
|
||||
|
||||
let valid = tokens.reduce((valid, s) =>
|
||||
valid && ((s !== '~') && urbitOb.isValidPatp(s) && s.includes('~')), true);
|
||||
|
||||
if (valid) {
|
||||
this.setState({
|
||||
validInvites: true,
|
||||
invites: tokens.map(t => t.slice(1)),
|
||||
});
|
||||
} else {
|
||||
this.setState({validInvites: false});
|
||||
}
|
||||
}
|
||||
|
||||
invite() {
|
||||
if (this.inviteInput) this.inviteInput.value = '';
|
||||
|
||||
let invite = {
|
||||
invite: {
|
||||
coll: this.props.blogId,
|
||||
title: this.props.title,
|
||||
who: this.state.invites,
|
||||
}
|
||||
}
|
||||
|
||||
this.inviteHeight = 133;
|
||||
this.setState({
|
||||
validInvites: false,
|
||||
invites: [],
|
||||
}, () => {
|
||||
this.props.api.action("publish", "publish-action", invite);
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
let back = '<- Back to notes'
|
||||
|
||||
let subscribers = this.props.subs.map((sub, i) => {
|
||||
return (
|
||||
<div className="flex w-100" key={i+1}>
|
||||
<p className="label-regular-mono w-100">~{sub}</p>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
subscribers.unshift(
|
||||
<div className="flex w-100" key={0}>
|
||||
<p className="label-regular-mono w-100">~{window.ship}</p>
|
||||
<p className="label-regular-mono w-100">Host (You)</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex-col mw-688" style={{marginTop:48}}>
|
||||
<hr className="gray-30" style={{marginBottom:25}}/>
|
||||
<p className="label-regular pointer b" onClick={this.props.back}>
|
||||
{back}
|
||||
</p>
|
||||
<p className="body-large b" style={{marginTop:16, marginBottom: 20}}>
|
||||
Manage Notebook
|
||||
</p>
|
||||
<div className="flex">
|
||||
<div className="flex-col w-100">
|
||||
<p className="body-regular-400">Members</p>
|
||||
<p className="gray-50 label-small-2"
|
||||
style={{marginTop:12, marginBottom: 23}}>
|
||||
Everyone subscribed to this notebook
|
||||
</p>
|
||||
{subscribers}
|
||||
</div>
|
||||
<div className="flex-col w-100">
|
||||
<p className="body-regular-400">Invite</p>
|
||||
<p className="gray-50 label-small-2"
|
||||
style={{marginTop:12, marginBottom: 23}}>
|
||||
Invite people to subscribe to this notebook
|
||||
</p>
|
||||
<textarea className="w-100 label-regular-mono overflow-y-hidden"
|
||||
ref={(el) => {this.inviteInput = el}}
|
||||
style={{resize:"none", marginBottom:8, height: this.inviteHeight}}
|
||||
onChange={this.inviteChange}>
|
||||
</textarea>
|
||||
<InviteLink enabled={this.state.validInvites} action={this.invite}/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -23,16 +23,30 @@ class PostButton extends Component {
|
||||
export class CommentBox extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
|
||||
this.commentChange = this.commentChange.bind(this);
|
||||
this.commentHeight = 54;
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!prevProps.enabled && this.props.enabled) {
|
||||
if (this.textarea) {
|
||||
this.textarea.value = '';
|
||||
if (this.commentInput) {
|
||||
this.commentInput.value = '';
|
||||
this.commentInput.style.height = 54;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commentChange(evt) {
|
||||
this.commentInput.style.height = 'auto';
|
||||
let newHeight = (this.commentInput.scrollHeight < 54)
|
||||
? 54 : this.commentInput.scrollHeight+2;
|
||||
this.commentInput.style.height = newHeight+'px';
|
||||
this.commentHeight = this.commentInput.style.height;
|
||||
|
||||
this.props.action(evt);
|
||||
}
|
||||
|
||||
render() {
|
||||
let textClass = (this.props.enabled)
|
||||
? "body-regular-400 w-100"
|
||||
@ -45,12 +59,12 @@ export class CommentBox extends Component {
|
||||
</div>
|
||||
<div className="flex-col w-100">
|
||||
<textarea className={textClass}
|
||||
ref={(el) => {this.textarea = el}}
|
||||
style={{resize: "none"}}
|
||||
ref={(el) => {this.commentInput = el}}
|
||||
style={{resize: "none", height: this.commentHeight}}
|
||||
type="text"
|
||||
name="commentBody"
|
||||
defaultValue=''
|
||||
onChange={this.props.action}
|
||||
onChange={this.commentChange}
|
||||
disabled={(!this.props.enabled)}>
|
||||
</textarea>
|
||||
<PostButton
|
||||
|
@ -45,8 +45,9 @@ export class Comment extends Component {
|
||||
</div>
|
||||
<div className="flex-col fl">
|
||||
<div className="label-small-mono gray-50">
|
||||
<p className="fl" style={{width: 107}}>{this.props.ship}</p>
|
||||
<p className="fl">{date}</p>
|
||||
<p className="fl label-small-mono"
|
||||
style={{width: 107}}>{this.props.ship}</p>
|
||||
<p className="fl label-small-mono">{date}</p>
|
||||
</div>
|
||||
<div className="cb body-regular-400">
|
||||
{body}
|
||||
|
@ -2,7 +2,6 @@ import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { Comment } from '/components/lib/comment';
|
||||
import { CommentBox } from '/components/lib/comment-box';
|
||||
import { Sigil } from '/components/lib/icons/sigil';
|
||||
|
||||
export class Comments extends Component {
|
||||
constructor(props){
|
||||
|
@ -8,6 +8,20 @@ const PC = withRouter(PublishCreate);
|
||||
|
||||
export class HeaderMenu extends Component {
|
||||
render () {
|
||||
let recentText = (this.props.unread)
|
||||
? <p className="label-regular">
|
||||
<span className="green-medium body-large"> • </span>
|
||||
<span>Recent</span>
|
||||
</p>
|
||||
: <p className="label-regular">Recent</p>;
|
||||
|
||||
let subsText = (this.props.invites)
|
||||
? <p className="label-regular">
|
||||
<span className="green-medium body-large"> • </span>
|
||||
<span>Subscriptions</span>
|
||||
</p>
|
||||
: <p className="label-regular">Subscriptions</p>;
|
||||
|
||||
return (
|
||||
<div className="fixed w-100 bg-white cf h-publish-header z-4"
|
||||
style={{top:48}}>
|
||||
@ -38,7 +52,7 @@ export class HeaderMenu extends Component {
|
||||
borderColor: "black",
|
||||
}}
|
||||
style={{flexBasis:148}}>
|
||||
Subscriptions
|
||||
{subsText}
|
||||
</NavLink>
|
||||
|
||||
<div className="fl bb b-gray-30 w-16" >
|
||||
@ -52,7 +66,7 @@ export class HeaderMenu extends Component {
|
||||
borderColor: "black",
|
||||
}}
|
||||
style={{flexBasis:148}}>
|
||||
My Blogs
|
||||
Notebooks
|
||||
</NavLink>
|
||||
|
||||
<div className="fl bb b-gray-30 w-16" style={{flexGrow:1}}>
|
||||
|
@ -1,57 +0,0 @@
|
||||
import React, { Component } from 'react';
|
||||
import { BrowserRouter, Route } from 'react-router-dom';
|
||||
import classnames from 'classnames';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { HeaderMenu } from '/components/lib/header-menu';
|
||||
import { PathControl } from '/components/lib/path-control';
|
||||
import { Switch } from 'react-router';
|
||||
|
||||
export class Header extends Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="cf w-100 bg-white h-publish-header">
|
||||
<Switch>
|
||||
<Route exact path="/~publish/recent" component={HeaderMenu}/>
|
||||
<Route exact path="/~publish/subs" component={HeaderMenu}/>
|
||||
<Route exact path="/~publish/pubs" component={HeaderMenu}/>
|
||||
|
||||
<Route exact path="/~publish/new"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<PathControl {...this.props} {...props}/>
|
||||
)
|
||||
}}/>
|
||||
<Route exact path="/~publish/new/blog"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<PathControl {...this.props} {...props}/>
|
||||
)
|
||||
}}/>
|
||||
<Route exact path="/~publish/new/post"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<PathControl {...this.props} {...props}/>
|
||||
)
|
||||
}}/>
|
||||
|
||||
<Route exact path="/~publish/:ship/:blog"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<PathControl {...this.props} {...props}/>
|
||||
)
|
||||
}}/>
|
||||
<Route exact path="/~publish/:ship/:blog/:post"
|
||||
render={ (props) => {
|
||||
return (
|
||||
<PathControl {...this.props} {...props}/>
|
||||
)
|
||||
}}/>
|
||||
</Switch>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
@ -3,6 +3,10 @@ import { sealDict } from '/components/lib/seal-dict';
|
||||
|
||||
|
||||
export class Sigil extends Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
let prefix = this.props.prefix ? JSON.parse(this.props.prefix) : false;
|
||||
|
||||
@ -11,7 +15,7 @@ export class Sigil extends Component {
|
||||
className="bg-black"
|
||||
style={{ flexBasis: 35, padding: 4}}>
|
||||
{
|
||||
sealDict.getSeal(this.props.ship, this.props.size, prefix)
|
||||
sealDict.getSeal(this.props.ship.slice(1), this.props.size, prefix)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
@ -39,7 +39,7 @@ export class PathControl extends Component {
|
||||
|
||||
if (this.props.location.pathname === '/~publish/new-blog') {
|
||||
path.push(
|
||||
{ text: 'New Blog', url: finalUrl }
|
||||
{ text: 'New Notebook', url: finalUrl }
|
||||
);
|
||||
} else if (this.props.location.pathname === '/~publish/new-post') {
|
||||
if (blog) {
|
||||
@ -49,7 +49,7 @@ export class PathControl extends Component {
|
||||
});
|
||||
}
|
||||
path.push(
|
||||
{ text: 'New Post', url: finalUrl }
|
||||
{ text: 'New Note', url: finalUrl }
|
||||
);
|
||||
}
|
||||
return path;
|
||||
@ -71,7 +71,7 @@ export class PathControl extends Component {
|
||||
|
||||
path.push(
|
||||
<Link to={seg.url} key={key++}
|
||||
className="fl gray-30 label-regular" style={style}>
|
||||
className="fl gray-30 label-regular one-line mw-336" style={style}>
|
||||
{seg.text}
|
||||
</Link>
|
||||
);
|
||||
|
@ -9,7 +9,7 @@ export class PostBody extends Component {
|
||||
super(props)
|
||||
}
|
||||
|
||||
renderA(what, node, attr) {
|
||||
renderA(what, node, attr, parentNode) {
|
||||
let aStyle = {
|
||||
textDecorationLine: "underline",
|
||||
wordWrap: "break-word"
|
||||
@ -19,7 +19,7 @@ export class PostBody extends Component {
|
||||
return item;
|
||||
} else {
|
||||
let newAttr = Object.assign({style: aStyle, key: key}, item.ga);
|
||||
return this.parseContent(item.c, item.gn, newAttr);
|
||||
return this.parseContent(item.c, item.gn, newAttr, node);
|
||||
}
|
||||
});
|
||||
const element =
|
||||
@ -28,26 +28,30 @@ export class PostBody extends Component {
|
||||
}
|
||||
|
||||
|
||||
renderIMG(what, node, attr) {
|
||||
renderIMG(what, node, attr, parentNode) {
|
||||
let imgStyle = {
|
||||
width: "100%",
|
||||
height: "auto"
|
||||
height: "auto",
|
||||
marginBottom: 12,
|
||||
};
|
||||
let newAttr = Object.assign({style: imgStyle}, attr);
|
||||
const element = React.createElement(node, newAttr);
|
||||
return element;
|
||||
}
|
||||
|
||||
renderDefault(what, node, attr) {
|
||||
renderP(what, node, attr, parentNode) {
|
||||
let dStyle = {
|
||||
wordWrap: "break-word"
|
||||
wordWrap: "break-word",
|
||||
};
|
||||
if (parentNode !== 'li') {
|
||||
dStyle.marginBottom = 12;
|
||||
}
|
||||
let children = what.map((item, key) => {
|
||||
if (typeof(item) === 'string') {
|
||||
return item;
|
||||
} else {
|
||||
let newAttr = Object.assign({key: key}, item.ga);
|
||||
return this.parseContent(item.c, item.gn, newAttr);
|
||||
return this.parseContent(item.c, item.gn, newAttr, node);
|
||||
}
|
||||
});
|
||||
const element =
|
||||
@ -55,20 +59,42 @@ export class PostBody extends Component {
|
||||
return element;
|
||||
}
|
||||
|
||||
parseContent(what, node, attr) {
|
||||
renderDefault(what, node, attr, parentNode) {
|
||||
let dStyle = {
|
||||
wordWrap: "break-word",
|
||||
};
|
||||
let children = what.map((item, key) => {
|
||||
if (typeof(item) === 'string') {
|
||||
return item;
|
||||
} else {
|
||||
let newAttr = Object.assign({key: key}, item.ga);
|
||||
return this.parseContent(item.c, item.gn, newAttr, node);
|
||||
}
|
||||
});
|
||||
const element =
|
||||
React.createElement(node, Object.assign({style: dStyle}, attr), children);
|
||||
return element;
|
||||
}
|
||||
|
||||
parseContent(what, node, attr, parentNode) {
|
||||
switch (node) {
|
||||
case "a":
|
||||
return this.renderA(what, node, attr);
|
||||
return this.renderA(what, node, attr, parentNode);
|
||||
case "img":
|
||||
return this.renderIMG(what, node, attr);
|
||||
return this.renderIMG(what, node, attr, parentNode);
|
||||
case "p":
|
||||
return this.renderP(what, node, attr, parentNode);
|
||||
default:
|
||||
return this.renderDefault(what, node, attr);
|
||||
return this.renderDefault(what, node, attr, parentNode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
render() {
|
||||
let page = this.parseContent(this.props.body.c, this.props.body.gn, this.props.body.ga);
|
||||
let page = this.parseContent(this.props.body.c,
|
||||
this.props.body.gn,
|
||||
this.props.body.ga,
|
||||
null);
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
@ -8,14 +8,15 @@ export class PostSnippet extends Component {
|
||||
|
||||
render() {
|
||||
let elem = this.props.body.c.find((elem) => {
|
||||
return elem.gn === "p" &&
|
||||
typeof(elem.c[0]) === "string";
|
||||
return (elem.gn === "p" && typeof(elem.c[0]) === "string");
|
||||
});
|
||||
|
||||
let string = elem.c[0];
|
||||
let string = (elem === undefined)
|
||||
? null
|
||||
: elem.c[0];
|
||||
|
||||
return (
|
||||
<p className="body-regular-400 body-preview"
|
||||
<p className="body-regular-400 five-lines"
|
||||
style={{WebkitBoxOrient: "vertical"}}>
|
||||
{string}
|
||||
</p>
|
||||
|
@ -28,7 +28,7 @@ export class PublishCreate extends Component {
|
||||
<div className="w-100">
|
||||
<p className="publish">Publish</p>
|
||||
<Link to={link}>
|
||||
<p className="create">+New Blog</p>
|
||||
<p className="create">+New Notebook</p>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
@ -45,7 +45,7 @@ export class PublishCreate extends Component {
|
||||
<div className="w-100">
|
||||
<p className="publish">Publish</p>
|
||||
<Link to={link}>
|
||||
<p className="create">+New Post</p>
|
||||
<p className="create">+New Note</p>
|
||||
</Link>
|
||||
</div>
|
||||
);
|
||||
|
@ -57,7 +57,8 @@ export class RecentPreview extends Component {
|
||||
{comments}
|
||||
</p>
|
||||
<Link to={collLink}>
|
||||
<p className="body-regular gray-50">
|
||||
<p className="body-regular gray-50 one-line mw-336"
|
||||
style={{WebkitBoxOrient: "vertical"}}>
|
||||
{this.props.post.collectionTitle}
|
||||
</p>
|
||||
</Link>
|
||||
|
@ -8,7 +8,7 @@ export class TitleSnippet extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<p className="body-large b title-preview"
|
||||
<p className="body-large b two-lines"
|
||||
style={{WebkitBoxOrient: "vertical"}}>
|
||||
{this.props.title}
|
||||
</p>
|
||||
|
@ -11,9 +11,9 @@ class FormLink extends Component {
|
||||
render(props){
|
||||
if (this.props.enabled) {
|
||||
return (
|
||||
<p className="body-large b z-2 pointer" onClick={this.props.action}>
|
||||
<button className="body-large b z-2 pointer" onClick={this.props.action}>
|
||||
{this.props.body}
|
||||
</p>
|
||||
</button>
|
||||
);
|
||||
}
|
||||
return (
|
||||
@ -184,16 +184,16 @@ export class NewBlog extends Component {
|
||||
|
||||
<FormLink
|
||||
enabled={(this.state.title !== '')}
|
||||
action={this.firstPost}
|
||||
body={"-> Create a first post"}
|
||||
action={this.addInvites}
|
||||
body={"-> Send Invites"}
|
||||
/>
|
||||
|
||||
<hr className="gray-30" style={{marginTop:32, marginBottom: 32}}/>
|
||||
|
||||
<FormLink
|
||||
enabled={(this.state.title !== '')}
|
||||
action={this.addInvites}
|
||||
body={"-> Send Invites"}
|
||||
action={this.firstPost}
|
||||
body={"-> Create a first note"}
|
||||
/>
|
||||
|
||||
<hr className="gray-30" style={{marginTop:32, marginBottom: 32}}/>
|
||||
@ -228,7 +228,7 @@ export class NewBlog extends Component {
|
||||
/>
|
||||
|
||||
<p className="body-regular-400" style={{marginTop:25, marginBottom:27}}>
|
||||
Who is invited to read this blog?
|
||||
Who is invited to read this notebook?
|
||||
</p>
|
||||
|
||||
<input className={invitesStyle}
|
||||
@ -244,7 +244,7 @@ export class NewBlog extends Component {
|
||||
<FormLink
|
||||
enabled={enableButtons}
|
||||
action={this.firstPost}
|
||||
body={"-> Save and create a first post"}
|
||||
body={"-> Save and create a first note"}
|
||||
/>
|
||||
|
||||
<hr className="gray-30" style={{marginTop:32, marginBottom: 32}}/>
|
||||
|
@ -23,7 +23,7 @@ class SideTab extends Component {
|
||||
-> Post
|
||||
</p>
|
||||
<p className="pointer" onClick={this.props.discardPost}>
|
||||
Discard post
|
||||
Discard note
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
|
@ -410,7 +410,7 @@ export class Post extends Component {
|
||||
<div className="absolute w-100" style={{top:124}}>
|
||||
<div className="mw-688 center mt4 flex-col" style={{flexBasis: 688}}>
|
||||
<Link to={blogLink}>
|
||||
<p className="body-regular">
|
||||
<p className="body-regular one-line mw-688">
|
||||
{blogLinkText}
|
||||
</p>
|
||||
</Link>
|
||||
|
@ -58,9 +58,11 @@ export class Pubs extends Component {
|
||||
let cls = "w-100 flex " + bg;
|
||||
return (
|
||||
<div className={cls} key={i}>
|
||||
<div className="fl body-regular-400" style={{flexBasis: 336}}>
|
||||
<div className="fl body-regular-400 mw-336 w-336 pr3">
|
||||
<Link to={data.url}>
|
||||
<p className="one-line mw-336">
|
||||
{data.title}
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
<p className="fl body-regular-400" style={{flexBasis:336}}>
|
||||
@ -73,16 +75,18 @@ export class Pubs extends Component {
|
||||
);
|
||||
});
|
||||
|
||||
let invites = (this.props.invites.length > 0);
|
||||
let unread = (this.props.unread.length > 0);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HM/>
|
||||
<HM invites={invites} unread={unread}/>
|
||||
<div className="absolute w-100" style={{top:124}}>
|
||||
<div className="flex-col">
|
||||
<div className="w-100">
|
||||
<h2 className="gray-50"
|
||||
style={{marginLeft: 16, marginTop:32, marginBottom: 16}}>
|
||||
My Blogs
|
||||
Notebooks
|
||||
</h2>
|
||||
</div>
|
||||
<div className="w-100 flex">
|
||||
|
@ -154,9 +154,12 @@ export class Recent extends Component {
|
||||
);
|
||||
});
|
||||
|
||||
let invites = (this.props.invites.length > 0);
|
||||
let unread = (this.props.unread.length > 0);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HM/>
|
||||
<HM invites={invites} unread={unread}/>
|
||||
<div className="absolute w-100"
|
||||
style={{top:124, marginLeft: 16, marginRight: 16, marginTop: 32}}>
|
||||
<div className="flex-col">
|
||||
|
@ -1,7 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { Header } from '/components/lib/header';
|
||||
import { HeaderBar } from '/components/lib/header-bar';
|
||||
|
||||
|
||||
|
@ -108,9 +108,11 @@ export class Subs extends Component {
|
||||
if (data.type === 'regular') {
|
||||
return (
|
||||
<div className={cls} key={i}>
|
||||
<div className="fl body-regular-400" style={{flexBasis: 336}}>
|
||||
<div className="fl mw-336" style={{flexBasis: 336}}>
|
||||
<Link to={data.url}>
|
||||
<p className="body-regular-400 one-line pr3">
|
||||
{data.title}
|
||||
</p>
|
||||
</Link>
|
||||
</div>
|
||||
<p className="fl body-regular-400" style={{flexBasis:336}}>
|
||||
@ -131,9 +133,13 @@ export class Subs extends Component {
|
||||
<div className={cls} key={i}>
|
||||
<div className="fl body-regular-400" style={{flexBasis: 336}}>
|
||||
<Link to={data.url}>
|
||||
<div className="mw-336 one-line pr3">
|
||||
<span className="body-large green-medium"> • </span>
|
||||
<span className="body-regular-400">Invite to</span>
|
||||
<span className="body-regular">{data.title}</span>
|
||||
<span className="body-regular">
|
||||
{data.title}
|
||||
</span>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<p className="fl body-regular-400" style={{flexBasis:336}}>
|
||||
@ -157,10 +163,12 @@ export class Subs extends Component {
|
||||
}
|
||||
});
|
||||
|
||||
let invites = (this.props.invites.length > 0);
|
||||
let unread = (this.props.unread.length > 0);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<HM/>
|
||||
<HM invites={invites} unread={unread}/>
|
||||
<div className="absolute w-100" style={{top:124}}>
|
||||
<div className="flex-col">
|
||||
<div className="w-100">
|
||||
|
@ -23,6 +23,7 @@ export class RumorReducer {
|
||||
this.removePost(json, state);
|
||||
delete state.pubs[json.coll].posts[json.post];
|
||||
} else {
|
||||
|
||||
let postIds = Object.keys(state.pubs[json.coll].posts);
|
||||
postIds.forEach((postId) => {
|
||||
this.removePost({
|
||||
@ -32,6 +33,7 @@ export class RumorReducer {
|
||||
}, state);
|
||||
});
|
||||
delete state.pubs[json.coll];
|
||||
|
||||
}
|
||||
} else {
|
||||
if (json.post) {
|
||||
@ -99,11 +101,19 @@ export class RumorReducer {
|
||||
|
||||
reduceCollection(json, state) {
|
||||
if (json.who === window.ship) {
|
||||
if (state.pubs[json.coll]) {
|
||||
state.pubs[json.coll].info = json.data;
|
||||
} else {
|
||||
state.pubs[json.coll] = {
|
||||
info: json.data,
|
||||
order: { pin: [], unpin: [] },
|
||||
posts: {},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (state.subs[json.who]) {
|
||||
if (state.subs[json.who][json.coll]) {
|
||||
state.subs[json.who][json.coll].info = json.data;
|
||||
} else {
|
||||
state.subs[json.who][json.coll] = {
|
||||
info: json.data,
|
||||
@ -111,6 +121,16 @@ export class RumorReducer {
|
||||
posts: {},
|
||||
}
|
||||
}
|
||||
} else {
|
||||
state.subs[json.who] = {
|
||||
[json.coll]: {
|
||||
info: json.data,
|
||||
order: { pin: [], unpin: [] },
|
||||
posts: {},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
reducePost(json, state) {
|
||||
|
@ -348,7 +348,9 @@
|
||||
[~ da-this]
|
||||
=. subs.sat (~(del by subs.sat) who.del col.del)
|
||||
:- ~(tap in ~(key by pos.u.old))
|
||||
(da-emit [ost.bol %pull /collection/[col.del] [who.del %publish] ~])
|
||||
%- da-emil
|
||||
:- [ost.bol %pull /collection/[col.del] [who.del %publish] ~]
|
||||
(affection-primary del)
|
||||
:: iterate through post ids collected before, removing each from
|
||||
:: secondary indices in state
|
||||
::
|
||||
@ -382,7 +384,8 @@
|
||||
=. da-this (da-remove who.del col.del u.pos.del)
|
||||
(da-emil (affection del))
|
||||
=. subs.sat (~(put by subs.sat) [who.del col.del] new)
|
||||
(da-remove who.del col.del u.pos.del)
|
||||
=. da-this (da-remove who.del col.del u.pos.del)
|
||||
(da-emil (affection-primary del))
|
||||
::
|
||||
==
|
||||
::
|
||||
@ -527,6 +530,15 @@
|
||||
|= del=delta
|
||||
^- (quip move _this)
|
||||
da-done:(da-change:da del)
|
||||
:: +affection: rumors to primary
|
||||
::
|
||||
++ affection-primary
|
||||
|= del=delta
|
||||
^- (list move)
|
||||
%+ turn (prey:pubsub:userlib /primary bol)
|
||||
|= [b=bone *]
|
||||
^- move
|
||||
[b %diff %publish-rumor del]
|
||||
:: +affection: rumors to interested
|
||||
::
|
||||
++ affection
|
||||
@ -1023,7 +1035,15 @@
|
||||
%edit-collection
|
||||
?. =(src.bol our.bol)
|
||||
[~ this]
|
||||
=/ pax=path /web/publish/[name.act]/publish-info
|
||||
=/ col=(unit collection) (~(get by pubs.sat) name.act)
|
||||
?~ col
|
||||
[~ this]
|
||||
?: ?=(%.n -.dat.col.u.col)
|
||||
[~ this]
|
||||
=/ out=collection-info p.dat.col.u.col(title title.act)
|
||||
:_ this
|
||||
[(write-file pax %publish-info !>(out))]~
|
||||
::
|
||||
%edit-post
|
||||
?. =(who.act our.bol)
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -73,7 +73,10 @@
|
||||
content+so:dejs
|
||||
==
|
||||
::
|
||||
++ delete-collection (of:dejs coll+(su:dejs sym) ~)
|
||||
++ delete-collection
|
||||
%- ot:dejs
|
||||
:~ coll+(su:dejs sym)
|
||||
==
|
||||
::
|
||||
++ delete-post
|
||||
%- ot:dejs
|
||||
@ -92,9 +95,6 @@
|
||||
%- ot:dejs
|
||||
:~ name+(su:dejs sym)
|
||||
title+so:dejs
|
||||
comments+comment-config
|
||||
allow-edit+edit-config
|
||||
perm+perm-config
|
||||
==
|
||||
::
|
||||
++ edit-post
|
||||
|
@ -8,7 +8,7 @@
|
||||
%+ sort ~(val by comments)
|
||||
|= [a=comment:publish b=comment:publish]
|
||||
^- ?
|
||||
(lte date-created.info.a date-created.info.b)
|
||||
(gte date-created.info.a date-created.info.b)
|
||||
::
|
||||
/_ /publish-comment/
|
||||
result
|
||||
|
@ -25,13 +25,7 @@
|
||||
[%delete-post coll=@tas post=@tas]
|
||||
[%delete-comment coll=@tas post=@tas comment=@tas]
|
||||
::
|
||||
$: %edit-collection
|
||||
name=@tas
|
||||
title=@t
|
||||
com=comment-config
|
||||
edit=edit-config
|
||||
perm=perm-config
|
||||
==
|
||||
[%edit-collection name=@tas title=@t]
|
||||
::
|
||||
$: %edit-post
|
||||
who=@p
|
||||
|
Loading…
Reference in New Issue
Block a user