Skip to content

Commit

Permalink
Added search
Browse files Browse the repository at this point in the history
  • Loading branch information
Auspicus committed Mar 17, 2019
1 parent 1d5ab50 commit 3aafeb4
Show file tree
Hide file tree
Showing 29 changed files with 6,449 additions and 9 deletions.
10 changes: 10 additions & 0 deletions content/page/search.es.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"date": "2017-09-12T13:25:52-06:00",
"url": "/es/buscar",
"title": "Buscar",
"call_to_action": [

],
"summary": "Your first and last stop when looking for things in Nosara."
}
{{< search >}}
10 changes: 10 additions & 0 deletions content/page/search.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"date": "2017-09-12T13:25:52-06:00",
"url": "/search",
"title": "Search",
"call_to_action": [

],
"summary": "Your first and last stop when looking for things in Nosara."
}
{{< search >}}
5 changes: 3 additions & 2 deletions themes/humans-of-nosara/components/field/field.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ function delay (cb) {
setTimeout(cb, 100);
}

document.querySelectorAll('.field > input')
document
.querySelectorAll('.field > input')
.forEach(function ($input) {
var $label = siblings($input, 'label')[0];
if ($input.value) {
Expand All @@ -31,4 +32,4 @@ document.querySelectorAll('.field > input')
$label.classList.add('field__label--active');
});
});
});
})
184 changes: 184 additions & 0 deletions themes/humans-of-nosara/components/search/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
const search = require('js-search')
const preact = require('preact')
const h = preact.h
const Component = preact.Component

class Search extends Component {
constructor(props) {
super(props)

this.state = { query: '' }
this.search = new search.Search('uid')
this.onChange = this.onChange.bind(this)
}

getKey(item, key) {
let root = item
const parts = key.split('.')
while (parts.length) {
root = root[parts.shift()]
}
return root
}

createFacets(entityTypes) {
// Store all searchable values
const facets = []

// Loop through each entity and collect searchable values
return facets
}

normalizeEntities(entityTypes) {
const normalizers = {
'name': data => data,
'phone': data => data && data.replace(/(\(*-*\)*\s*)/g, ''),
'location.name': data => data
}
const data = {}

entityTypes.forEach(entityType => {
// Create the index for this entity type
data[entityType.type] = data[entityType.type] || {}

// Fill the index with each unique entity
entityType.data.forEach(entity => {
data[entityType.type][entity.uid] = entity
})
})

return data
}

componentDidMount() {
this
.load()
.then(entityTypes => {

})
}

onChange(event) {
this.setState({ query: event.target.value })
}

load() {
return Promise.all([
'/data/c21_property.json',
'/data/hon_charity.json',
'/data/hon_interviewee.json',
'/data/ves_graduate.json',
'/data/remax_property.json'
].map(async data => {
const response = await fetch(data)
return await response.json()
}))
}

dedupe(arr, key) {
return arr.filter((o, i, arr) => arr.findIndex(t => t[key] === o[key]) === i)
}

itemFromUID(uid) {
const parts = uid.split(':')
const entityType = parts.shift()
const entityId = parts.shift()

return this.state.data[entityType][entityId]
}

query(n) {
const multi = this.state.query.split(' ')
const occurences = {}
const results = []

while (multi.length) {
const next = multi.shift()
results.push.apply(
results,
this
.state
.facets
.filter(f => f.key.toLowerCase().indexOf(next) > -1)
)
}

// Create a map to sort results by # of matches
results
.forEach(result => {
occurences[result.uid] = occurences[result.uid] || 0
occurences[result.uid]++
})

return (
this
.dedupe(
results
.filter(item => occurences[item.uid] > multi.length)
.sort((a, b) => occurences[b.uid] - occurences[a.uid]),
'uid'
)
.map(item => { console.log(item); return item; })
.slice(0, n)
.map(result => this.itemFromUID(result.uid))
)
}

render() {
const results = this.state.query ? this.query(25).map(item => {
const src = !!item.image
? item.image
: !!item.images
? item.images[0]
: null
const href = !!item.url
? item.url
: null
const phone = !!item.phone
? item.phone
: null
const price = !!item.price
? item.price
: null
const location = !!item.location
? item.location
: null
const locationName = !!location
? location.name
: null

return (
h('div', { className: 'search__result' },
h('a', { href, target: '_blank' }, [
src ? h('div', { className: 'search__image', style: { backgroundImage: `url(${src})` } }) : null,
price
? h('div', { className: 'search__price' }, `$${Number(price).toLocaleString()}`)
: null,
h('h3', null, item.name),
phone
? href
? h('div', { className: 'search__phone' }, phone)
: h('a', { href: `tel:${phone}` }, h('div', { className: 'search__phone' }, phone))
: null,
locationName
? h('div', { className: 'search__location' }, locationName)
: null,
])
)
)
}) : null

return (
h('div', null, [
h('div', { className: 'field search__field '}, [
h('svg', { className: 'search__icon', xmlns: 'http:https://www.w3.org/2000/svg', viewBox: '0 0 20 20' }, [ h('path', { d: 'M12.9 14.32a8 8 0 1 1 1.41-1.41l5.35 5.33-1.42 1.42-5.33-5.34zM8 14A6 6 0 1 0 8 2a6 6 0 0 0 0 12z' }) ]),
h('input', { value: this.state.query, className: 'field__input', id: 'search', type: 'text', name: 'search', placeholder: 'What are you looking for?', onInput: this.onChange })
]),
!this.state.query ? h('div', { className: 'search__suggestions' }, 'You could try looking for people, properties or charities.') : null,
h('div', { className: 'search__results' }, results)
])
)
}
}

