diff --git a/pkg/interface/publish/src/js/api.js b/pkg/interface/publish/src/js/api.js index 44cb376c3..47a1fc4b4 100644 --- a/pkg/interface/publish/src/js/api.js +++ b/pkg/interface/publish/src/js/api.js @@ -139,6 +139,15 @@ class UrbitApi { }); } + setSelected(selected) { + store.handleEvent({ + type: "local", + data: { + selected: selected + } + }) + } + } export let api = new UrbitApi(); diff --git a/pkg/interface/publish/src/js/components/lib/group-filter.js b/pkg/interface/publish/src/js/components/lib/group-filter.js new file mode 100644 index 000000000..711a01330 --- /dev/null +++ b/pkg/interface/publish/src/js/components/lib/group-filter.js @@ -0,0 +1,231 @@ +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.contacts : {}; + index = Object.keys(associations).map((each) => { + let eachGroup = []; + eachGroup.push(each); + let name = each; + if (associations[each].metadata) { + name = (associations[each].metadata.title !== "") + ? associations[each].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/publish/src/js/components/lib/header-bar.js b/pkg/interface/publish/src/js/components/lib/header-bar.js index 73e660d0f..4ca3991e2 100644 --- a/pkg/interface/publish/src/js/components/lib/header-bar.js +++ b/pkg/interface/publish/src/js/components/lib/header-bar.js @@ -1,61 +1,49 @@ -import React, { Component } from 'react'; -import { IconHome } from '/components/lib/icons/icon-home'; -import { Sigil } from '/components/lib/icons/sigil'; -import { cite } from '../../lib/util'; +import React, { Component } from "react"; +import { GroupFilter } from "./group-filter"; +import { Sigil } from "/components/lib/icons/sigil"; export class HeaderBar extends Component { - constructor(props) { - super(props); - } - render() { - let popout = (window.location.href.includes("popout/")) - ? "dn" - : "dn db-m db-l db-xl"; + let popout = window.location.href.includes("popout/") + ? "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)} +
    ); } -} \ No newline at end of file +} diff --git a/pkg/interface/publish/src/js/components/lib/sidebar.js b/pkg/interface/publish/src/js/components/lib/sidebar.js index b9c5dac02..7856e44bb 100644 --- a/pkg/interface/publish/src/js/components/lib/sidebar.js +++ b/pkg/interface/publish/src/js/components/lib/sidebar.js @@ -61,11 +61,21 @@ export class Sidebar extends Component { } }); + let selectedGroups = !!props.selectedGroups ? props.selectedGroups: []; let groupedItems = Object.keys(associations) + .filter((each) => { + if (selectedGroups.length === 0) { + return true; + } + let selectedPaths = selectedGroups.map((e) => { return e[0] }); + return (selectedPaths.includes(each)); + }) .map((each, i) => { let books = groupedNotebooks[each]; if (books.length === 0) return; - if (groupedNotebooks["/~/"] && groupedNotebooks["/~/"].length !== 0) { + if ((selectedGroups.length === 0) && + groupedNotebooks["/~/"] && + groupedNotebooks["/~/"].length !== 0) { i = i + 1; } return( @@ -79,7 +89,9 @@ export class Sidebar extends Component { /> ) }) - if (groupedNotebooks["/~/"] && groupedNotebooks["/~/"].length !== 0) { + if ((selectedGroups.length === 0) && + groupedNotebooks["/~/"] && + groupedNotebooks["/~/"].length !== 0) { groupedItems.unshift( @@ -39,6 +40,7 @@ export class Root extends Component { invites={state.invites} notebooks={state.notebooks} associations={associations} + selectedGroups={selectedGroups} contacts={contacts}>
    @@ -64,6 +66,7 @@ export class Root extends Component { invites={state.invites} notebooks={state.notebooks} associations={associations} + selectedGroups={selectedGroups} contacts={contacts}> @@ -221,6 +228,7 @@ export class Root extends Component { invites={state.invites} notebooks={state.notebooks} associations={associations} + selectedGroups={selectedGroups} contacts={contacts} path={path}> - +