pass snippet and about field from backend

wire up routing for notebook page
add infinite scroll and note fetching logic to notebook page
This commit is contained in:
Isaac Visintainer 2020-01-31 15:00:06 -08:00
parent fe44b25f92
commit 919db6a3be
11 changed files with 181 additions and 59 deletions

View File

@ -628,10 +628,12 @@
++ form-note
|= [note-name=@tas udon=@t]
^- note
=/ build=(each manx tang)
%- mule |.
^- manx
elm:(static:cram (ream udon))
=/ body=tape (slag (add 3 (need (find ";>" (trip udon)))) (trip udon))
=/ snippet=@t (of-wain:format (scag 1 (to-wain:format (crip body))))
:: =/ build=(each manx tang)
:: %- mule |.
:: ^- manx
:: elm:(static:cram (ream udon))
::
=/ meta=(each (map term knot) tang)
%- mule |.
@ -658,7 +660,7 @@
now.bol
%.n
udon
build
snippet
~
==
::
@ -1284,7 +1286,7 @@
=/ notebook-json (notebook-full-json host book-name u.book)
?> ?=(%o -.notebook-json)
=. p.notebook-json
(~(uni by p.notebook-json) (notes-page notes.u.book 0 50))
(~(uni by p.notebook-json) (notes-page notes.u.book 0 10))
=. p.notebook-json
(~(put by p.notebook-json) %subscribers (get-subscribers-json book-name))
=/ notebooks-json (notebooks-map-json our.bol books subs)
@ -1418,7 +1420,7 @@
=/ notebook-json (notebook-full-json u.host book-name u.book)
?> ?=(%o -.notebook-json)
=. p.notebook-json
(~(uni by p.notebook-json) (notes-page notes.u.book 0 50))
(~(uni by p.notebook-json) (notes-page notes.u.book 0 10))
=. p.notebook-json
(~(put by p.notebook-json) %subscribers (get-subscribers-json book-name))
=/ jon=json (pairs notebook+notebook-json ~)

View File

@ -103,6 +103,7 @@
%- pairs
:~ title+s+title.book
date-created+(time date-created.book)
about+s+description.book
num-notes+(numb ~(wyt by notes.book))
num-unread+(numb (count-unread notes.book))
==
@ -113,6 +114,7 @@
=, enjs:format
%- pairs
:~ title+s+title.book
about+s+description.book
date-created+(time date-created.book)
num-notes+(numb ~(wyt by notes.book))
num-unread+(numb (count-unread notes.book))
@ -160,10 +162,10 @@
author+s+(scot %p author.note)
title+s+title.note
date-created+(time date-created.note)
build+(note-build-to-json build.note)
snippet+s+snippet.note
file+s+file.note
num-comments+(numb ~(wyt by comments.note))
comments+(comments-page comments.note 0 50)
comments+(comments-page comments.note 0 10)
read+b+read.note
==
::
@ -191,7 +193,7 @@
date-created+(time date-created.note)
num-comments+(numb ~(wyt by comments.note))
read+b+read.note
:: XX snippet
snippet+s+snippet.note
==
::
++ notes-page

View File

@ -40,7 +40,8 @@
last-edit=@da
read=?
file=@t
build=(each manx tang)
snippet=@t
:: build=(each manx tang)
comments=(map @da comment)
==
::

View File

