diff --git a/pkg/interface/groups/src/css/custom.css b/pkg/interface/groups/src/css/custom.css index 3f4a1babcf..95aa634bc3 100644 --- a/pkg/interface/groups/src/css/custom.css +++ b/pkg/interface/groups/src/css/custom.css @@ -167,6 +167,6 @@ a { border-color: #fff; } .hover-bg-gray1-d:hover { - color: #4d4d4d; + background-color: #4d4d4d; } } \ No newline at end of file diff --git a/pkg/interface/groups/src/js/api.js b/pkg/interface/groups/src/js/api.js index 5ebf220df4..9c0016fb52 100644 --- a/pkg/interface/groups/src/js/api.js +++ b/pkg/interface/groups/src/js/api.js @@ -191,6 +191,16 @@ class UrbitApi { }) } + setSelected(selected) { + store.handleEvent({ + data: { + local: { + selected: selected + } + } + }) + } + } export let api = new UrbitApi(); diff --git a/pkg/interface/groups/src/js/components/lib/group-filter.js b/pkg/interface/groups/src/js/components/lib/group-filter.js new file mode 100644 index 0000000000..fb0f12ecfa --- /dev/null +++ b/pkg/interface/groups/src/js/components/lib/group-filter.js @@ -0,0 +1,232 @@ +import React, { Component } from 'react' + +export class GroupFilter extends Component { + constructor(props) { + super(props); + this.state = { + open: false, + selected: [], + groups: [], + searchTerm: "", + results: [] + } + this.toggleOpen = this.toggleOpen.bind(this); + this.handleClickOutside = this.handleClickOutside.bind(this); + this.groupIndex = this.groupIndex.bind(this); + this.search = this.search.bind(this); + this.addGroup = this.addGroup.bind(this); + this.deleteGroup = this.deleteGroup.bind(this); + } + + componentDidMount() { + document.addEventListener('mousedown', this.handleClickOutside); + this.groupIndex(); + let selected = localStorage.getItem("urbit-selectedGroups"); + if (selected) { + this.setState({selected: JSON.parse(selected)}, (() => { + window.api.setSelected(this.state.selected); + })) + } + } + + componentWillUnmount() { + document.removeEventListener('mousedown', this.handleClickOutside); + } + + componentDidUpdate(prevProps) { + if (prevProps !== this.props) { + this.groupIndex(); + } + } + + handleClickOutside(evt) { + if ((this.dropdown && !this.dropdown.contains(evt.target)) + && (this.toggleButton && !this.toggleButton.contains(evt.target))) { + this.setState({ open: false }); + } + } + + toggleOpen() { + this.setState({open: !this.state.open}); + } + + groupIndex() { + const { props, state } = this; + let index = []; + let associations = !!props.associations ? props.associations : {}; + index = Object.keys(associations).map((each) => { + let eachGroup = []; + eachGroup.push(each); + let name = each; + let groupPath = `${each}/contacts${each}`; + if (associations[each][groupPath] && associations[each][groupPath].metadata) { + name = (associations[each][groupPath].metadata.title !== "") + ? associations[each][groupPath].metadata.title : name; + } + eachGroup.push(name); + return eachGroup; + }); + this.setState({groups: index}) + } + + search(evt) { + this.setState({searchTerm: evt.target.value}); + let term = evt.target.value.toLowerCase(); + + if (term.length < 3) { + return this.setState({results: []}) + } + + let groupMatches = []; + groupMatches = this.state.groups.filter(e => { + return (e[0].includes(term) || e[1].includes(term)); + }); + this.setState({results: groupMatches}); + } + + addGroup(group) { + let selected = this.state.selected; + if (!(group in selected)) { + selected.push(group); + } + this.setState({ + searchTerm: "", + selected: selected, + results: [] + }, (() => { + window.api.setSelected(this.state.selected); + localStorage.setItem("urbit-selectedGroups", JSON.stringify(this.state.selected)); + })) + } + + deleteGroup(group) { + let selected = this.state.selected; + selected = selected.filter(e => { + return e !== group; + }); + this.setState({selected: selected}, (() => { + window.api.setSelected(this.state.selected); + localStorage.setItem("urbit-selectedGroups", JSON.stringify(this.state.selected)); + })) + } + + render() { + const { props, state } = this; + + let currentGroup = "All Groups"; + + if (state.selected.length > 0) { + let titles = state.selected.map((each) => { + return each[1]; + }) + currentGroup = titles.join(" + "); + } + + let buttonOpened = (state.open) + ? "bg-gray5 bg-gray1-d white-d" : "hover-bg-gray5 hover-bg-gray1-d white-d"; + + let dropdownClass = (state.open) + ? "absolute db z-2 bg-white bg-gray0-d white-d ba b--gray3 b--gray1-d" + : "dn"; + + let inviteCount = (props.invites && props.invites.length > 0) + ? + : ; + + let selectedGroups =
+ let searchResults =
+ + if (state.results.length > 0) { + let groupResults = state.results.map((group => { + return( +
  • this.addGroup(group)}> + {(group[1]) ? group[1] : group[0]} +
  • + ) + })) + searchResults = ( +
    +

    Groups

    + {groupResults} +
    + ) + } + + if (state.selected.length > 0) { + let allSelected = this.state.selected.map((each) => { + let name = each[1]; + return( + + {name} + this.deleteGroup(each)}> + x + + + ) + }) + selectedGroups = ( +
    + {allSelected} +
    + ) + } + + return ( +
    +
    this.toggleOpen()} + ref={(el) => this.toggleButton = el}> +

    {currentGroup}

    +
    +
    { this.dropdown = el }}> +

    Group Select and Filter

    + Manage all Groups + {inviteCount} + +

    Filter Groups

    +
    + + {searchResults} + {selectedGroups} +
    +
    +
    + ) + } +} + +export default GroupFilter; \ No newline at end of file diff --git a/pkg/interface/groups/src/js/components/lib/group-sidebar.js b/pkg/interface/groups/src/js/components/lib/group-sidebar.js index 2e1dab4fb8..4797ff46d3 100644 --- a/pkg/interface/groups/src/js/components/lib/group-sidebar.js +++ b/pkg/interface/groups/src/js/components/lib/group-sidebar.js @@ -57,6 +57,14 @@ export class GroupSidebar extends Component { (path in props.groups) ); }) + .filter((path) => { + let selectedGroups = !!props.selectedGroups ? props.selectedGroups : []; + if (selectedGroups.length === 0) { + return true; + } + let selectedPaths = selectedGroups.map((e => {return e[0]})); + return (selectedPaths.includes(path)); + }) .sort((a, b) => { let aName = a.substr(1); let bName = b.substr(1); diff --git a/pkg/interface/groups/src/js/components/lib/header-bar.js b/pkg/interface/groups/src/js/components/lib/header-bar.js index aa03afd4e3..cd9c194581 100644 --- a/pkg/interface/groups/src/js/components/lib/header-bar.js +++ b/pkg/interface/groups/src/js/components/lib/header-bar.js @@ -1,23 +1,24 @@ import React, { Component } from "react"; -import { cite } from '../../lib/util'; -import { IconHome } from "/components/lib/icons/icon-home"; +import { GroupFilter } from "./group-filter"; import { Sigil } from "/components/lib/icons/sigil"; export class HeaderBar extends Component { render() { let popout = window.location.href.includes("popout/") - ? "dn" - : "dn db-m db-l db-xl"; + ? "dn" : "dn db-m db-l db-xl"; - let title = document.title === "Home" ? "" : document.title; + // let spinner = !!this.props.spinner + // ? this.props.spinner : false; - let spinner = !!this.props.spinner ? this.props.spinner : false; + // let spinnerClasses = ""; - let spinnerClasses = ""; + // if (spinner === true) { + // spinnerClasses = "spin-active"; + // } - if (spinner === true) { - spinnerClasses = "spin-active"; - } + let invites = (this.props.invites && this.props.invites.contacts) + ? this.props.invites.contacts + : {}; return (
    - - - - Home - - - - {title} - -
    - - {cite(window.ship)} +
    ); diff --git a/pkg/interface/groups/src/js/components/root.js b/pkg/interface/groups/src/js/components/root.js index fd7294c304..a1dbffd334 100644 --- a/pkg/interface/groups/src/js/components/root.js +++ b/pkg/interface/groups/src/js/components/root.js @@ -34,7 +34,8 @@ export class Root extends Component { let invites = (!!state.invites && '/contacts' in state.invites) ? state.invites['/contacts'] : {}; - let associations = !! state.associations ? state.associations : {}; + let associations = !!state.associations ? state.associations : {}; + let selectedGroups = !!state.selected ? state.selected : []; return ( @@ -45,6 +46,7 @@ export class Root extends Component { - +