,
};
@@ -36,13 +44,13 @@ type Props = {
@keydown(['/', 't'])
search() {
- if (this.props.auth.isAuthenticated)
+ if (this.props.auth.authenticated)
_.defer(() => this.props.history.push('/search'));
}
@keydown(['d'])
dashboard() {
- if (this.props.auth.isAuthenticated)
+ if (this.props.auth.authenticated)
_.defer(() => this.props.history.push('/'));
}
@@ -51,7 +59,7 @@ type Props = {
};
render() {
- const { auth, user } = this.props;
+ const { user, auth, ui, collections } = this.props;
return (
@@ -69,78 +77,65 @@ type Props = {
{this.props.notifications}
-
-
- Atlas
-
- {this.props.title}
-
-
-
-
-
- {this.props.actions}
-
- {auth.authenticated &&
- user &&
-
- {this.props.search &&
-
-
-
-
-
-
- }
- }>
-
- Settings
-
-
-
- Keyboard shortcuts
-
-
-
- API
-
- Logout
-
- }
-
-
-
+
+ {auth.authenticated &&
+ user &&
+
+
+
+ Atlas
+
+ }>
+
+ Settings
+
+
+
+ Keyboard shortcuts
+
+
+
+ API
+
+ Logout
+
+
-
- {this.props.children}
-
+
+
+ Search
+
+
+ Dashboard
+ Starred
+
+
+ {ui.activeCollection
+ ?
+ : }
+
+
+ }
+
+
+ {this.props.children}
+
+
);
}
}
const Container = styled(Flex)`
+ position: relative;
width: 100%;
height: 100%;
`;
-const Header = styled(Flex)`
- display: flex;
- justify-content: space-between;
- align-items: center;
-
- padding: 0 20px;
-
- z-index: 1;
- background: #fff;
- height: ${headerHeight};
- border-bottom: 1px solid #eee;
-
- font-size: 14px;
- line-height: 1;
-`;
-
const LogoLink = styled(Link)`
+ margin-top: 5px;
font-family: 'Atlas Grotesk';
font-weight: bold;
color: ${textColor};
@@ -148,28 +143,6 @@ const LogoLink = styled(Link)`
font-size: 16px;
`;
-const Title = styled.span`
- color: #ccc;
-
- a {
- color: #ccc;
- }
-
- a:hover {
- color: ${textColor};
- }
-`;
-
-const Search = styled(Flex)`
- margin: 0 5px;
- padding: 15px 5px 0 5px;
- cursor: pointer;
-`;
-
-const SearchIcon = styled.img`
- height: 20px;
-`;
-
const Avatar = styled.img`
width: 24px;
height: 24px;
@@ -181,8 +154,31 @@ const MenuLink = styled(Link)`
`;
const Content = styled(Flex)`
- height: 100%;
overflow: scroll;
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: ${props => (props.editMode ? 0 : '250px')};
+ transition: left 200ms ease-in-out;
`;
-export default withRouter(inject('user', 'auth')(Layout));
+const Sidebar = styled(Flex)`
+ width: 250px;
+ margin-left: ${props => (props.editMode ? '-250px' : 0)};
+ padding: 10px 20px;
+ background: rgba(250, 251, 252, 0.71);
+ border-right: 1px solid #eceff3;
+ transition: margin-left 200ms ease-in-out;
+`;
+
+const Header = styled(Flex)`
+ margin-bottom: 20px;
+`;
+
+const LinkSection = styled(Flex)`
+ margin-bottom: 20px;
+ flex-direction: column;
+`;
+
+export default withRouter(inject('user', 'auth', 'ui', 'collections')(Layout));
diff --git a/frontend/components/Layout/components/SidebarCollection/SidebarCollection.js b/frontend/components/Layout/components/SidebarCollection/SidebarCollection.js
new file mode 100644
index 00000000..de6a1244
--- /dev/null
+++ b/frontend/components/Layout/components/SidebarCollection/SidebarCollection.js
@@ -0,0 +1,39 @@
+// @flow
+import React from 'react';
+import { observer } from 'mobx-react';
+import { Flex } from 'reflexbox';
+import styled from 'styled-components';
+
+import SidebarLink from '../SidebarLink';
+
+import Collection from 'models/Collection';
+
+type Props = {
+ collection: Collection,
+};
+
+const SidebarCollection = ({ collection }: Props) => {
+ if (collection) {
+ return (
+
+
+ {collection.documents.map(document => (
+
+ {document.title}
+
+ ))}
+
+ );
+ }
+ return null;
+};
+
+const Header = styled(Flex)`
+ font-size: 11px;
+ font-weight: 500;
+ text-transform: uppercase;
+ color: #9FA6AB;
+ letter-spacing: 0.04em;
+`;
+
+export default observer(SidebarCollection);
diff --git a/frontend/components/Layout/components/SidebarCollection/index.js b/frontend/components/Layout/components/SidebarCollection/index.js
new file mode 100644
index 00000000..80b2a046
--- /dev/null
+++ b/frontend/components/Layout/components/SidebarCollection/index.js
@@ -0,0 +1,3 @@
+// @flow
+import SidebarCollection from './SidebarCollection';
+export default SidebarCollection;
diff --git a/frontend/components/Layout/components/SidebarCollectionList/SidebarCollectionList.js b/frontend/components/Layout/components/SidebarCollectionList/SidebarCollectionList.js
new file mode 100644
index 00000000..0115ec66
--- /dev/null
+++ b/frontend/components/Layout/components/SidebarCollectionList/SidebarCollectionList.js
@@ -0,0 +1,36 @@
+// @flow
+import React from 'react';
+import { observer, inject } from 'mobx-react';
+import { Flex } from 'reflexbox';
+import styled from 'styled-components';
+
+import SidebarLink from '../SidebarLink';
+
+import CollectionsStore from 'stores/CollectionsStore';
+
+type Props = {
+ collections: CollectionsStore,
+};
+
+const SidebarCollectionList = observer(({ collections }: Props) => {
+ return (
+
+
+ {collections.data.map(collection => (
+
+ {collection.name}
+
+ ))}
+
+ );
+});
+
+const Header = styled(Flex)`
+ font-size: 11px;
+ font-weight: 500;
+ text-transform: uppercase;
+ color: #9FA6AB;
+ letter-spacing: 0.04em;
+`;
+
+export default inject('collections')(SidebarCollectionList);
diff --git a/frontend/components/Layout/components/SidebarCollectionList/index.js b/frontend/components/Layout/components/SidebarCollectionList/index.js
new file mode 100644
index 00000000..ed4ba40c
--- /dev/null
+++ b/frontend/components/Layout/components/SidebarCollectionList/index.js
@@ -0,0 +1,3 @@
+// @flow
+import SidebarCollectionList from './SidebarCollectionList';
+export default SidebarCollectionList;
diff --git a/frontend/components/Layout/components/SidebarLink/SidebarLink.js b/frontend/components/Layout/components/SidebarLink/SidebarLink.js
new file mode 100644
index 00000000..73543635
--- /dev/null
+++ b/frontend/components/Layout/components/SidebarLink/SidebarLink.js
@@ -0,0 +1,26 @@
+// @flow
+import React from 'react';
+import { observer } from 'mobx-react';
+import { NavLink } from 'react-router-dom';
+import { Flex } from 'reflexbox';
+import styled from 'styled-components';
+
+const activeStyle = {
+ color: '#000000',
+};
+
+const SidebarLink = observer(props => (
+
+
+
+));
+
+const LinkContainer = styled(Flex)`
+ padding: 5px 0;
+
+ a {
+ color: #848484;
+ }
+`;
+
+export default SidebarLink;
diff --git a/frontend/components/Layout/components/SidebarLink/index.js b/frontend/components/Layout/components/SidebarLink/index.js
new file mode 100644
index 00000000..eabfd77f
--- /dev/null
+++ b/frontend/components/Layout/components/SidebarLink/index.js
@@ -0,0 +1,3 @@
+// @flow
+import SidebarLink from './SidebarLink';
+export default SidebarLink;
diff --git a/frontend/components/Sidebar/Sidebar.js b/frontend/components/Sidebar/Sidebar.js
deleted file mode 100644
index d4a9f58b..00000000
--- a/frontend/components/Sidebar/Sidebar.js
+++ /dev/null
@@ -1,85 +0,0 @@
-// @flow
-import React from 'react';
-import { observer } from 'mobx-react';
-import { withRouter } from 'react-router-dom';
-
-import { Flex } from 'reflexbox';
-import Tree from 'components/Tree';
-import Separator from './components/Separator';
-
-import styles from './Sidebar.scss';
-import classNames from 'classnames/bind';
-const cx = classNames.bind(styles);
-
-import SidebarStore from './SidebarStore';
-
-type Props = {
- open?: boolean,
- onToggle: Function,
- navigationTree: Object,
- onNavigationUpdate: Function,
- onNodeCollapse: Function,
- history: Object,
-};
-
-@observer class Sidebar extends React.Component {
- props: Props;
- store: SidebarStore;
-
- constructor(props: Props) {
- super(props);
-
- this.store = new SidebarStore();
- }
-
- toggleEdit = (e: MouseEvent) => {
- e.preventDefault();
- this.store.toggleEdit();
- };
-
- render() {
- return (
-
- {this.props.open &&
-
-
-
-
-
- {this.store.isEditing &&
-
- Drag & drop to organize
- }
-
- {!this.store.isEditing ? 'Organize documents' : 'Done'}
-
-
- }
-
-
-
-
- );
- }
-}
-
-export default withRouter(Sidebar);
diff --git a/frontend/components/Sidebar/Sidebar.scss b/frontend/components/Sidebar/Sidebar.scss
deleted file mode 100644
index dc46e94e..00000000
--- a/frontend/components/Sidebar/Sidebar.scss
+++ /dev/null
@@ -1,56 +0,0 @@
-@import '~styles/constants.scss';
-
-.sidebar {
- position: relative;
- width: 250px;
- border-right: 1px solid #eee;
- font-size: 13px;
-}
-
-.sidebarToggle {
- display: flex;
- position: relative;
- width: 60px;
- cursor: pointer;
- justify-content: center;
-
- &:hover {
- background-color: #f5f5f5;
-
- .menuIcon {
- opacity: 1;
- }
- }
-}
-
-.menuIcon {
- margin-top: 18px;
- height: 28px;
- opacity: 0.15;
-}
-
-.content {
- padding: 20px 20px 20px 5px;
-}
-
-.tree {
-
-}
-
-.actions {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- background-color: #fff;
- padding: 10px 20px;
- height: 40px;
-}
-
-.action {
- color: $gray;
-
- &.active {
- color: $textColor;
- }
-}
diff --git a/frontend/components/Sidebar/SidebarStore.js b/frontend/components/Sidebar/SidebarStore.js
deleted file mode 100644
index b57621c5..00000000
--- a/frontend/components/Sidebar/SidebarStore.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// @flow
-import { observable, action } from 'mobx';
-
-class SidebarStore {
- @observable isEditing = false;
-
- /* Actions */
-
- @action toggleEdit = () => {
- this.isEditing = !this.isEditing;
- };
-}
-
-export default SidebarStore;
diff --git a/frontend/components/Sidebar/components/Separator/Separator.js b/frontend/components/Sidebar/components/Separator/Separator.js
deleted file mode 100644
index 8cc898a7..00000000
--- a/frontend/components/Sidebar/components/Separator/Separator.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// @flow
-import React from 'react';
-
-import styles from './Separator.scss';
-
-class Separator extends React.Component {
- render() {
- return (
-
- ยท
-
- );
- }
-}
-
-export default Separator;
diff --git a/frontend/components/Sidebar/components/Separator/Separator.scss b/frontend/components/Sidebar/components/Separator/Separator.scss
deleted file mode 100644
index 7aa44d11..00000000
--- a/frontend/components/Sidebar/components/Separator/Separator.scss
+++ /dev/null
@@ -1,6 +0,0 @@
-@import '~styles/constants.scss';
-
-.separator {
- padding: 0 10px;
- color: $lightGray;
-}
diff --git a/frontend/components/Sidebar/components/Separator/index.js b/frontend/components/Sidebar/components/Separator/index.js
deleted file mode 100644
index 4b828564..00000000
--- a/frontend/components/Sidebar/components/Separator/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// @flow
-import Separator from './Separator';
-export default Separator;
diff --git a/frontend/components/Sidebar/index.js b/frontend/components/Sidebar/index.js
deleted file mode 100644
index c1b441c2..00000000
--- a/frontend/components/Sidebar/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// @flow
-import Sidebar from './Sidebar';
-export default Sidebar;
diff --git a/frontend/components/Tree/Node.js b/frontend/components/Tree/Node.js
deleted file mode 100644
index ba8157a3..00000000
--- a/frontend/components/Tree/Node.js
+++ /dev/null
@@ -1,139 +0,0 @@
-/* eslint-disable */
-import React from 'react';
-
-import styles from './Tree.scss';
-import classNames from 'classnames/bind';
-const cx = classNames.bind(styles);
-
-class Node extends React.Component {
- displayName: 'UITreeNode';
-
- renderCollapse = () => {
- const index = this.props.index;
-
- if (index.children && index.children.length) {
- const collapsed = index.node.collapsed;
-
- return (
-
-
-
- );
- }
-
- return null;
- };
-
- renderChildren = () => {
- const index = this.props.index;
- const tree = this.props.tree;
- const dragging = this.props.dragging;
-
- if (index.children && index.children.length) {
- const childrenStyles = {};
-
- if (!this.props.rootNode) {
- if (index.node.collapsed) childrenStyles.display = 'none';
- childrenStyles.paddingLeft = `${this.props.paddingLeft}px`;
- }
-
- return (
-
- {index.children.map(child => {
- const childIndex = tree.getIndex(child);
- return (
-
- );
- })}
-
- );
- }
-
- return null;
- };
-
- isModifying = () => {
- return this.props.allowUpdates && !this.props.rootNode;
- };
-
- onClick = () => {
- const index = this.props.index;
- const node = index.node;
- if (!this.isModifying()) this.props.history.push(node.url);
- };
-
- render() {
- const index = this.props.index;
- const dragging = this.props.dragging;
- const node = index.node;
- const style = {};
-
- return (
-
-
e.stopPropagation()
- : this.handleMouseDown
- }
- >
- {!this.props.rootNode && this.renderCollapse()}
-
- {node.title}
-
-
- {this.renderChildren()}
-
- );
- }
-
- handleCollapse = e => {
- e.stopPropagation();
- const nodeId = this.props.index.id;
- if (this.props.onCollapse) this.props.onCollapse(nodeId);
- };
-
- handleMouseDown = e => {
- const nodeId = this.props.index.id;
- const dom = this.refs.inner;
-
- if (this.props.onDragStart) {
- this.props.onDragStart(nodeId, dom, e);
- }
- };
-}
-
-module.exports = Node;
diff --git a/frontend/components/Tree/Tree.js b/frontend/components/Tree/Tree.js
deleted file mode 100644
index 7296da9a..00000000
--- a/frontend/components/Tree/Tree.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/* eslint-disable */
-const Tree = require('js-tree');
-const proto = Tree.prototype;
-
-proto.updateNodesPosition = function() {
- let top = 1;
- let left = 1;
- const root = this.getIndex(1);
- const self = this;
-
- root.top = top++;
- root.left = left++;
-
- if (root.children && root.children.length) {
- walk(root.children, root, left, root.node.collapsed);
- }
-
- function walk(children, parent, left, collapsed) {
- let height = 1;
- children.forEach(id => {
- const node = self.getIndex(id);
- if (collapsed) {
- node.top = null;
- node.left = null;
- } else {
- node.top = top++;
- node.left = left;
- }
-
- if (node.children && node.children.length) {
- height += walk(
- node.children,
- node,
- left + 1,
- collapsed || node.node.collapsed
- );
- } else {
- node.height = 1;
- height += 1;
- }
- });
-
- if (parent.node.collapsed) parent.height = 1;
- else parent.height = height;
- return parent.height;
- }
-};
-
-proto.move = function(fromId, toId, placement) {
- if (fromId === toId || toId === 1) return;
-
- const obj = this.remove(fromId);
- let index = null;
-
- if (placement === 'before') index = this.insertBefore(obj, toId);
- else if (placement === 'after') index = this.insertAfter(obj, toId);
- else if (placement === 'prepend') index = this.prepend(obj, toId);
- else if (placement === 'append') index = this.append(obj, toId);
-
- // todo: perf
- this.updateNodesPosition();
- return index;
-};
-
-proto.getNodeByTop = function(top) {
- const indexes = this.indexes;
- for (const id in indexes) {
- if (indexes.hasOwnProperty(id)) {
- if (indexes[id].top === top) return indexes[id];
- }
- }
-};
-
-module.exports = Tree;
diff --git a/frontend/components/Tree/Tree.scss b/frontend/components/Tree/Tree.scss
deleted file mode 100644
index 22c70218..00000000
--- a/frontend/components/Tree/Tree.scss
+++ /dev/null
@@ -1,87 +0,0 @@
-@mixin no-select {
- -webkit-user-select: none;
- -khtml-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-
-.tree {
- @include no-select;
- padding: 20px 20px 20px 5px;
- overflow: scroll;
- position: absolute;
- top: 0;
- bottom: 40px;
- right: 0;
- left: 0;
-}
-
-.draggable {
- position: absolute;
- opacity: 0.8;
- @include no-select;
-}
-
-.node {
- &.placeholder > * {
- visibility: hidden;
- }
-
- &.placeholder {
- border: 1px dashed #ccc;
- }
-
- .inner {
- position: relative;
- cursor: pointer;
- padding-left: 10px;
- }
-
- .collapse {
- position: absolute;
- left: 0;
- cursor: pointer;
-
- width: 20px;
- height: 25px;
- }
-
- .caretRight {
- margin-top: 3px;
- margin-left: -3px;
- }
-
- .caretDown {
- transform: rotate(90deg);
- margin-left: -4px;
- margin-top: 2px;
- }
-}
-
-.node {
- &.placeholder {
- border: 1px dashed #1385e5;
- }
-
- .nodeLabel {
- display: inline-block;
- width: 100%;
- padding: 4px 5px 0;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
-
- &.isModifying {
- cursor: move;
- }
-
- &.isActive {
- background-color: #31363F;
- }
- }
-
- .rootLabel {
- color: #ccc;
- }
-}
diff --git a/frontend/components/Tree/UiTree.js b/frontend/components/Tree/UiTree.js
deleted file mode 100644
index 02d774d3..00000000
--- a/frontend/components/Tree/UiTree.js
+++ /dev/null
@@ -1,275 +0,0 @@
-/* eslint-disable */
-const React = require('react');
-const Tree = require('./Tree');
-const Node = require('./Node');
-
-import styles from './Tree.scss';
-
-export default React.createClass({
- displayName: 'UITree',
-
- propTypes: {
- tree: React.PropTypes.object.isRequired,
- paddingLeft: React.PropTypes.number,
- onCollapse: React.PropTypes.func,
- allowUpdates: React.PropTypes.bool,
- history: React.PropTypes.object,
- },
-
- getDefaultProps() {
- return {
- paddingLeft: 20,
- };
- },
-
- getInitialState() {
- return this.init(this.props);
- },
-
- componentWillReceiveProps(nextProps) {
- if (!this._updated) this.setState(this.init(nextProps));
- else this._updated = false;
- },
-
- init(props) {
- const tree = new Tree(props.tree);
- tree.isNodeCollapsed = props.isNodeCollapsed;
- tree.changeNodeCollapsed = props.changeNodeCollapsed;
- tree.updateNodesPosition();
-
- return {
- tree,
- dragging: {
- id: null,
- x: null,
- y: null,
- w: null,
- h: null,
- },
- };
- },
-
- getDraggingDom() {
- const tree = this.state.tree;
- const dragging = this.state.dragging;
-
- if (dragging && dragging.id) {
- const draggingIndex = tree.getIndex(dragging.id);
- const draggingStyles = {
- top: dragging.y,
- left: dragging.x,
- width: dragging.w,
- };
-
- return (
-
-
-
- );
- }
-
- return null;
- },
-
- render() {
- const tree = this.state.tree;
- const dragging = this.state.dragging;
- const draggingDom = this.getDraggingDom();
-
- return (
-
- {draggingDom}
-
-
- );
- },
-
- dragStart(id, dom, e) {
- this.dragging = {
- id,
- w: dom.offsetWidth,
- h: dom.offsetHeight,
- x: dom.offsetLeft,
- y: dom.offsetTop,
- };
-
- this._startX = dom.offsetLeft;
- this._startY = dom.offsetTop;
- this._offsetX = e.clientX;
- this._offsetY = e.clientY;
- this._start = true;
-
- window.addEventListener('mousemove', this.drag);
- window.addEventListener('mouseup', this.dragEnd);
- },
-
- // oh
- drag(e) {
- if (this._start) {
- this.setState({
- dragging: this.dragging,
- });
- this._start = false;
- }
-
- const tree = this.state.tree;
- const dragging = this.state.dragging;
- const paddingLeft = this.props.paddingLeft;
- let newIndex = null;
- let index = tree.getIndex(dragging.id);
- const collapsed = index.node.collapsed;
-
- const _startX = this._startX;
- const _startY = this._startY;
- const _offsetX = this._offsetX;
- const _offsetY = this._offsetY;
-
- const pos = {
- x: _startX + e.clientX - _offsetX,
- y: _startY + e.clientY - _offsetY,
- };
- dragging.x = pos.x;
- dragging.y = pos.y;
-
- const diffX = dragging.x - paddingLeft / 2 - (index.left - 2) * paddingLeft;
- const diffY = dragging.y - dragging.h / 2 - (index.top - 2) * dragging.h;
-
- if (diffX < 0) {
- // left
- if (index.parent && !index.next) {
- newIndex = tree.move(index.id, index.parent, 'after');
- }
- } else if (diffX > paddingLeft) {
- // right
- if (index.prev) {
- const prevNode = tree.getIndex(index.prev).node;
- if (!prevNode.collapsed && !prevNode.leaf) {
- newIndex = tree.move(index.id, index.prev, 'append');
- }
- }
- }
-
- if (newIndex) {
- index = newIndex;
- newIndex.node.collapsed = collapsed;
- dragging.id = newIndex.id;
- }
-
- if (diffY < 0) {
- // up
- const above = tree.getNodeByTop(index.top - 1);
- newIndex = tree.move(index.id, above.id, 'before');
- } else if (diffY > dragging.h) {
- // down
- if (index.next) {
- let below = tree.getIndex(index.next);
- if (below.children && below.children.length && !below.node.collapsed) {
- newIndex = tree.move(index.id, index.next, 'prepend');
- } else {
- newIndex = tree.move(index.id, index.next, 'after');
- }
- } else {
- let below = tree.getNodeByTop(index.top + index.height);
- if (below && below.parent !== index.id) {
- if (below.children && below.children.length) {
- newIndex = tree.move(index.id, below.id, 'prepend');
- } else {
- newIndex = tree.move(index.id, below.id, 'after');
- }
- }
- }
- }
-
- if (newIndex) {
- newIndex.node.collapsed = collapsed;
- dragging.id = newIndex.id;
- }
-
- this.setState({
- tree,
- dragging,
- });
- },
-
- dragEnd() {
- this.setState({
- dragging: {
- id: null,
- x: null,
- y: null,
- w: null,
- h: null,
- },
- });
-
- this.change(this.state.tree);
- window.removeEventListener('mousemove', this.drag);
- window.removeEventListener('mouseup', this.dragEnd);
- },
-
- change(tree) {
- this._updated = true;
- if (this.props.onChange) this.props.onChange(tree.obj);
- },
-
- toggleCollapse(nodeId) {
- const tree = this.state.tree;
- const index = tree.getIndex(nodeId);
- const node = index.node;
- node.collapsed = !node.collapsed;
- tree.updateNodesPosition();
-
- this.setState({
- tree,
- });
-
- if (this.props.onCollapse) this.props.onCollapse(node.id, node.collapsed);
- },
-
- // buildTreeNumbering(tree) {
- // const numberBuilder = (index, node, parentNumbering) => {
- // let numbering = parentNumbering ? `${parentNumbering}.${index}` : index;
- // let children;
- // if (node.children) {
- // children = node.children.map((child, childIndex) => {
- // return numberBuilder(childIndex+1, child, numbering);
- // });
- // }
-
- // const data = {
- // module: {
- // ...node.module,
- // index: numbering,
- // }
- // }
- // if (children) {
- // data.children = children;
- // }
-
- // return data;
- // };
-
- // const newTree = {...tree};
- // newTree.children = [];
- // tree.children.forEach((child, index) => {
- // newTree.children.push(numberBuilder(index+1, child));
- // })
- // return newTree;
- // }
-});
diff --git a/frontend/components/Tree/assets/chevron.svg b/frontend/components/Tree/assets/chevron.svg
deleted file mode 100644
index 4daab592..00000000
--- a/frontend/components/Tree/assets/chevron.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/frontend/components/Tree/index.js b/frontend/components/Tree/index.js
deleted file mode 100644
index fe1ac2ee..00000000
--- a/frontend/components/Tree/index.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// @flow
-import UiTree from './UiTree';
-export default UiTree;
diff --git a/frontend/index.js b/frontend/index.js
index 901089c8..6a8224ab 100644
--- a/frontend/index.js
+++ b/frontend/index.js
@@ -31,6 +31,8 @@ import Flatpage from 'scenes/Flatpage';
import ErrorAuth from 'scenes/ErrorAuth';
import Error404 from 'scenes/Error404';
+import Layout from 'components/Layout';
+
import flatpages from 'static/flatpages';
let DevTools;
@@ -94,32 +96,35 @@ render(
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
+
+
+
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
diff --git a/frontend/scenes/Collection/Collection.js b/frontend/scenes/Collection/Collection.js
index 96210a58..cd00815c 100644
--- a/frontend/scenes/Collection/Collection.js
+++ b/frontend/scenes/Collection/Collection.js
@@ -3,11 +3,10 @@ import React from 'react';
import { observer, inject } from 'mobx-react';
import { Redirect } from 'react-router';
import _ from 'lodash';
-import { notFoundUrl } from 'utils/routeHelpers';
import CollectionsStore from 'stores/CollectionsStore';
+import CollectionStore from './CollectionStore';
-import Layout from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import PreviewLoading from 'components/PreviewLoading';
@@ -16,50 +15,26 @@ type Props = {
match: Object,
};
-type State = {
- redirectUrl: ?string,
-};
-
@observer class Collection extends React.Component {
props: Props;
- state: State;
+ store: CollectionStore;
constructor(props) {
super(props);
- this.state = {
- redirectUrl: null,
- };
+ this.store = new CollectionStore();
}
componentDidMount = () => {
const { id } = this.props.match.params;
- this.props.collections
- .getById(id)
- .then(collection => {
- if (collection.type !== 'atlas')
- throw new Error('TODO code up non-atlas collections');
-
- this.setState({
- redirectUrl: collection.documents[0].url,
- });
- })
- .catch(() => {
- this.setState({
- redirectUrl: notFoundUrl(),
- });
- });
+ this.store.fetchCollection(id);
};
render() {
- return (
-
- {this.state.redirectUrl && }
-
-
+ return this.store.redirectUrl
+ ?
+ :
-
-
- );
+ ;
}
}
export default inject('collections')(Collection);
diff --git a/frontend/scenes/Collection/CollectionStore.js b/frontend/scenes/Collection/CollectionStore.js
index 8aa446e8..16569b8e 100644
--- a/frontend/scenes/Collection/CollectionStore.js
+++ b/frontend/scenes/Collection/CollectionStore.js
@@ -1,37 +1,30 @@
// @flow
-import { observable, action, computed } from 'mobx';
+import { observable, action } from 'mobx';
import invariant from 'invariant';
import { client } from 'utils/ApiClient';
-import Collection from 'models/Collection';
-
-const store = new class AtlasStore {
- @observable collection: ?(Collection & { recentDocuments?: Object[] });
+import { notFoundUrl } from 'utils/routeHelpers';
+class CollectionStore {
+ @observable redirectUrl: ?string;
@observable isFetching = true;
- /* Computed */
-
- @computed get isLoaded(): boolean {
- return !this.isFetching && !!this.collection;
- }
-
/* Actions */
- @action fetchCollection = async (id: string, successCallback: Function) => {
+ @action fetchCollection = async (id: string) => {
this.isFetching = true;
- this.collection = null;
try {
const res = await client.get('/collections.info', { id });
invariant(res && res.data, 'Data should be available');
const { data } = res;
- this.collection = new Collection(data);
- successCallback(data);
+
+ if (data.type === 'atlas') this.redirectUrl = data.documents[0].url;
+ else throw new Error('TODO code up non-atlas collections');
} catch (e) {
- console.error('Something went wrong');
+ this.redirectUrl = notFoundUrl();
}
this.isFetching = false;
};
-}();
+}
-export default store;
+export default CollectionStore;
diff --git a/frontend/scenes/Dashboard/Dashboard.js b/frontend/scenes/Dashboard/Dashboard.js
index 57ed95bb..af6ff217 100644
--- a/frontend/scenes/Dashboard/Dashboard.js
+++ b/frontend/scenes/Dashboard/Dashboard.js
@@ -5,7 +5,6 @@ import { Flex } from 'reflexbox';
import CollectionsStore from 'stores/CollectionsStore';
-import Layout from 'components/Layout';
import Collection from 'components/Collection';
import PreviewLoading from 'components/PreviewLoading';
import CenteredContent from 'components/CenteredContent';
@@ -21,17 +20,15 @@ type Props = {
const { collections } = this.props;
return (
-
-
-
- {!collections.isLoaded
- ?
- : collections.data.map(collection => (
-
- ))}
-
-
-
+
+
+ {!collections.isLoaded
+ ?
+ : collections.data.map(collection => (
+
+ ))}
+
+
);
}
}
diff --git a/frontend/scenes/Document/Document.js b/frontend/scenes/Document/Document.js
index c8b0631d..d32e9448 100644
--- a/frontend/scenes/Document/Document.js
+++ b/frontend/scenes/Document/Document.js
@@ -2,15 +2,16 @@
import React, { Component } from 'react';
import get from 'lodash/get';
import styled from 'styled-components';
-import { observer } from 'mobx-react';
+import { observer, inject } from 'mobx-react';
import { withRouter, Prompt } from 'react-router';
import { Flex } from 'reflexbox';
+import UiStore from 'stores/UiStore';
+
import DocumentStore from './DocumentStore';
-import Breadcrumbs from './components/Breadcrumbs';
import Menu from './components/Menu';
import Editor from 'components/Editor';
-import Layout, { HeaderAction, SaveAction } from 'components/Layout';
+import { HeaderAction, SaveAction } from 'components/Layout';
import PublishingInfo from 'components/PublishingInfo';
import PreviewLoading from 'components/PreviewLoading';
import CenteredContent from 'components/CenteredContent';
@@ -21,25 +22,12 @@ You have unsaved changes.
Are you sure you want to discard them?
`;
-const Container = styled.div`
- position: relative;
- font-weight: 400;
- font-size: 1em;
- line-height: 1.5em;
- padding: 0 3em;
- width: 50em;
-`;
-
-const Meta = styled.div`
- position: absolute;
- top: 12px;
-`;
-
type Props = {
match: Object,
history: Object,
keydown: Object,
newChildDocument?: boolean,
+ ui: UiStore,
};
@observer class Document extends Component {
@@ -48,10 +36,13 @@ type Props = {
constructor(props: Props) {
super(props);
- this.store = new DocumentStore({ history: this.props.history });
+ this.store = new DocumentStore({
+ history: this.props.history,
+ ui: props.ui,
+ });
}
- componentDidMount = () => {
+ componentDidMount() {
if (this.props.newDocument) {
this.store.collectionId = this.props.match.params.id;
this.store.newDocument = true;
@@ -67,19 +58,25 @@ type Props = {
this.store.newDocument = false;
this.store.fetchDocument();
}
- };
+ }
+
+ componentWillUnmout() {
+ this.props.ui.clearActiveCollection();
+ }
onEdit = () => {
const url = `${this.store.document.url}/edit`;
this.props.history.push(url);
+ this.props.ui.enableEditMode();
};
- onSave = (options: { redirect?: boolean } = {}) => {
+ onSave = async (options: { redirect?: boolean } = {}) => {
if (this.store.newDocument || this.store.newChildDocument) {
- this.store.saveDocument(options);
+ await this.store.saveDocument(options);
} else {
- this.store.updateDocument(options);
+ await this.store.updateDocument(options);
}
+ this.props.ui.disableEditMode();
};
onImageUploadStart = () => {
@@ -97,12 +94,12 @@ type Props = {
render() {
const isNew = this.props.newDocument || this.props.newChildDocument;
const isEditing = this.props.match.params.edit;
- const title = (
+ /*const title = (
- );
+ );*/
const titleText = this.store.document && get(this.store, 'document.title');
@@ -117,49 +114,71 @@ type Props = {
/>
: Edit }
-
+ {!isEditing &&
+ }
);
return (
-
-
-
- {this.store.isFetching &&
-
-
- }
- {this.store.document &&
-
- {!isEditing &&
-
+
+ {actions}
+
+
+
+ {this.store.isFetching &&
+
+
+ }
+ {this.store.document &&
+
+ {!isEditing &&
- }
-
- }
-
+ />}
+
+ }
+
+
);
}
}
-export default withRouter(Document);
+const Container = styled(Flex)`
+ position: relative;
+ width: 100%;
+`;
+
+const PagePadding = styled(Flex)`
+ padding: 80px 20px;
+`;
+
+const Actions = styled(Flex)`
+ position: absolute;
+ top: 0;
+ right: 20px;
+`;
+
+const DocumentContainer = styled.div`
+ font-weight: 400;
+ font-size: 1em;
+ line-height: 1.5em;
+ padding: 0 3em;
+ width: 50em;
+`;
+
+export default withRouter(inject('ui')(Document));
diff --git a/frontend/scenes/Error404/Error404.js b/frontend/scenes/Error404/Error404.js
index d7865b16..6acd7564 100644
--- a/frontend/scenes/Error404/Error404.js
+++ b/frontend/scenes/Error404/Error404.js
@@ -2,23 +2,20 @@
import React from 'react';
import { Link } from 'react-router-dom';
-import Layout from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import PageTitle from 'components/PageTitle';
class Error404 extends React.Component {
render() {
return (
-
+
-
- Not Found
+ Not Found
- We're unable to find the page you're accessing.
+ We're unable to find the page you're accessing.
- Maybe you want to try search instead?
-
-
+ Maybe you want to try search instead?
+
);
}
}
diff --git a/frontend/scenes/ErrorAuth/ErrorAuth.js b/frontend/scenes/ErrorAuth/ErrorAuth.js
index c9cf6f2b..edfbd009 100644
--- a/frontend/scenes/ErrorAuth/ErrorAuth.js
+++ b/frontend/scenes/ErrorAuth/ErrorAuth.js
@@ -2,23 +2,20 @@
import React from 'react';
import { Link } from 'react-router-dom';
-import Layout from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import PageTitle from 'components/PageTitle';
class ErrorAuth extends React.Component {
render() {
return (
-
+
-
- Authentication failed
+ Authentication failed
-
- We were unable to log you in. Please try again.
-
-
-
+
+ We were unable to log you in. Please try again.
+
+
);
}
}
diff --git a/frontend/scenes/Home/Home.js b/frontend/scenes/Home/Home.js
index 4cf12891..022f1b94 100644
--- a/frontend/scenes/Home/Home.js
+++ b/frontend/scenes/Home/Home.js
@@ -7,7 +7,6 @@ import styled from 'styled-components';
import AuthStore from 'stores/AuthStore';
-import Layout from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import SlackAuthLink from 'components/SlackAuthLink';
import Alert from 'components/Alert';
@@ -40,30 +39,28 @@ type Props = {
return (
-
- {this.props.auth.authenticated && }
+ {this.props.auth.authenticated && }
-
- {showLandingPageCopy &&
-
-
Simple, fast, markdown.
-
- We're building a modern wiki for engineering teams.
-
- }
+
+ {showLandingPageCopy &&
-
-
-
-
-
-
+ Simple, fast, markdown.
+
+ We're building a modern wiki for engineering teams.
+
+ }
+
+
+
+
+
+
);
}
diff --git a/frontend/scenes/Search/Search.js b/frontend/scenes/Search/Search.js
index 30dad695..543992e6 100644
--- a/frontend/scenes/Search/Search.js
+++ b/frontend/scenes/Search/Search.js
@@ -12,7 +12,6 @@ import ArrowKeyNavigation from 'boundless-arrow-key-navigation';
import SearchField from './components/SearchField';
import SearchStore from './SearchStore';
-import Layout, { Title } from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import DocumentPreview from 'components/DocumentPreview';
import PageTitle from 'components/PageTitle';
@@ -83,41 +82,38 @@ const ResultsWrapper = styled(Flex)`
render() {
const query = this.props.match.params.query;
- const title = ;
const hasResults = this.store.documents.length > 0;
return (
-
+
-
- {this.props.notFound &&
-
-
Not Found
-
We're unable to find the page you're accessing.
-
-
}
-
-
-
- {this.store.documents.map((document, index) => (
- index === 0 && this.setFirstDocumentRef(ref)}
- key={document.id}
- document={document}
- />
- ))}
-
-
-
-
+ {this.props.notFound &&
+
+
Not Found
+
We're unable to find the page you're accessing.
+
+
}
+
+
+
+ {this.store.documents.map((document, index) => (
+ index === 0 && this.setFirstDocumentRef(ref)}
+ key={document.id}
+ document={document}
+ />
+ ))}
+
+
+
);
}
}
diff --git a/frontend/scenes/Settings/Settings.js b/frontend/scenes/Settings/Settings.js
index e16ac6e9..709a7dfd 100644
--- a/frontend/scenes/Settings/Settings.js
+++ b/frontend/scenes/Settings/Settings.js
@@ -8,7 +8,6 @@ import ApiKeyRow from './components/ApiKeyRow';
import styles from './Settings.scss';
import SettingsStore from './SettingsStore';
-import Layout, { Title } from 'components/Layout';
import CenteredContent from 'components/CenteredContent';
import SlackAuthLink from 'components/SlackAuthLink';
import PageTitle from 'components/PageTitle';
@@ -22,72 +21,69 @@ import PageTitle from 'components/PageTitle';
}
render() {
- const title = ;
const showSlackSettings = DEPLOYMENT === 'hosted';
return (
-
+
-
- {showSlackSettings &&
-
-
Slack
-
- Connect Atlas to your Slack to instantly search for your documents
- using /atlas
command.
-
-
-
-
-
-
}
-
+ {showSlackSettings &&
-
API access
+
Slack
- Create API tokens to hack on your Atlas.
- Learn more in API documentation .
+ Connect Atlas to your Slack to instantly search for your documents
+ using /atlas
command.
- {this.store.apiKeys &&
-
-
- {this.store.apiKeys &&
- this.store.apiKeys.map(key => (
-
- ))}
-
-
}
-
-
-
+
-
+
+
}
+
+
+
API access
+
+ Create API tokens to hack on your Atlas.
+ Learn more in API documentation .
+
+
+ {this.store.apiKeys &&
+
+
+ {this.store.apiKeys &&
+ this.store.apiKeys.map(key => (
+
+ ))}
+
+
}
+
+
+
-
-
+
+
);
}
}
diff --git a/frontend/stores/CollectionsStore.js b/frontend/stores/CollectionsStore.js
index 745684a6..2f9d2daf 100644
--- a/frontend/stores/CollectionsStore.js
+++ b/frontend/stores/CollectionsStore.js
@@ -38,8 +38,7 @@ class CollectionsStore {
}
};
- @action getById = async (id: string): Promise => {
- if (!this.isLoaded) await this.fetch();
+ getById = (id: string): Collection => {
return _.find(this.data, { id });
};
diff --git a/frontend/stores/UiStore.js b/frontend/stores/UiStore.js
index 80c95352..4a3bb7aa 100644
--- a/frontend/stores/UiStore.js
+++ b/frontend/stores/UiStore.js
@@ -1,33 +1,26 @@
// @flow
-import { observable, action, computed, autorunAsync } from 'mobx';
-
-const UI_STORE = 'UI_STORE';
+import { observable, action } from 'mobx';
class UiStore {
- @observable sidebar: boolean = false;
-
- /* Computed */
-
- @computed get asJson(): string {
- return JSON.stringify({
- sidebar: this.sidebar,
- });
- }
+ @observable activeCollection: ?string;
+ @observable editMode: boolean = false;
/* Actions */
- @action toggleSidebar = (): void => {
- this.sidebar = !this.sidebar;
+ @action setActiveCollection = (id: string): void => {
+ this.activeCollection = id;
};
- constructor() {
- // Rehydrate
- const data = JSON.parse(localStorage.getItem(UI_STORE) || '{}');
- this.sidebar = data.sidebar;
+ @action clearActiveCollection = (): void => {
+ this.activeCollection = null;
+ };
- autorunAsync(() => {
- localStorage.setItem(UI_STORE, this.asJson);
- });
+ @action enableEditMode() {
+ this.editMode = true;
+ }
+
+ @action disableEditMode() {
+ this.editMode = false;
}
}
diff --git a/frontend/styles/base.scss b/frontend/styles/base.scss
index 10cd2225..c7bd8153 100644
--- a/frontend/styles/base.scss
+++ b/frontend/styles/base.scss
@@ -20,11 +20,11 @@ html, body, .viewport {
}
body {
- font-family: 'Atlas Grotesk', -apple-system, 'Helvetica Neue', Helvetica, sans-serif;
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
font-size: 15px;
line-height: 1.5;
margin: 0;
- color: $textColor;
+ color: #617180;
background-color: #fff;
display: flex;
position: absolute;
@@ -32,6 +32,10 @@ body {
right: 0;
bottom: 0;
left: 0;
+
+ -moz-osx-font-smoothing: grayscale;
+ -webkit-font-smoothing: antialiased;
+ text-rendering: optimizeLegibility;
}
img {
max-width: 100%;
@@ -41,13 +45,13 @@ svg {
max-height: 100%;
}
a {
- color: $actionColor;
+ color: #005AA6;
text-decoration: none;
cursor: pointer;
}
h1, h2, h3,
h4, h5, h6 {
- font-weight: 600;
+ font-weight: 500;
line-height: 1.25;
margin-top: 1em;
margin-bottom: .5em;
diff --git a/server/static/index.html b/server/static/index.html
index e732e8ce..21c5637e 100644
--- a/server/static/index.html
+++ b/server/static/index.html
@@ -1,36 +1,19 @@
-
- Atlas
-
+
- .container {
- display: flex;
- flex;
- }
+
+
- .header {
- display: flex;
- flex: 1;
- height: 42px;
- border-bottom: 1px solid #eee;
- }
-
-
-
-
-
-