mirror of
https://github.com/urbit/shrub.git
synced 2024-11-24 04:58:08 +03:00
link: sidebar redesign with grouped collections
This commit is contained in:
parent
e7a29dc628
commit
744dc47be9
@ -214,4 +214,7 @@ a {
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
.hover-bg-gray1-d:hover {
|
||||
background-color: #4d4d4d;
|
||||
}
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
import React, { Component } from 'react';
|
||||
|
||||
import { Route, Link } from 'react-router-dom';
|
||||
import { ChannelsItem } from '/components/lib/channels-item';
|
||||
import { GroupItem } from './group-item';
|
||||
import { SidebarInvite } from '/components/lib/sidebar-invite';
|
||||
import { Welcome } from '/components/lib/welcome';
|
||||
import { alphabetiseAssociations } from '../../lib/util';
|
||||
|
||||
export class ChannelsSidebar extends Component {
|
||||
// drawer to the left
|
||||
@ -21,34 +22,75 @@ export class ChannelsSidebar extends Component {
|
||||
);
|
||||
});
|
||||
|
||||
const channelItems =
|
||||
[...props.listening].map((path) => {
|
||||
const meta = props.associations[path];
|
||||
if (!meta) return null;
|
||||
const selected = (props.selected === path);
|
||||
const linkCount = !!props.links[path] ? props.links[path].totalItems : 0;
|
||||
const unseenCount = !!props.links[path]
|
||||
? props.links[path].unseenCount
|
||||
: linkCount
|
||||
let associations = !!props.associations.contacts ? alphabetiseAssociations(props.associations.contacts) : {};
|
||||
|
||||
return (
|
||||
<ChannelsItem
|
||||
key={path}
|
||||
link={path}
|
||||
memberList={props.groups[meta["group-path"]]}
|
||||
selected={selected}
|
||||
linkCount={linkCount}
|
||||
unseenCount={unseenCount}
|
||||
name={meta.metadata.title}/>
|
||||
);
|
||||
});
|
||||
let groupedChannels = {};
|
||||
[...props.listening].map((path) => {
|
||||
let groupPath = !!props.associations.link[path] ?
|
||||
props.associations.link[path]["group-path"] : "";
|
||||
|
||||
console.log(path);
|
||||
console.log(groupPath);
|
||||
|
||||
if (groupPath.startsWith("/~/")) {
|
||||
if (groupedChannels["/~/"]) {
|
||||
let array = groupedChannels["/~/"];
|
||||
array.push(path);
|
||||
groupedChannels["/~/"] = array;
|
||||
} else {
|
||||
groupedChannels["/~/"] = [path];
|
||||
};
|
||||
}
|
||||
if (groupPath in associations) {
|
||||
if (groupedChannels[groupPath]) {
|
||||
let array = groupedChannels[groupPath];
|
||||
array.push[path];
|
||||
groupedChannels[groupPath] = array;
|
||||
} else {
|
||||
groupedChannels[groupPath] = [path];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
let i = -1;
|
||||
const groupedItems = Object.keys(associations).map((each) => {
|
||||
let channels = groupedChannels[each];
|
||||
if (!channels || channels.length === 0) return;
|
||||
i++;
|
||||
if (groupedChannels["/~/"] && groupedChannels["/~/"].length !== 0) {
|
||||
i++;
|
||||
}
|
||||
|
||||
return (
|
||||
<GroupItem
|
||||
key={i}
|
||||
index={i}
|
||||
association={associations[each]}
|
||||
linkMetadata={props.associations["link"]}
|
||||
channels={channels}
|
||||
selected={props.selected}
|
||||
links={props.links}
|
||||
/>
|
||||
)
|
||||
});
|
||||
if (groupedChannels["/~/"] && groupedChannels["/~/"].length !== 0) {
|
||||
groupedItems.unshift(
|
||||
<GroupItem
|
||||
key={"/~/"}
|
||||
index={0}
|
||||
association={"/~/"}
|
||||
linkMetadata={props.associations["link"]}
|
||||
channels={groupedChannels["/~/"]}
|
||||
selected={props.selected}
|
||||
links={props.links}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
let activeClasses = (this.props.active === "collections") ? " " : "dn-s ";
|
||||
|
||||
let hiddenClasses = true;
|
||||
|
||||
// probably a more concise way to write this
|
||||
|
||||
if (this.props.popout) {
|
||||
hiddenClasses = false;
|
||||
} else {
|
||||
@ -63,17 +105,16 @@ export class ChannelsSidebar extends Component {
|
||||
: "dn")}>
|
||||
<a className="db dn-m dn-l dn-xl f8 pb3 pl3" href="/">⟵ Landscape</a>
|
||||
<div className="overflow-y-scroll h-100">
|
||||
<div className="w-100 bg-transparent pa4 bb b--gray4 b--gray2-d"
|
||||
style={{paddingBottom: 10, paddingTop: 10}}>
|
||||
<div className="w-100 bg-transparent">
|
||||
<Link
|
||||
className="dib f9 pointer green2 gray4-d mr4"
|
||||
className="dib f9 pointer green2 gray4-d pa4"
|
||||
to={"/~link/new"}>
|
||||
New Collection
|
||||
</Link>
|
||||
</div>
|
||||
<Welcome associations={props.associations}/>
|
||||
{sidebarInvites}
|
||||
{channelItems}
|
||||
{groupedItems}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -7,25 +7,18 @@ export class ChannelsItem extends Component {
|
||||
const { props } = this;
|
||||
|
||||
let selectedClass = (props.selected)
|
||||
? "bg-gray5 bg-gray1-d b--gray4 b--gray2-d"
|
||||
: "b--gray4 b--gray2-d";
|
||||
? "bg-gray5 bg-gray1-d"
|
||||
: "pointer hover-bg-gray5 hover-bg-gray1-d";
|
||||
|
||||
let memberCount = props.memberList
|
||||
? props.memberList.size
|
||||
: 0;
|
||||
const unseenCount = props.unseenCount > 0
|
||||
? <span className="green2">{" " + props.unseenCount + " unread"}</span>
|
||||
? <span className="dib white bg-gray3 bg-gray2-d fw6 br1" style={{padding: "1px 5px"}}>{props.unseenCount}</span>
|
||||
: null;
|
||||
|
||||
return (
|
||||
<Link to={makeRoutePath(props.link)}>
|
||||
<div className={"w-100 v-mid f9 pl4 bb z1 pa3 pt4 pb4 b--gray4 b--gray1-d gray3-d pointer " + selectedClass}>
|
||||
<p className="f9 pt1">{props.name}</p>
|
||||
<p className="f9 gray2">
|
||||
{memberCount + " contributor" + ((memberCount === 1) ? "" : "s")}
|
||||
</p>
|
||||
<p className="f9 pb1">
|
||||
{props.linkCount + " link" + ((props.linkCount === 1) ? "" : "s")}
|
||||
<div className={"w-100 v-mid f9 ph4 z1 pv1 " + selectedClass}>
|
||||
<p className="f9 dib">{props.name}</p>
|
||||
<p className="f9 dib fr">
|
||||
{unseenCount}
|
||||
</p>
|
||||
</div>
|
||||
|
45
pkg/interface/link/src/js/components/lib/group-item.js
Normal file
45
pkg/interface/link/src/js/components/lib/group-item.js
Normal file
@ -0,0 +1,45 @@
|
||||
import React, { Component } from 'react';
|
||||
import { ChannelsItem } from './channels-item';
|
||||
|
||||
export class GroupItem extends Component {
|
||||
render() {
|
||||
const { props, state } = this;
|
||||
let association = !!props.association ? props.association : {};
|
||||
|
||||
let title = association["app-path"] ? association["app-path"] : "Unmanaged Collections";
|
||||
|
||||
if (association.metadata && association.metadata.title) {
|
||||
title = association.metadata.title !== ""
|
||||
? association.metadata.title : title;
|
||||
}
|
||||
|
||||
let channels = !!props.channels ? props.channels : [];
|
||||
let first = (props.index === 0) ? "pt1" : "pt4";
|
||||
|
||||
let channelItems = channels.map((each, i) => {
|
||||
const meta = props.linkMetadata[each];
|
||||
if (!meta) return null;
|
||||
const selected = (props.selected === each);
|
||||
const unseenCount = !!props.links[each]
|
||||
? props.links[each].unseenCount
|
||||
: 0;
|
||||
return (
|
||||
<ChannelsItem
|
||||
key={each}
|
||||
link={each}
|
||||
selected={selected}
|
||||
unseenCount={unseenCount}
|
||||
name={meta.metadata.title}
|
||||
/>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<div className={first}>
|
||||
<p className="f9 ph4 fw6 gray3">{title}</p>
|
||||
{channelItems}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default GroupItem;
|
@ -49,7 +49,7 @@ export class Root extends Component {
|
||||
<Skeleton
|
||||
active="collections"
|
||||
spinner={state.spinner}
|
||||
associations={associations.link}
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
groups={groups}
|
||||
rightPanelHide={true}
|
||||
@ -71,7 +71,7 @@ export class Root extends Component {
|
||||
return (
|
||||
<Skeleton
|
||||
spinner={state.spinner}
|
||||
associations={associations.link}
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
groups={groups}
|
||||
rightPanelHide={true}
|
||||
@ -108,7 +108,7 @@ export class Root extends Component {
|
||||
return (
|
||||
<Skeleton
|
||||
spinner={state.spinner}
|
||||
associations={associations.link}
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
groups={groups}
|
||||
selected={resourcePath}
|
||||
@ -145,7 +145,7 @@ export class Root extends Component {
|
||||
return (
|
||||
<Skeleton
|
||||
spinner={state.spinner}
|
||||
associations={associations.link}
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
groups={groups}
|
||||
selected={resourcePath}
|
||||
@ -198,7 +198,7 @@ export class Root extends Component {
|
||||
return (
|
||||
<Skeleton
|
||||
spinner={state.spinner}
|
||||
associations={associations.link}
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
groups={groups}
|
||||
selected={resourcePath}
|
||||
@ -253,7 +253,7 @@ export class Root extends Component {
|
||||
return (
|
||||
<Skeleton
|
||||
spinner={state.spinner}
|
||||
associations={associations.link}
|
||||
associations={associations}
|
||||
invites={invites}
|
||||
groups={groups}
|
||||
selected={resourcePath}
|
||||
|
@ -164,4 +164,26 @@ export function cite(ship) {
|
||||
return shortened;
|
||||
}
|
||||
return `~${patp}`;
|
||||
}
|
||||
|
||||
export function alphabetiseAssociations(associations) {
|
||||
let result = {};
|
||||
Object.keys(associations).sort((a, b) => {
|
||||
let aName = a.substr(1);
|
||||
let bName = b.substr(1);
|
||||
if (a.metadata && a.metadata.title) {
|
||||
aName = a.metadata.title !== ""
|
||||
? a.metadata.title
|
||||
: a.substr(1);
|
||||
}
|
||||
if (b.metadata && b.metadata.title) {
|
||||
bName = b.metadata.title !== ""
|
||||
? b.metadata.title
|
||||
: b.substr(1);
|
||||
}
|
||||
return aName.toLowerCase().localeCompare(bName.toLowerCase());
|
||||
}).map((each) => {
|
||||
result[each] = associations[each];
|
||||
})
|
||||
return result;
|
||||
}
|
Loading…
Reference in New Issue
Block a user