preact.render(h(Search), document.querySelector('#search'))
81 changes: 81 additions & 0 deletions themes/humans-of-nosara/components/search/search.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
.search {
max-width: 960px;
margin: 2rem auto;
text-align: center;
}

.search__field input {
padding-top: .75rem;
padding-bottom: .75rem;
padding-left: 2.5rem;
font-family: 'Montserrat', sans-serif;
}

.search__icon {
position: absolute;
left: .75rem;
top: .85rem;
width: 1rem;
height: 1rem;
fill: #3c3c3c;
}

.search__suggestions {
margin: 2rem 0;
font-weight: 700;
font-size: .9rem;
}

.search__results {
margin: 2rem auto;
display: flex;
flex-wrap: wrap;
justify-content: space-between;
}

.search__result {
box-sizing: border-box;
flex: 1 1 100%;
text-align: left;
box-shadow: 0 10px 15px rgba(50, 50, 93, .1), 0 5px 15px rgba(0, 0, 0, .07);
margin-bottom: 3rem;
border-radius: 5px;
overflow: hidden;
}
@media (min-width: 560px) {
.search__result {
flex: 0 1 47%;
}
}

.search__result a {
text-decoration: inherit;
}

.search__image {
width: 100%;
height: 10rem;
background-size: cover;
background-position: center;
background-repeat: no-repeat;
}

.search__result h3 {
margin: 1rem;
font-size: 1rem;
}

.search__phone {
font-size: .8rem;
margin: 1rem;
}

.search__price {
font-size: 1.25rem;
margin: 1rem;
}

.search__location {
font-size: .8rem;
margin: 1rem;
}
3 changes: 3 additions & 0 deletions themes/humans-of-nosara/crawlers/bt_yoga_class.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = () => {

}
25 changes: 25 additions & 0 deletions themes/humans-of-nosara/crawlers/c21_property.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = async (page) => {
await page.goto('https://century21nosara.com/nosara-real-estate-listings/', {
waitUntil: 'load',
timeout: 0
})

const properties = await page.evaluate(() => {
const data = []
document.querySelectorAll('.property-item-wrapper').forEach(node => {
try {
data.push({
uid: 'c21_property_' + data.length,
name: node.querySelector('h4 a').innerHTML.trim(),
location: { name: 'Nosara', geo: null },
images: [node.querySelector('.attachment-property-thumb-image').src],
price: parseInt(node.querySelector('.price').innerHTML.split('<small>').shift().trim().replace(/\$/g, '').replace('.00', '').replace(/,/g, '')),
url: node.querySelector('h4 a').href
})
} catch (err) {}
})
return data
})

return properties
}
19 changes: 19 additions & 0 deletions themes/humans-of-nosara/crawlers/hon_charity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module.exports = async (page) => {
await page.goto('https://www.humansofnosara.org/donate/')

const charities = await page.evaluate(() => {
const data = []
document.querySelectorAll('.feature-cta').forEach(node => {
data.push({
uid: 'hon_charity_' + data.length,
name: node.querySelector('.feature-cta__button').innerHTML.trim(),
image: node.querySelector('.feature-cta__background').style.backgroundImage.replace('url("', '').replace('")', ''),
location: { name: 'Nosara', geo: null },
url: node.querySelector('.feature-cta__content-link').href
})
})
return data
})

return charities
}
25 changes: 25 additions & 0 deletions themes/humans-of-nosara/crawlers/hon_interviewee.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
module.exports = async (page) => {
await page.goto('https://www.humansofnosara.org/')

const interviewee = await page.evaluate(() => {
const data = []
const capitalize = str => str.split(' ').map(substr => `${substr.slice(0, 1).toUpperCase()}${substr.slice(1)}`).join(' ')
document.querySelectorAll('.article-teaser').forEach(node => {
try {
data.push({
uid: 'hon_interviewee_' + data.length,
name: capitalize(node.querySelector('a').href.replace('https://www.humansofnosara.org/human/', '').replace(/-/g, ' ').replace(/\//g, '')),
image: node.querySelector('.article-teaser__image').src,
location: { name: 'Nosara', geo: null },
phone: null,
email: null
})
} catch (err) {
data.push(err.toString())
}
})
return data
})

return interviewee
}
Loading

0 comments on commit 3aafeb4

Please sign in to comment.