added portal search closes #10

This commit is contained in:
Daniel 2018-02-25 22:43:53 -05:00
parent 6e1ff2e55c
commit 83670df3b4
6 changed files with 214 additions and 28 deletions

File diff suppressed because one or more lines are too long

View File

@ -19,6 +19,10 @@
/*color: inherit;*/
/*background: transparent;*/
}
a {
color: inherit;
text-decoration: inherit;
}
/*pass window height (w/o scroll bars) down to react app, note can't use vh because that includes scroll bars and mobile browser footer, etc so doesn't give viewable area*/
html, body { height: 100%; }
html { background-color:#494949; }

View File

@ -157,3 +157,8 @@ export function Donate(props) {
</form>
);
}
export function SearchButton(props) {
return (<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="magnifying-glass"><g fillRule="evenodd"><path d="M21.747 20.524l-4.872-4.871a.864.864 0 1 0-1.222 1.222l4.871 4.872a.864.864 0 1 0 1.223-1.223z"></path><path d="M3.848 10.763a6.915 6.915 0 0 1 6.915-6.915 6.915 6.915 0 0 1 6.915 6.915 6.915 6.915 0 0 1-6.915 6.915 6.915 6.915 0 0 1-6.915-6.915zm-1.729 0a8.643 8.643 0 0 0 8.644 8.644 8.643 8.643 0 0 0 8.644-8.644 8.643 8.643 0 0 0-8.644-8.644 8.643 8.643 0 0 0-8.644 8.644z"></path></g>
</svg>);
}

View File

@ -1,16 +1,179 @@
import React from 'react';
import Interactive from 'react-interactive';
import {Link} from 'react-router-dom';
import API from '../SpreadsheetData';
import {observable} from "mobx";
import {observer, inject} from 'mobx-react';
import loki from 'lokijs';
import s from '../../styles/app.style';
import {SearchButton} from '../Snippets';
@inject((stores, props, context) => props) @observer
export default class SearchPortal extends React.Component {
@observable input;
@observable query;
constructor(props) {
super(props);
this.search = this.search.bind(this);
this.query = this.input = decodeURIComponent(this.props.location.search.substr(1));
}
render() {
return (<div className="search">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" className="magnifying-glass"><g fillRule="evenodd"><path d="M21.747 20.524l-4.872-4.871a.864.864 0 1 0-1.222 1.222l4.871 4.872a.864.864 0 1 0 1.223-1.223z"></path><path d="M3.848 10.763a6.915 6.915 0 0 1 6.915-6.915 6.915 6.915 0 0 1 6.915 6.915 6.915 6.915 0 0 1-6.915 6.915 6.915 6.915 0 0 1-6.915-6.915zm-1.729 0a8.643 8.643 0 0 0 8.644 8.644 8.643 8.643 0 0 0 8.644-8.644 8.643 8.643 0 0 0-8.644-8.644 8.643 8.643 0 0 0-8.644 8.644z"></path></g>
</svg>Search
<form onSubmit={this.search}>
<input type="text" value={this.query} onChange={(e) => this.query = e.target.value} />
<button type="submit"><SearchButton /></button>
</form>
<DBSearch string={this.input}/>
</div>);
}
search(event) {
event.preventDefault();
event.stopPropagation();
this.props.history.push('/portal/Search/?'+encodeURIComponent(this.query));
this.input = this.query;
}
}
@inject((stores, props, context) => props) @observer
class DBSearch extends React.Component {
@observable loaded = false;
constructor() {
super();
this.filter = new loki("filter.db");
}
render() {
let string = this.props.string;
if (API.urls === null ||
API.portal === null ||
API.cards === null) {
return (<span>Loading...</span>);
}
if (this.loaded == false) {
API.buildCollection([{'portal': 'attacks'}, , {'portal': 'battlegear'}, {'portal': 'creatures'}, {'portal': 'locations'}, {'portal': 'mugic'}])
.then(() => {
this.loaded = true;
});
return (<span>Loading...</span>);
}
// No search
if (string == "") {
return (<div></div>);
}
let filter = this.filter.addCollection('filter');
var pview = filter.addDynamicView('filter');
pview.applySimpleSort('gsx$name');
let attackResults = API.portal.attacks.chain();
let battlegearResults = API.portal.battlegear.chain();
let creatureResults = API.portal.creatures.chain();
let locationResults = API.portal.locations.chain();
let mugicResults = API.portal.mugic.chain();
// Attributes Background Details
attackResults = attackResults.find({'$or': [
{'gsx$name': {'$regex': new RegExp(string, 'i')}},
{'gsx$attributes': {'$regex': new RegExp(string, 'i')}},
{'gsx$background': {'$regex': new RegExp(string, 'i')}},
{'gsx$details': {'$regex': new RegExp(string, 'i')}}
]});
// Attributes Background Details
battlegearResults = battlegearResults.find({'$or': [
{'gsx$name': {'$regex': new RegExp(string, 'i')}},
{'gsx$attributes': {'$regex': new RegExp(string, 'i')}},
{'gsx$background': {'$regex': new RegExp(string, 'i')}},
{'gsx$details': {'$regex': new RegExp(string, 'i')}}
]});
// Appearance Background Special Abilities Details
creatureResults = creatureResults.find({'$or': [
{'gsx$name': {'$regex': new RegExp(string, 'i')}},
{'gsx$appearance': {'$regex': new RegExp(string, 'i')}},
{'gsx$background': {'$regex': new RegExp(string, 'i')}},
{'gsx$specialabilities': {'$regex': new RegExp(string, 'i')}},
{'gsx$details': {'$regex': new RegExp(string, 'i')}}
]});
// Local Features Background Details
locationResults = locationResults.find({'$or': [
{'gsx$name': {'$regex': new RegExp(string, 'i')}},
{'gsx$localfeatures': {'$regex': new RegExp(string, 'i')}},
{'gsx$background': {'$regex': new RegExp(string, 'i')}},
{'gsx$details': {'$regex': new RegExp(string, 'i')}}
]});
// Background Details
mugicResults = mugicResults.find({'$or': [
{'gsx$name': {'$regex': new RegExp(string, 'i')}},
{'gsx$background': {'$regex': new RegExp(string, 'i')}},
{'gsx$details': {'$regex': new RegExp(string, 'i')}}
]});
let temp;
temp = attackResults.data();
temp.forEach(function(v){ delete v.$loki });
filter.insert(temp);
temp = battlegearResults.data();
temp.forEach(function(v){ delete v.$loki });
filter.insert(temp);
temp = creatureResults.data();
temp.forEach(function(v){ delete v.$loki });
filter.insert(temp);
temp = locationResults.data();
temp.forEach(function(v){ delete v.$loki });
filter.insert(temp);
temp = mugicResults.data();
temp.forEach(function(v){ delete v.$loki });
filter.insert(temp);
let results = pview.data();
this.filter.removeCollection('filter');
let content = results.map((card, i) => {
let link = "/portal";
switch (card.gsx$type) {
case "Attacks":
link += '/Attacks/' + card.gsx$name;
break;
case "Battlegear":
link += '/Battlegear/' + card.gsx$name;
break;
case "Creatures":
link += '/Creatures/' + card.gsx$name;
break;
case "Locations":
link += '/Locations/' + card.gsx$name;
break;
case "Mugic":
link += '/Mugic/' + card.gsx$name;
break;
}
return (<div key={i}><Interactive as={Link} {...s.link} to={link}>
{card.gsx$name}
</Interactive><br /></div>);
});
if (results.length == 0) {
content = (<div>No Results Found</div>);
}
return (<div className="results">
<div>Results containing {string}:</div><br />
{content}
</div>);
}
}

