Merge branch 'mp/os1/publish-sidebar' into os1-rc

This commit is contained in:
Logan Allen 2020-02-06 11:37:50 -08:00
commit 69fbf7f13f
8 changed files with 203 additions and 66 deletions

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

@ -167,7 +167,14 @@ a {
outline: 0px solid transparent;
}
.dropdown::after {
content: "⌃";
transform: rotate(180deg);
position: absolute;
right: 8px;
top: 16px;
color: #7f7f7f;
}
.no-scrollbar {
-ms-overflow-style: none;
scrollbar-width: none;

View File

@ -1,13 +1,33 @@
import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
//TODO take props and render entry in sidebar
export class NotebookItem extends Component {
render() {
let { props } = this;
let selectedClass = (props.selected) ? "bg-gray5 b--gray4" : "b--gray4";
let postCount = (props.total === 1)
? `${props.total} post` : `${props.total} posts`;
let unread = (props.unreadCount > 0)
? `${props.unreadCount} unread` : "";
return (
<div>
</div>
)
<Link
to={"/~publish/notebook/" + props.path}>
<div className={"w-100 v-mid f9 pl4 bb " + selectedClass}>
<p className="f9 pt1">{props.title}</p>
<p className="f9 mono gray2">by {props.author}</p>
<p className="f9 pb1">
{postCount}
<span className="green2 ml3">
{unread}
</span>
</p>
</div>
</Link>
);
}
}

View File