@ -166,3 +166,13 @@ a {
[contenteditable]:focus {
outline: 0px solid transparent;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}

View File

@ -1,19 +0,0 @@
import React, { Component } from 'react';
export class All extends Component {
render() {
return (
<div className="mv6">
<div className="mb1">Title</div>
<p className="mb1">I dreamt of urbit hardware - stars and galaxies and planets had differing...</p>
<div className="flex">
<div className="mono gray2 mr3">~fabled-faster</div>
<div className="gray2 mr3">1m ago</div>
<div className="gray2">No Comments</div>
</div>
</div>
)
}
}
export default All

View File

@ -8,7 +8,7 @@ export class NewPost extends Component {
constructor(props) {
super(props);
this.state = {
body: "# Hello",
body: '',
title: '',
submit: false,
awaiting: null,
@ -81,7 +81,7 @@ export class NewPost extends Component {
</button>
</div>
<input type="text"
<input autoFocus type="text"
style={{paddingBottom: 8, paddingTop: 24}}
className="w-100"
onChange={this.titleChange}

View File

@ -0,0 +1,73 @@
import React, { Component } from 'react';
import moment from 'moment';
import { Link } from 'react-router-dom';
export class NotebookPosts extends Component {
constructor(props){
super(props);
moment.updateLocale('en', {
relativeTime: {
past: function(input) {
return input === 'just now'
? input
: input + ' ago'
},
s : 'just now',
future : 'in %s',
m : '1m',
mm : '%dm',
h : '1h',
hh : '%dh',
d : '1d',
dd : '%dd',
M : '1 month',
MM : '%d months',
y : '1 year',
yy : '%d years',
}
});
}
render() {
let notes = [];
for (var i=0; i<this.props.list.length; i++) {
let noteId = this.props.list[i];
let note = this.props.notes[noteId];
if (!note) {
break;
}
let comment = "No Comments";
if (note["num-comments"] == 1) {
comment = "1 Comment";
} else if (note["num-comments"] > 1) {
comment = `${note["num-comments"]} Comments`;
}
let date = moment(note["date-created"]).fromNow();
let url = `/~publish/note/${this.props.host}/${this.props.notebookName}/${noteId}`
notes.push(
<Link key={i} to={url}>
<div className="mv6">
<div className="mb1">{note.title}</div>
<p className="mb1">{note.snippet}</p>
<div className="flex">
<div className="mono gray2 mr3">{note.author}</div>
<div className="gray2 mr3">{date}</div>
<div className="gray2">{comment}</div>
</div>
</div>
</Link>
)
}
return (
<div className="flex-col">
{notes}
</div>
);
}
}
export default NotebookPosts

View File

@ -1,7 +1,7 @@
import React, { Component } from 'react';
import { Link, Switch, Route } from 'react-router-dom';
import { NoteList } from './note-list';
import { All } from './all';
import { NotebookPosts } from './notebook-posts';
import { About } from './about';
import { Subscribers } from './subscribers';
import { Settings } from './settings';
@ -23,22 +23,84 @@ import { Settings } from './settings';
export class Notebook extends Component {
constructor(props){
super(props);
console.log("props", this.props);
this.state = {
ours: (window.ship === this.props.ship.slice(1)),
numNotes: 10,
};
this.onScroll = this.onScroll.bind(this);
}
onScroll(e) {
let scrollTop = this.scrollElement.scrollTop;
let clientHeight = e.target.clientHeight;
let scrollHeight = e.target.scrollHeight;
let atBottom = false;
if (scrollHeight - scrollTop - clientHeight < 40) {
atBottom = true;
}
let loadedNotes = Object.keys(this.props.notebook.notes).length;
let allNotes = this.props.notebook["notes-by-date"].length;
let fullyLoaded = (loadedNotes === allNotes);
if (atBottom && !fullyLoaded) {
window.api.fetchNotesPage(this.props.ship, this.props.notebookName, loadedNotes, 5);
}
}
componentWillMount(){
if (!this.props.notebook.notes) {
window.api.fetchNotebook(this.props.ship, this.props.notebookName);
}
}
render() {
let tabStyles = {
posts: "bb b--gray4 gray2 NotebookTab",
about: "bb b--gray4 gray2 NotebookTab",
subscribers: "bb b--gray4 gray2 NotebookTab",
settings: "bb b--gray4 pr2 gray2 NotebookTab",
// subscribers: "bb b--gray4 gray2 NotebookTab",
// settings: "bb b--gray4 pr2 gray2 NotebookTab",
}
tabStyles[this.props.view] = "bb b--black black NotebookTab";
let inner = null;
switch (this.props.view) {
case "posts":
let notesList = this.props.notebook["notes-by-date"] || [];
let notes = this.props.notebook.notes || null;
inner = <NotebookPosts notes={notes}
list={notesList}
host={this.props.ship}
notebookName={this.props.notebookName}/>
break;
case "about":
inner = <p className="f8 lh-solid">{this.props.notebook.about}</p>
break;
// case "subscribers":
// inner = <Subscribers/>
// break;
// case "settings":
// inner = <Settings/>
// break;
default:
break;
}
let base = `/~publish/notebook/${this.props.ship}/${this.props.notebookName}`;
let about = base + '/about';
let subs = base + '/subscribers';
let settings = base + '/settings';
let newUrl = base + '/new';
return (
<div className="center mw6 f9 h-100"
style={{paddingLeft:16, paddingRight:16}}>
<div className="h-100 overflow-container">
<div className="h-100 overflow-container no-scrollbar"
onScroll={this.onScroll}
ref={(el) => {this.scrollElement = el}}>
<div className="flex justify-between"
style={{marginTop: 56, marginBottom: 32}}>
<div className="flex-col">
@ -49,31 +111,24 @@ export class Notebook extends Component {
</span>
</span>
</div>
<button className="NotebookButton bg-light-green green2">
<Link to={newUrl} className="NotebookButton bg-light-green green2">
New Post
</button>
</Link>
</div>
<div className="flex" style={{marginBottom:24}}>
<div className={tabStyles.posts}>
<Link to={base} className={tabStyles.posts}>
All Posts
</div>
<div className={tabStyles.about}>
</Link>
<Link to={about} className={tabStyles.about}>
About
</div>
<div className={tabStyles.subscribers}>
Subscribers
</div>
<div className={tabStyles.settings}>
Settings
</div>
</Link>
<div className="bb b--gray4 gray2 NotebookTab" style={{flexGrow:1}}>
</div>
</div>
<div style={{height:"calc(100% - 170px)"}} className="f9 lh-solid">
<Settings />
<div style={{height:"calc(100% - 188px)"}} className="f9 lh-solid">
{inner}
</div>
</div>
</div>

View File

@ -41,9 +41,9 @@ export class Sidebar extends Component {
<a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/"> Landscape</a>
<div className="w-100 pa4">
<Link
to="/~publish/new"
to="/~publish/notebook/~zod/foo"
className="green2 mr4 f9">
New
zod/foo
</Link>
<Link
to="/~publish/join"

View File

@ -2,7 +2,6 @@ import _ from 'lodash';
export class PrimaryReducer {
reduce(json, state){
console.log("primaryReducer", json);
switch(Object.keys(json)[0]){
case "add-book":
this.addBook(json["add-book"], state);

View File

@ -2,7 +2,6 @@ import _ from 'lodash';
export class ResponseReducer {
reduce(json, state) {
console.log("responseReducer", json);
switch(json.type) {
case "notebooks":
this.handleNotebooks(json, state);