diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/client/views/search/CheckBox.scss | 34 | ||||
-rw-r--r-- | src/client/views/search/CheckBox.tsx | 40 | ||||
-rw-r--r-- | src/client/views/search/IconBar.scss | 7 | ||||
-rw-r--r-- | src/client/views/search/IconBar.tsx | 145 | ||||
-rw-r--r-- | src/client/views/search/SearchBox.tsx | 31 | ||||
-rw-r--r-- | src/client/views/search/SearchItem.scss | 13 | ||||
-rw-r--r-- | src/client/views/search/SearchItem.tsx | 15 | ||||
-rw-r--r-- | src/client/views/search/minus.svg | 5 | ||||
-rw-r--r-- | src/client/views/search/plus.svg | 5 |
9 files changed, 249 insertions, 46 deletions
diff --git a/src/client/views/search/CheckBox.scss b/src/client/views/search/CheckBox.scss new file mode 100644 index 000000000..8eee9176b --- /dev/null +++ b/src/client/views/search/CheckBox.scss @@ -0,0 +1,34 @@ +@import "../globalCssVariables"; + +.checkbox { + display: flex; + + .check-box { + z-index: 900; + position: relative; + height: 20px; + width: 20px; + overflow: visible; + background-color: transparent; + border-style: solid; + border-color: $alt-accent; + border-width: 2px; + } + + .box:hover { + background-color: $intermediate-color; + } + + .checkmark { + z-index: 1000; + position: relative; + fill-opacity: 0; + stroke-width: 4px; + stroke: white; + } + +} + +.checkbox-title { + text-transform: uppercase; +}
\ No newline at end of file diff --git a/src/client/views/search/CheckBox.tsx b/src/client/views/search/CheckBox.tsx new file mode 100644 index 000000000..8b5f7d7c1 --- /dev/null +++ b/src/client/views/search/CheckBox.tsx @@ -0,0 +1,40 @@ +import * as React from 'react'; +import { observer } from 'mobx-react'; +import { observable, action, runInAction } from 'mobx'; +import "./CheckBox.scss"; + +interface CheckBoxProps { + originalStatus: boolean; + updateStatus(newStatus: boolean): void; + title: string; +} + +@observer +export class CheckBox extends React.Component<CheckBoxProps>{ + @observable _status: boolean; + + constructor(props: CheckBoxProps) { + super(props); + + this._status = this.props.originalStatus; + } + + onClick = () => { + this._status = !this._status; + this.props.updateStatus(this._status); + } + + render() { + return ( + <div className="checkbox"> + <div className="check-box"> + <svg viewBox="10 10 20 20"> + <path className="checkmark" d="M14.1 27.2l7.1 7.2 16.7-16.8" /> + </svg> + </div> + <div className="checkbox-title">{this.props.title}</div> + </div> + ) + } + +}
\ No newline at end of file diff --git a/src/client/views/search/IconBar.scss b/src/client/views/search/IconBar.scss index e08e09702..3d38b7ac3 100644 --- a/src/client/views/search/IconBar.scss +++ b/src/client/views/search/IconBar.scss @@ -32,7 +32,8 @@ font-size: 2em; } -.type-icon.selected { + +.type-icon.add.selected { background-color: $alt-accent; opacity: 1; } @@ -47,6 +48,10 @@ width: 28px; } +.filter-description{ + text-transform: capitalize; +} + .type-icon.filter:hover { transform: scale(1.1); background-color: $alt-accent; diff --git a/src/client/views/search/IconBar.tsx b/src/client/views/search/IconBar.tsx index 8fb7d0959..ba337dcab 100644 --- a/src/client/views/search/IconBar.tsx +++ b/src/client/views/search/IconBar.tsx @@ -9,7 +9,7 @@ import { faSearch, faFilePdf, faFilm, faImage, faObjectGroup, faStickyNote, faMu import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { library } from '@fortawesome/fontawesome-svg-core'; import * as _ from "lodash"; -var classNames = require('classnames'); +import $ from 'jquery'; library.add(faSearch); library.add(faObjectGroup); @@ -25,7 +25,8 @@ library.add(faBan); export interface IconBarProps { updateIcon(icons: string[]): void; - getIcons(): string[]; + getSelectedTypes(): string[]; + getRemovedTypes(): string[]; } @observer @@ -45,13 +46,45 @@ export class IconBar extends React.Component<IconBarProps> { @observable webRef = React.createRef<HTMLDivElement>(); @observable allRefs: React.RefObject<HTMLDivElement>[] = [this.colRef, this.imgRef, this.textRef, this.pdfRef, this.vidRef, this.audioRef, this.linkRef, this.histRef, this.webRef]; - @observable originalFilteredNodes: string[] = this.props.getIcons(); + @observable originalSelectedNodes: string[] = this.props.getSelectedTypes(); + @observable originalRemovedNodes: string[] = this.props.getSelectedTypes(); + + @observable removeType: boolean = false; constructor(props: IconBarProps){ super(props); IconBar.Instance = this; } + @action + downKeyHandler = (e: KeyboardEvent) => { + if (e.key !== "Control") return; + this.removeType = true; + e.preventDefault(); + e.stopPropagation(); + + } + + @action + upKeyHandler = (e: KeyboardEvent) => { + e.preventDefault(); + e.stopPropagation(); + this.removeType = false; + } + + componentWillMount() { + document.removeEventListener("keydown", this.downKeyHandler); + document.addEventListener("keydown", this.downKeyHandler); + document.removeEventListener("keyup", this.upKeyHandler); + document.addEventListener("keyup", this.upKeyHandler); + } + + componentWillUnMount() { + document.removeEventListener("keyup", this.upKeyHandler); + document.removeEventListener("keydown", this.downKeyHandler); + } + + componentDidMount = () => { //i KNOW this is bad i just can't get this to re render eeeeeeeek this.forceUpdate(); @@ -113,25 +146,40 @@ export class IconBar extends React.Component<IconBarProps> { this.allRefs.forEach(element => { if (element.current) { element.current.setAttribute("data-selected", "false"); + element.current.setAttribute("data-removed", "false"); } }); } @action.bound - alternateRef(ref: any) { + alternateSelectedRef(ref: any) { if (ref.getAttribute("data-selected") === "true") { ref.setAttribute("data-selected", "false"); } else { ref.setAttribute("data-selected", "true"); + ref.setAttribute("data-removed", "false") } } + //TODO: this needs help + @action.bound + alternateRemovedRef(ref: any) { + if (ref.getAttribute("data-removed") === "true") { + ref.setAttribute("data-removed", "false"); + } + else { + ref.setAttribute("data-removed", "true"); + ref.setAttribute("data-selected", "false") + } + } + + //TODO: this needs help @action.bound onClick = (value: string) => { - let icons: string[] = this.props.getIcons(); + let icons: string[] = this.props.getSelectedTypes(); let ref = this.getRef(value); - this.alternateRef(ref); + this.alternateSelectedRef(ref); if (value === DocTypes.NONE) { icons = []; // if its none, change the color of all the other circles @@ -164,107 +212,148 @@ export class IconBar extends React.Component<IconBarProps> { } } - getInitialStatus = (type: string) => { - if (this.originalFilteredNodes.includes(type)) { + //checks attribues of ref to return whether or not a type should be specifically included in the search + @action.bound + getInitialSelectedStatus = (type: string) => { + if (this.originalSelectedNodes.includes(type)) { return "true"; } return "false"; } + //checks attributes of ref to return whether or not it should be excluded from search results + @action.bound + isRemoved = (ref: React.RefObject<HTMLDivElement>) => { + if(ref.current){ + if(ref.current.getAttribute("data-removed") === "true") { + return true; + } + return false; + } + } + + //gets status upon mounting if a doc type should be removed from the results + @action.bound + getInitialRemovedStatus = (type: string) => { + if (this.originalRemovedNodes.includes(type)) { + return "true"; + } + return "false"; + } + + @action.bound + changeCursor() { + if(!this.removeType) + {document.body.style.cursor = 'url(".\noun_Plus_2224963.svg")';} + else{ + {document.body.style.cursor = 'url(".\noun_Plus_2224963.svg")';} + } + } + render() { return ( <div> <div className="filter icon-title">Filter by type of node</div> - <div className="filter icon-bar"> + <div className="filter icon-bar" onMouseOver={this.changeCursor}> <div className="filter type-outer"> <div className={"type-icon none not-selected"} ref={this.noneRef} data-selected={"false"} + data-removed = {"false"} onClick={() => { this.onClick(DocTypes.NONE); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: -2 }} icon={faBan} /> </div> <div className="filter-description">Clear</div> </div> <div className="type-outer"> - <div className={"type-icon filter " + (this.isRefSelected(this.pdfRef) ? "selected" : "not-selected")} + <div className={"type-icon filter " + (this.isRemoved(this.pdfRef) ? "add" : "remove") + (this.isRefSelected(this.pdfRef) ? "selected" : "not-selected")} ref={this.pdfRef} - data-selected={this.getInitialStatus(DocTypes.PDF)} + data-selected={this.getInitialSelectedStatus(DocTypes.PDF)} + data-removed = {this.getInitialRemovedStatus(DocTypes.PDF)} onClick={() => { this.onClick(DocTypes.PDF); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 0 }} icon={faFilePdf} /> </div> - <div className="filter-description">PDF</div> + <div className="filter-description">{DocTypes.PDF}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.histRef) ? "selected" : "not-selected")} ref={this.histRef} - data-selected={this.getInitialStatus(DocTypes.HIST)} + data-selected={this.getInitialSelectedStatus(DocTypes.HIST)} + data-removed = {this.getInitialRemovedStatus(DocTypes.HIST)} onClick={() => { this.onClick(DocTypes.HIST); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 1 }} icon={faChartBar} /> </div> - <div className="filter-description">Histogram</div> + <div className="filter-description">{DocTypes.HIST}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.colRef) ? "selected" : "not-selected")} ref={this.colRef} - data-selected={this.getInitialStatus(DocTypes.COL)} + data-selected={this.getInitialSelectedStatus(DocTypes.COL)} + data-removed = {this.getInitialRemovedStatus(DocTypes.COL)} onClick={() => { this.onClick(DocTypes.COL); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 2 }} icon={faObjectGroup} /> </div> - <div className="filter-description">Collection</div> + <div className="filter-description">{DocTypes.COL}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.imgRef) ? "selected" : "not-selected")} ref={this.imgRef} - data-selected={this.getInitialStatus(DocTypes.IMG)} + data-selected={this.getInitialSelectedStatus(DocTypes.IMG)} + data-removed = {this.getInitialRemovedStatus(DocTypes.IMG)} onClick={() => { this.onClick(DocTypes.IMG); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 3 }} icon={faImage} /> </div> - <div className="filter-description">Image</div> + <div className="filter-description">{DocTypes.IMG}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.vidRef) ? "selected" : "not-selected")} ref={this.vidRef} - data-selected={this.getInitialStatus(DocTypes.VID)} + data-selected={this.getInitialSelectedStatus(DocTypes.VID)} + data-removed = {this.getInitialRemovedStatus(DocTypes.VID)} onClick={() => { this.onClick(DocTypes.VID); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 4 }} icon={faFilm} /> </div> - <div className="filter-description">Video</div> + <div className="filter-description">{DocTypes.VID}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.webRef) ? "selected" : "not-selected")} ref={this.webRef} - data-selected={this.getInitialStatus(DocTypes.WEB)} + data-selected={this.getInitialSelectedStatus(DocTypes.WEB)} + data-removed = {this.getInitialRemovedStatus(DocTypes.WEB)} onClick={() => { this.onClick(DocTypes.WEB); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 5 }} icon={faGlobeAsia} /> </div> - <div className="filter-description">Web</div> + <div className="filter-description">{DocTypes.WEB}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.linkRef) ? "selected" : "not-selected")} ref={this.linkRef} - data-selected={this.getInitialStatus(DocTypes.LINK)} + data-selected={this.getInitialSelectedStatus(DocTypes.LINK)} + data-removed = {this.getInitialRemovedStatus(DocTypes.LINK)} onClick={() => { this.onClick(DocTypes.LINK); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 6 }} icon={faLink} /> </div> - <div className="filter-description">Link</div> + <div className="filter-description">{DocTypes.LINK}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.audioRef) ? "selected" : "not-selected")} ref={this.audioRef} - data-selected={this.getInitialStatus(DocTypes.AUDIO)} + data-selected={this.getInitialSelectedStatus(DocTypes.AUDIO)} + data-removed = {this.getInitialRemovedStatus(DocTypes.AUDIO)} onClick={() => { this.onClick(DocTypes.AUDIO); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 7 }} icon={faMusic} /> </div> - <div className="filter-description">Audio</div> + <div className="filter-description">{DocTypes.AUDIO}</div> </div> <div className="type-outer"> <div className={"type-icon filter " + (this.isRefSelected(this.textRef) ? "selected" : "not-selected")} ref={this.textRef} - data-selected={this.getInitialStatus(DocTypes.TEXT)} + data-selected={this.getInitialSelectedStatus(DocTypes.TEXT)} + data-removed = {this.getInitialRemovedStatus(DocTypes.TEXT)} onClick={() => { this.onClick(DocTypes.TEXT); }}> <FontAwesomeIcon className="fontawesome-icon filter" style={{ order: 8 }} icon={faStickyNote} /> </div> - <div className="filter-description">Text</div> + <div className="filter-description">{DocTypes.TEXT}</div> </div> </div> </div> diff --git a/src/client/views/search/SearchBox.tsx b/src/client/views/search/SearchBox.tsx index 622fa27f0..fc54d87e2 100644 --- a/src/client/views/search/SearchBox.tsx +++ b/src/client/views/search/SearchBox.tsx @@ -23,7 +23,11 @@ import { findDOMNode } from 'react-dom'; import { ToggleBar } from './ToggleBar'; import { IconBar } from './IconBar'; import { type } from 'os'; +import { CheckBox } from './CheckBox'; +export enum Keys { + TITLE = "title", +} @observer export class SearchBox extends React.Component { @@ -64,8 +68,8 @@ export class SearchBox extends React.Component { @action.bound onChange(e: React.ChangeEvent<HTMLInputElement>) { this._searchString = e.target.value; - - if(this._searchString === ""){ + + if (this._searchString === "") { this._results = []; this._openNoResults = false; } @@ -86,12 +90,13 @@ export class SearchBox extends React.Component { query = newWords.join(" "); } - if(query === ""){ + if (query === "") { results = []; } - else{ + else { //gets json result into a list of documents that can be used - results = await this.getResults(query);} + results = await this.getResults(query); + } runInAction(() => { this._resultsOpen = true; @@ -250,6 +255,10 @@ export class SearchBox extends React.Component { this._pointerTime = e.timeStamp; } + updateCheckStatus(newStat: boolean) { + console.log("updating!") + } + // Useful queries: // Delegates of a document: {!join from=id to=proto_i}id:{protoId} // Documents in a collection: {!join from=data_l to=id}id:{collectionProtoId} @@ -268,10 +277,10 @@ export class SearchBox extends React.Component { </div> {this._resultsOpen ? ( <div className="searchBox-results"> - { (this._results.length !== 0) ? ( + {(this._results.length !== 0) ? ( this._results.map(result => <SearchItem doc={result} key={result[Id]} />) - ) : - this._openNoResults ? (<div className = "no-result">No Search Results</div>) : null } + ) : + this._openNoResults ? (<div className="no-result">No Search Results</div>) : null} </div> ) : undefined} @@ -285,16 +294,16 @@ export class SearchBox extends React.Component { <ToggleBar originalStatus={this._wordStatus} optionOne={"Include Any Keywords"} optionTwo={"Include All Keywords"} changeStatus={this.handleWordQueryChange} /> </div> <div className="type-of-node filter-div"> - <IconBar updateIcon={this.updateIcon} getIcons={this.getIcons} /> + <IconBar updateIcon={this.updateIcon} getSelectedTypes={this.getIcons} /> </div> <div className="filter-collection filter-div"> temp for filtering by collection </div> <div className="where-in-doc filter-div"> - temp for filtering where in doc the keywords are found + <CheckBox originalStatus={true} updateStatus={this.updateCheckStatus} title={Keys.TITLE} /> </div> </div> - <button className="reset-filter" onClick = {this.resetFilters}>Reset Filters</button> + <button className="reset-filter" onClick={this.resetFilters}>Reset Filters</button> </div> ) : undefined} </div> diff --git a/src/client/views/search/SearchItem.scss b/src/client/views/search/SearchItem.scss index 5afb69164..630d27cc3 100644 --- a/src/client/views/search/SearchItem.scss +++ b/src/client/views/search/SearchItem.scss @@ -131,4 +131,17 @@ -webkit-transform: scale(1); -ms-transform: scale(1); transform: scale(1); +} + +.search-label{ + text-transform: capitalize; + opacity: 0; + -webkit-transition: opacity 0.2s ease-in-out; + -moz-transition: opacity 0.2s ease-in-out; + -o-transition: opacity 0.2s ease-in-out; + transition: opacity 0.2s ease-in-out; +} + +.search-type:hover +.search-label{ + opacity: 1; }
\ No newline at end of file diff --git a/src/client/views/search/SearchItem.tsx b/src/client/views/search/SearchItem.tsx index fb0eade4b..c19057819 100644 --- a/src/client/views/search/SearchItem.tsx +++ b/src/client/views/search/SearchItem.tsx @@ -152,21 +152,24 @@ export class SearchItem extends React.Component<SearchItemProps> { render() { return ( - <div className="search-overview" onPointerDown = {this.pointerDown}> - <div className="search-item" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc} ref={this.collectionRef} id="result" onClick={this.onClick} onPointerDown={ () => { + <div className="search-overview" onPointerDown={this.pointerDown}> + <div className="search-item" onPointerEnter={this.highlightDoc} onPointerLeave={this.unHighlightDoc} ref={this.collectionRef} id="result" onClick={this.onClick} onPointerDown={() => { this.pointerDown; - SetupDrag(this.collectionRef, this.startDocDrag);}} > + SetupDrag(this.collectionRef, this.startDocDrag); + }} > <div className="main-search-info"> <div className="search-title" id="result" >{this.props.doc.title}</div> <div className="search-info"> <div className="link-container item"> <div className="link-count">{this.linkCount}</div> - <div className = "link-extended">{this.linkString}</div> + <div className="link-extended">{this.linkString}</div> + </div> + <div className="icon"> + <div className="search-type" >{this.DocumentIcon}</div> + <div className="search-label">{this.props.doc.type}</div> </div> - <div className="search-type" >{this.DocumentIcon}</div> </div> </div> - <div className="found">Where Found: (i.e. title, body, etc)</div> </div> <div className="searchBox-instances"> <SelectorContextMenu {...this.props} /> diff --git a/src/client/views/search/minus.svg b/src/client/views/search/minus.svg new file mode 100644 index 000000000..63cd809f6 --- /dev/null +++ b/src/client/views/search/minus.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" version="1.1" style="shape-rendering:geometricPrecision;text-rendering:geometricPrecision;image-rendering:optimizeQuality;" viewBox="0 0 738 922.5" x="0px" y="0px" fill-rule="evenodd" clip-rule="evenodd"><defs><style type="text/css"> + + .fil0 {fill:black} + + </style></defs><g><path class="fil0" d="M369 0c203,0 369,165 369,369 0,203 -166,369 -369,369 -204,0 -369,-166 -369,-369 0,-204 165,-369 369,-369zm-197 305l394 0c35,0 64,29 64,64 0,35 -29,64 -64,64l-394 0c-36,0 -65,-29 -65,-64 0,-36 29,-64 65,-64z"/></g><text x="0" y="753" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">Created by Manaqib S</text><text x="0" y="758" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">from the Noun Project</text></svg>
\ No newline at end of file diff --git a/src/client/views/search/plus.svg b/src/client/views/search/plus.svg new file mode 100644 index 000000000..deb855637 --- /dev/null +++ b/src/client/views/search/plus.svg @@ -0,0 +1,5 @@ +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" version="1.1" style="shape-rendering:geometricPrecision;text-rendering:geometricPrecision;image-rendering:optimizeQuality;" viewBox="0 0 443 553.75" x="0px" y="0px" fill-rule="evenodd" clip-rule="evenodd"><defs><style type="text/css"> + + .fil0 {fill:black} + + </style></defs><g><path class="fil0" d="M221 0c123,0 222,99 222,221 0,123 -99,222 -222,222 -122,0 -221,-99 -221,-222 0,-122 99,-221 221,-221zm0 46c18,0 33,15 33,33l0 109 109 0c19,0 34,15 34,33 0,18 -15,33 -34,33l-109 0 0 109c0,19 -15,34 -33,34 -18,0 -33,-15 -33,-34l0 -109 -109 0c-18,0 -33,-15 -33,-33 0,-18 15,-33 33,-33l109 0 0 -109c0,-18 15,-33 33,-33z"/></g><text x="0" y="458" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">Created by mohkamil</text><text x="0" y="463" fill="#000000" font-size="5px" font-weight="bold" font-family="'Helvetica Neue', Helvetica, Arial-Unicode, Arial, Sans-serif">from the Noun Project</text></svg>
\ No newline at end of file |