Merge pull request #2284 from urbit/mp/os1/publish/popout-note

publish: collapsable sidebar logic, popout for all notebook/note views
This commit is contained in:
matildepark 2020-02-13 12:40:10 -05:00 committed by GitHub
commit d40a37b7cf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 184 additions and 147 deletions

View File

@ -96,7 +96,7 @@ a {
.NewPost {
width: 100%;
height: calc(100% - 103px);
height: calc(100% - 115px);
display: flex;
padding-top: 8px;
}

View File

@ -1,7 +1,5 @@
import React from 'react';
import ReactDOM from 'react-dom';
import _ from 'lodash';
import { uuid } from '/lib/util';
import { store } from './store'
class UrbitApi {
setAuthTokens(authTokens) {
@ -125,10 +123,9 @@ class UrbitApi {
sidebarBoolean = false;
}
store.handleEvent({
type: {
local: {
'sidebarToggle': sidebarBoolean
}
type: "local",
data: {
'sidebarToggle': sidebarBoolean
}
});
}

View File

@ -1,16 +0,0 @@
import React, { Component } from 'react';
//TODO "About" subcomponent of Notebook.js
//Fill in with "description" from props.notebook
export class About extends Component {
render() {
return (
<p className="f8 lh-solid">
</p>
)
}
}
export default About

View File

@ -9,7 +9,7 @@ export class SidebarSwitcher extends Component {
: "dib-m dib-l dib-xl";
return (
<div className="pt2">
<div className={"absolute left-1 top-1 " + popoutSwitcher}>
<a
className="pointer flex-shrink-0"
onClick={() => {

View File

@ -1,4 +1,6 @@
import React, { Component } from 'react'
import { SidebarSwitcher } from './icons/icon-sidebar-switch';
import { Route, Link } from 'react-router-dom';
import { Controlled as CodeMirror } from 'react-codemirror2'
import { dateToDa, stringToSymbol } from '/lib/util';
@ -44,8 +46,9 @@ export class NewPost extends Component {
componentDidUpdate(prevProps, prevState) {
let notebook = this.props.notebooks[this.props.ship][this.props.book];
if (notebook.notes[this.state.awaiting]) {
let popout = (this.props.popout) ? "popout/" : "";
let redirect =
`/~publish/note/${this.props.ship}/${this.props.book}/${this.state.awaiting}`;
`/~publish/${popout}note/${this.props.ship}/${this.props.book}/${this.state.awaiting}`;
this.props.history.push(redirect);
}
}
@ -59,9 +62,11 @@ export class NewPost extends Component {
let submit = !(value === '' || this.state.title === '');
this.setState({body: value, submit: submit});
}
render() {
let notebook = this.props.notebooks[this.props.ship][this.props.book];
const { props, state } = this;
let notebook = props.notebooks[props.ship][props.book];
const options = {
mode: 'markdown',
@ -74,39 +79,66 @@ export class NewPost extends Component {
let date = dateToDa(new Date()).slice(1, -10);
let submitStyle = (this.state.submit)
let submitStyle = (state.submit)
? { color: '#2AA779', cursor: "pointer" }
: { color: '#B1B2B3', cursor: "auto" };
let hrefIndex = props.location.pathname.indexOf("/notebook/");
let publishsubStr = props.location.pathname.substr(hrefIndex)
let popoutHref = `/~publish/popout${publishsubStr}`;
let hiddenOnPopout = (props.popout)
? "" : "dib-m dib-l dib-xl";
return (
<div className="center mw7 f9 h-100">
<div style={{padding: 16}} className="flex-col">
<div className="w-100 tl">
<button disabled={!this.state.submit} style={submitStyle}
onClick={this.postSubmit}>
Publish To {notebook.title}
</button>
<div className="f9 h-100 relative">
<div className="w-100 tl pv4 flex justify-center">
<SidebarSwitcher
sidebarShown={props.sidebarShown}
popout={props.popout}
/>
<button
className="v-mid w-100 mw7 tl pl4 h1"
disabled={!state.submit}
style={submitStyle}
onClick={this.postSubmit}>
Publish To {notebook.title}
</button>
<Link
className={"dn absolute right-1 top-1 " + hiddenOnPopout}
to={popoutHref}
target="_blank">
<img src="/~publish/popout.png"
height={16}
width={16}
/>
</Link>
</div>
<div className="overflow-container mw7 center">
<div style={{ padding: 16 }}>
<input
autoFocus
type="text"
style={{ paddingBottom: 8 }}
className="w-100"
onChange={this.titleChange}
placeholder="New Post"
/>
<div style={{ color: "#7F7F7F" }}>{date}</div>
</div>
<input autoFocus type="text"
style={{paddingBottom: 8, paddingTop: 24}}
className="w-100"
onChange={this.titleChange}
placeholder="New Post" />
<div style={{color:'#7F7F7F'}}>{date}</div>
</div>
<div className="NewPost">
<CodeMirror
value={this.state.body}
options={options}
onBeforeChange={(e, d, v) => this.bodyChange(e, d, v)}
onChange={(editor, data, value) => {}}
/>
<div className="NewPost">
<CodeMirror
value={state.body}
options={options}
onBeforeChange={(e, d, v) => this.bodyChange(e, d, v)}
onChange={(editor, data, value) => {}}
/>
</div>
</div>
</div>
)
);
}
}

View File

@ -1,16 +0,0 @@
import React, { Component } from 'react'
//TODO render props from notebook.js as a div of individual notes in the
//notebook
export class NoteItem extends Component {
render() {
return (
<div>
</div>
)
}
}
export default NoteItem

View File

@ -1,15 +0,0 @@
import React, { Component } from 'react';
import { NoteItem } from './note-item';
//TODO map a list of NoteItems
export class NoteList extends Component {
render() {
return (
<div>
</div>
)
}
}
export default NoteList

View File

@ -14,9 +14,11 @@ export class NoteNavigation extends Component {
let nextUrl = ''
let prevUrl = ''
let popout = (this.props.popout) ? "popout/" : "";
if (this.props.next && this.props.prev) {
nextUrl = `/~publish/note/${this.props.ship}/${this.props.book}/${this.props.next.id}`;
prevUrl = `/~publish/note/${this.props.ship}/${this.props.book}/${this.props.prev.id}`;
nextUrl = `/~publish/${popout}note/${this.props.ship}/${this.props.book}/${this.props.next.id}`;
prevUrl = `/~publish/${popout}note/${this.props.ship}/${this.props.book}/${this.props.prev.id}`;
nextComponent =
<Link to={nextUrl} className="di flex-column tr w-100 pv6 bt bb b--gray3">
<div className="f9 gray2 mb2">Next</div>
@ -32,7 +34,7 @@ export class NoteNavigation extends Component {
</Link>
} else if (this.props.prev) {
prevUrl = `/~publish/note/${this.props.ship}/${this.props.book}/${this.props.prev.id}`;
prevUrl = `/~publish/${popout}note/${this.props.ship}/${this.props.book}/${this.props.prev.id}`;
prevComponent =
<Link to={prevUrl} className="di flex-column w-100 pv6 bt bb b--gray3">
<div className="f9 gray2 mb2">Previous</div>
@ -40,7 +42,7 @@ export class NoteNavigation extends Component {
<div className="f9 gray2">{this.props.prev.date}</div>
</Link>
} else if (this.props.next) {
nextUrl = `/~publish/note/${this.props.ship}/${this.props.book}/${this.props.next.id}`;
nextUrl = `/~publish/${popout}note/${this.props.ship}/${this.props.book}/${this.props.next.id}`;
nextComponent =
<Link to={nextUrl} className="di flex-column tr w-100 pv6 bt bb b--gray3">
<div className="f9 gray2 mb2">Next</div>

View File

@ -1,4 +1,6 @@
import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
import { SidebarSwitcher } from './icons/icon-sidebar-switch';
import { Comments } from './comments';
import { NoteNavigation } from './note-navigation';
import moment from 'moment';
@ -129,18 +131,49 @@ export class Note extends Component {
date: moment(notebook.notes[nextId]["date-created"]).fromNow()
}
let popout = (props.popout) ? "popout/" : "";
let hrefIndex = props.location.pathname.indexOf("/note/");
let publishsubStr = props.location.pathname.substr(hrefIndex);
let popoutHref = `/~publish/popout${publishsubStr}`;
let hiddenOnPopout = props.popout ? "" : "dib-m dib-l dib-xl";
let baseUrl = `/~publish/${popout}notebook/${props.ship}/${props.book}`;
return (
<div className="h-100 overflow-container no-scrollbar"
onScroll={this.onScroll}
ref={(el) => {this.scrollElement = el}}>
<div className="flex justify-center mt4 ph4 pb4">
<div className="w-100 mw6">
<div
className="h-100 no-scrollbar"
onScroll={this.onScroll}
ref={el => {
this.scrollElement = el;
}}>
<div className="h-100 flex flex-column items-center mt4 ph4 pb4">
<div className="w-100 flex justify-center pb6">
<SidebarSwitcher
popout={props.popout}
sidebarShown={props.sidebarShown}
/>
<Link className="f9 w-100 mw6 tl" to={baseUrl}>
{"<- Notebook index"}
</Link>
<Link
to={popoutHref}
className={"dn absolute right-1 top-1 " + hiddenOnPopout}
target="_blank">
<img src="/~publish/popout.png"
height={16}
width={16}
/>
</Link>
</div>
<div className="w-100 mw6 overflow-container">
<div className="flex flex-column">
<div className="f9 mb1">{title}</div>
<div className="flex mb6">
<div className={"di f9 gray2 mr2 " +
((name === author) ? "mono" : "")}>
<div
className={
"di f9 gray2 mr2 " + (name === author ? "mono" : "")
}>
{name}
</div>
<div className="di f9 gray2">{date}</div>
@ -150,20 +183,23 @@ export class Note extends Component {
<ReactMarkdown source={newfile} />
</div>
<NoteNavigation
popout={props.popout}
prev={prev}
next={next}
ship={props.ship}
book={props.book}/>
<Comments ship={props.ship}
book={props.book}
/>
<Comments
ship={props.ship}
book={props.book}
note={props.note}
comments={comments}
contacts={props.contacts}
/>
/>
</div>
</div>
</div>
)
);
}
}

View File

@ -55,7 +55,8 @@ export class NotebookPosts extends Component {
comment = `${note["num-comments"]} Comments`;
}
let date = moment(note["date-created"]).fromNow();
let url = `/~publish/note/${props.host}/${props.notebookName}/${noteId}`
let popout = (props.popout) ? "popout/" : "";
let url = `/~publish/${popout}note/${props.host}/${props.notebookName}/${noteId}`
notes.push(
<Link key={i} to={url}>

View File

@ -1,10 +1,10 @@
import React, { Component } from 'react';
import { Link, Switch, Route } from 'react-router-dom';
import { NoteList } from './note-list';
import { SidebarSwitcher } from './icons/icon-sidebar-switch';
import { NotebookPosts } from './notebook-posts';
import { About } from './about';
import { Subscribers } from './subscribers';
import { Settings } from './settings';
import Sidebar from './sidebar';
//TODO subcomponent logic for subscribers, settings
@ -71,6 +71,13 @@ export class Notebook extends Component {
render() {
const { props } = this;
// popout logic
let hrefIndex = props.location.pathname.indexOf("/notebook/");
let publishsubStr = props.location.pathname.substr(hrefIndex);
let popoutHref = `/~publish/popout${publishsubStr}`;
let hiddenOnPopout = props.popout ? "" : "dib-m dib-l dib-xl";
let notebook = props.notebooks[props.ship][props.book];
let tabStyles = {
@ -87,6 +94,7 @@ export class Notebook extends Component {
let notesList = notebook["notes-by-date"] || [];
let notes = notebook.notes || null;
inner = <NotebookPosts notes={notes}
popout={props.popout}
list={notesList}
host={props.ship}
notebookName={props.book}
@ -106,6 +114,7 @@ export class Notebook extends Component {
break;
}
// displaying nicknames, sigil colors for contacts
let contact = !!(props.ship.substr(1) in props.contacts)
? props.contacts[props.ship.substr(1)] : false;
let name = props.ship;
@ -114,7 +123,8 @@ export class Notebook extends Component {
? contact.nickname : props.ship;
}
let base = `/~publish/notebook/${props.ship}/${props.book}`;
let popout = (props.popout) ? "popout/" : "";
let base = `/~publish/${popout}notebook/${props.ship}/${props.book}`;
let about = base + '/about';
let subs = base + '/subscribers';
let settings = base + '/settings';
@ -142,20 +152,37 @@ export class Notebook extends Component {
<div
className="center mw6 f9 h-100"
style={{ paddingLeft: 16, paddingRight: 16 }}>
<SidebarSwitcher
popout={props.popout}
sidebarShown={props.sidebarShown}
/>
<div className="w-100 dn-m dn-l dn-xl inter pt4 pb6 f9">
<Link to="/~publish">{"<- All Notebooks"}</Link>
</div>
<Link
className={"dn absolute right-1 top-1 " + hiddenOnPopout}
to={popoutHref}
target="_blank"
>
<img src="/~publish/popout.png"
height={16}
width={16}
/>
</Link>
<div
className="h-100 overflow-container no-scrollbar"
className="h-100 pt0 pt8-m pt8-l pt8-xl overflow-container no-scrollbar"
onScroll={this.onScroll}
ref={el => {
this.scrollElement = el;
}}>
<div
className="flex justify-between"
style={{ marginTop: 56, marginBottom: 32 }}>
style={{ marginBottom: 32 }}>
<div className="flex-col">
<div className="mb1">{notebook.title}</div>
<span>
<span className="gray3 mr1">by</span>
<span className={(props.ship === name) ? "mono" : ""}>
<span className={props.ship === name ? "mono" : ""}>
{name}
</span>
</span>

View File

@ -146,7 +146,7 @@ export class Sidebar extends Component {
"overflow-y-hidden " + activeClasses +
(hiddenClasses ? "flex-basis-100-s flex-basis-30-ns" : "dn")
}>
<a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/">
<a className="db dn-m dn-l dn-xl f9 pb3 pl3" href="/">
Landscape
</a>
<div className="w-100">
@ -156,11 +156,6 @@ export class Sidebar extends Component {
<Link to="/~publish/join" className="f9 gray2">
Join Notebook
</Link>
<h2
className={`f8 pt3 pr4 pb3 pl3 black c-default bb b--gray4 mb2
dn-m dn-l dn-xl`}>
Your Notebooks
</h2>
<div className="dropdown relative bb b--gray4">
<select
style={{ WebkitAppearance: "none" }}

View File

@ -55,7 +55,7 @@ export class Root extends Component {
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
sidebarShown={state.sidebarShown}
invites={state.invites}
notebooks={state.notebooks}
contacts={contacts}>
@ -75,7 +75,7 @@ export class Root extends Component {
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
sidebarShown={state.sidebarShown}
invites={state.invites}
notebooks={state.notebooks}
contacts={contacts}>
@ -83,12 +83,14 @@ export class Root extends Component {
</Skeleton>
)
}}/>
<Route exact path="/~publish/(popout)?/notebook/:ship/:notebook/:view?"
<Route exact path="/~publish/:popout?/notebook/:ship/:notebook/:view?"
render={ (props) => {
let view = (props.match.params.view)
? props.match.params.view
: "posts";
let popout = !!props.match.params.popout || false;
let ship = props.match.params.ship || "";
let notebook = props.match.params.notebook || "";
@ -102,10 +104,10 @@ export class Root extends Component {
if (view === "new") {
return (
<Skeleton
popout={false}
popout={popout}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
sidebarShown={state.sidebarShown}
invites={state.invites}
notebooks={state.notebooks}
contacts={contacts}
@ -114,6 +116,8 @@ export class Root extends Component {
notebooks={state.notebooks}
ship={ship}
book={notebook}
sidebarShown={state.sidebarShown}
popout={popout}
{...props}
/>
</Skeleton>
@ -122,10 +126,10 @@ export class Root extends Component {
else {
return (
<Skeleton
popout={false}
popout={popout}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
sidebarShown={state.sidebarShown}
invites={state.invites}
notebooks={state.notebooks}
contacts={contacts}
@ -137,19 +141,23 @@ export class Root extends Component {
book={notebook}
groups={state.groups}
contacts={notebookContacts}
sidebarShown={state.sidebarShown}
popout={popout}
{...props}
/>
</Skeleton>
);
}
}}/>
<Route exact path="/~publish/(popout)?/note/:ship/:notebook/:note"
<Route exact path="/~publish/:popout?/note/:ship/:notebook/:note"
render={ (props) => {
let ship = props.match.params.ship || "";
let notebook = props.match.params.notebook || "";
let path = `${ship}/${notebook}`
let note = props.match.params.note || "";
let popout = !!props.match.params.popout || false;
let bookGroupPath =
state.notebooks[ship][notebook]["subscribers-group-path"];
let notebookContacts = (bookGroupPath in state.contacts)
@ -157,10 +165,10 @@ export class Root extends Component {
return (
<Skeleton
popout={false}
popout={popout}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
sidebarShown={state.sidebarShown}
invites={state.invites}
notebooks={state.notebooks}
contacts={contacts}
@ -171,6 +179,9 @@ export class Root extends Component {
contacts={notebookContacts}
ship={ship}
note={note}
sidebarShown={state.sidebarShown}
popout={popout}
{...props}
/>
</Skeleton>
);

View File

@ -33,7 +33,7 @@ export class Skeleton extends Component {
path={props.path}
invites={props.invites}
/>
<div className={"h-100 w-100 overflow-container " + rightPanelHide} style={{
<div className={"h-100 w-100 relative " + rightPanelHide} style={{
flexGrow: 1,
}}>
{props.children}

View File

@ -1,17 +0,0 @@
import _ from 'lodash';
export class LocalReducer {
reduce(json, state) {
let data = _.get(json, 'local', false);
if (data) {
this.sidebarToggle(data, state);
}
}
sidebarToggle(obj, state) {
let data = _.has(obj, 'sidebarToggle', false);
if (data) {
state.sidebarShown = obj.sidebarToggle;
}
}
}

View File

@ -68,7 +68,7 @@ export class ResponseReducer {
for (var key in json.data.notebook.notes) {
let oldNote = state.notebooks[json.host][json.notebook].notes[key];
if (!(oldNote)) {
state.notebooks[json.host][json.notebook].notes[key] =
state.notebooks[json.host][json.notebook].notes[key] =
json.data.notebook.notes[key];
} else if (!(oldNote.build)) {
state.notebooks[json.host][json.notebook].notes[key]["author"] =
@ -124,7 +124,7 @@ export class ResponseReducer {
for (var key in json.data.notes) {
let oldNote = state.notebooks[json.host][json.notebook].notes[key];
if (!(oldNote)) {
state.notebooks[json.host][json.notebook].notes[key] =
state.notebooks[json.host][json.notebook].notes[key] =
json.data.notes[key];
} else if (!(oldNote.build)) {
state.notebooks[json.host][json.notebook].notes[key]["author"] =
@ -149,7 +149,7 @@ export class ResponseReducer {
}
handleCommentsPage(json, state) {
if (state.notebooks[json.host] &&
if (state.notebooks[json.host] &&
state.notebooks[json.host][json.notebook] &&
state.notebooks[json.host][json.notebook].notes[json.note])
{
@ -186,11 +186,11 @@ export class ResponseReducer {
throw Error("tried to fetch paginated comments, but we don't have the note");
}
}
sidebarToggle(json, state) {
let data = _.has(json, 'sidebarToggle', false);
let data = _.has(json.data, 'sidebarToggle', false);
if (data) {
state.sidebarShown = json.type.local.sidebarToggle;
state.sidebarShown = json.data.sidebarToggle;
}
}

View File

@ -13,7 +13,7 @@ class Store {
permissions: {},
invites: {},
spinner: false,
sidebarShown: false,
sidebarShown: true
}
this.initialReducer = new InitialReducer();