@ -6,62 +6,163 @@ export class Sidebar extends Component {
constructor(props) {
super(props);
this.state = {
sort: "oldest"
sort: "oldest",
sortedBooks: new Map()
}
this.sort = this.sort.bind(this);
this.sortChange = this.sortChange.bind(this);
}
componentDidMount() {
this.sort();
}
componentDidUpdate(prevProps, prevState) {
if ((prevState.sort !== this.state.sort) || (prevProps !== this.props)) {
this.sort();
}
}
sort() {
let { props, state } = this;
let notebooks = new Map();
Object.keys(props.notebooks).map(host => {
Object.keys(props.notebooks[host]).map(notebook => {
let title = `${host}/${notebook}`;
notebooks.set(title, props.notebooks[host][notebook])
})
});
switch (state.sort) {
case "oldest":
notebooks = new Map(
[...notebooks.entries()].sort(
(a, b) => {
if ((a[1]) && (b[1])) {
return a[1]["date-created"] - b[1]["date-created"]
}
}
)
);
break;
case "newest":
notebooks = new Map(
[...notebooks.entries()].sort(
(a, b) => {
if ((a[1]) && (b[1])) {
return b[1]["date-created"] - a[1]["date-created"]
}
}
)
);
break;
case "alphabetical":
notebooks = new Map(
[...notebooks.entries()].sort((a, b) => {
if ((a[1]) && (b[1])) {
if (a[1]["title"].toLowerCase() < b[1]["title"].toLowerCase()) {
return -1;
}
if (a[1]["title"].toLowerCase() > b[1]["title"].toLowerCase()) {
return 1;
}
return 0;
}
})
);
break;
case "reverseAlphabetical":
notebooks = new Map(
[...notebooks.entries()].sort((a, b) => {
if ((a[1]) && (b[1])) {
if (a[1]["title"].toLowerCase() > b[1]["title"].toLowerCase()) {
return -1;
}
if (a[1]["title"].toLowerCase() < b[1]["title"].toLowerCase()) {
return 1;
}
return 0;
}
})
);
break;
default:
break;
}
this.setState({ sortedBooks: notebooks });
}
sortChange(event) {
this.setState({sort: event.target.value});
}
render() {
const { props, state } = this;
let activeClasses = (this.props.active === "sidebar") ? " " : "dn-s ";
let activeClasses = (props.active === "sidebar") ? " " : "dn-s ";
let hiddenClasses = true;
if (this.props.popout) {
if (props.popout) {
hiddenClasses = false;
} else {
hiddenClasses = this.props.sidebarShown;
hiddenClasses = props.sidebarShown;
};
//TODO render notebook list from state
// (make a new array of all notebooks from {author: {notebook}}
// prop.notebook obj, case-switch the sorting from this.state.sort, and map it)
//TODO allow for user sorting of notebook list
//
//(reactive dropdown -> amends state -> sort by state prop)
//
let notebooks = <div></div>
let notebookItems = [...state.sortedBooks].map(([path, book]) => {
let selected = (props.path === path);
let author = path.split("/")[0];
return (
<NotebookItem
key={book.title}
title={book.title}
author={author}
path={path}
total={book["num-notes"]}
unreadCount={book["num-unread"]}
selected={selected}
/>
);
})
let notebooks = <div>{notebookItems}</div>
return (
<div className={`bn br-m br-l br-xl b--gray4 b--gray2-d lh-copy h-100
flex-shrink-0 mw-300-ns pt3 pt0-m pt0-l pt0-xl
relative ` + activeClasses + ((hiddenClasses)
? "flex-basis-100-s flex-basis-30-ns"
: "dn")}>
<a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/"> Landscape</a>
<div className="w-100 pa4">
<Link
to="/~publish/new"
className="green2 mr4 f9">
New Notebook
<div
className={
"bn br-m br-l br-xl b--gray4 b--gray2-d lh-copy h-100 " +
"flex-shrink-0 mw-300-ns pt3 pt0-m pt0-l pt0-xl relative " +
activeClasses +
(hiddenClasses ? "flex-basis-100-s flex-basis-30-ns" : "dn")
}>
<a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/">
Landscape
</a>
<div className="w-100">
<Link to="/~publish/new" className="green2 mr4 f9 pl4 pt4 dib">
New Notebook
</Link>
<Link
to="/~publish/join"
className="f9 gray2">
Join Notebook
<Link to="/~publish/join" className="f9 gray2">
Join Notebook
</Link>
</div>
<div className="overflow-y-scroll h-100">
<h2 className={`f8 pt1 pr4 pb3 pl3 black c-default bb b--gray4 mb2
<h2
className={`f8 pt3 pr4 pb3 pl3 black c-default bb b--gray4 mb2
dn-m dn-l dn-xl`}>
Your Notebooks
Your Notebooks
</h2>
{/*TODO Dropdown attached to this.state.sort */}
{notebooks}
<div className="dropdown relative bb b--gray4">
<select
style={{ WebkitAppearance: "none" }}
className="pl4 pv6 f9 bg-white bg-black-d white-d bn w-100 inter"
value={this.state.sort}
onChange={this.sortChange}>
<option value="oldest">Oldest Notebooks First</option>
<option value="newest">Newest Notebooks First</option>
<option value="alphabetical">Alphabetical A -> Z</option>
<option value="reverseAlphabetical">Alphabetical Z -> A</option>
</select>
</div>
</div>
<div className="overflow-y-scroll h-100">{notebooks}</div>
</div>
);
}
}
export default Sidebar;
export default Sidebar;

View File

@ -78,14 +78,17 @@ export class Root extends Component {
let ship = props.match.params.ship || "";
let notebook = props.match.params.notebook || "";
let path = `${ship}/${notebook}`;
if (view === "new") {
return (
<Skeleton
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
notebooks={state.notebooks}>
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
notebooks={state.notebooks}
path={path}>
<NewPost
notebooks={state.notebooks}
ship={ship}
@ -93,46 +96,51 @@ export class Root extends Component {
{...props}
/>
</Skeleton>
)
);
}
else {
return (
<Skeleton
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
notebooks={state.notebooks}>
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
notebooks={state.notebooks}
path={path}>
<Notebook
notebooks={state.notebooks}
view={view}
ship={ship}
book={notebook}
{...props}/>
{...props}
/>
</Skeleton>
)
);
}
}}/>
<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 || "";
return (
<Skeleton
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
notebooks={state.notebooks}>
popout={false}
active={"rightPanel"}
rightPanelHide={false}
sidebarShown={true}
notebooks={state.notebooks}
path={path}>
<Note
notebooks={state.notebooks}
book={notebook}
ship={ship}
note={note}/>
note={note}
/>
</Skeleton>
)
);
}}/>
</BrowserRouter>
)

View File

@ -29,6 +29,7 @@ export class Skeleton extends Component {
sidebarShown={props.sidebarShown}
active={props.active}
notebooks={props.notebooks}
path={props.path}
/>
<div className={"h-100 w-100 overflow-container " + rightPanelHide} style={{
flexGrow: 1,