View File

@ -12,6 +12,7 @@ import Creatures from './Category/Creatures';
import Locations from './Category/Locations';
import Mugic from './Category/Mugic';
import Tribes from './Category/Tribes';
import {SearchButton} from '../Snippets';
@inject((stores, props, context) => props) @observer
export default class Base extends React.Component {
@ -43,16 +44,22 @@ function Routing(props) {
<Route path={`${match.url}/Locations`} component={Locations} />
<Route path={`${match.url}/Mugic`} component={Mugic} />
{tribes}
<Route path={`${match.url}/Search`} component={Search} />
</div>
);
}
function voidClick(e) {
e.preventDefault();
e.stopPropagation();
}
function Header() {
const types = (() => {
return (
<li className="dropdown">
<Link to=" " className="dropbtn">Types</Link>
<Link to=" " onClick={voidClick} className="dropbtn">Types</Link>
<div className="dropdown-content">
<Link to="/portal/Attacks">Attacks</Link>
<Link to="/portal/Battlegear">Battlegear</Link>
@ -67,8 +74,9 @@ function Header() {
const tribes = ["Danian", "Mipedian", "OverWorld", "UnderWorld"].map((tribe, i) => {
return (
<li key={i} className="dropdown">
<Link to={"/portal/"+tribe} className="dropbtn">{tribe}</Link>
<Link to=" " className="dropbtn" onClick={voidClick}>{tribe}</Link>
<div className="dropdown-content">
<Link to={"/portal/"+tribe}>All</Link>
<Link to={"/portal/Creatures/"+tribe}> Creatures</Link>
<Link to={"/portal/Mugic/"+tribe}> Mugic</Link>
</div>
@ -80,10 +88,10 @@ function Header() {
<div className="navbar">
<ul>
<li><Link to="/portal/">Home</Link></li>
<li><Link to="javascript:void(0)"><Search /></Link></li>
<li><Link to="/portal/Search"><SearchButton />Search</Link></li>
{types}
<li className="dropdown">
<Link to={"/portal/Generic"} className="dropbtn">Generic</Link>
<Link to=" " onClick={voidClick} className="dropbtn">Generic</Link>
<div className="dropdown-content">
<Link to={"/portal/Generic/Mugic"}>Mugic</Link>
</div>
@ -93,3 +101,4 @@ function Header() {
</div>
);
}

View File

@ -81,10 +81,6 @@
display: block;
}
.search {
}
.magnifying-glass {
cursor: pointer;
transition: color .2s;
@ -124,3 +120,12 @@
.entry .icon20, .entry .icon24 {
vertical-align: middle;
}
.search .results div {
padding-top: 10px;
}
.search .results a {
font-size: 16px;
line-height: 20px;
}