feat: functional search on site
This commit is contained in:
@@ -145,32 +145,28 @@
|
|||||||
<p>NO MATCHING STRAINS :(</p>
|
<p>NO MATCHING STRAINS :(</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="strains.length > 0" class="container cards">
|
<div v-if="strains.length > 0" class="container">
|
||||||
<div v-for="strain in strains" class="card">
|
<div>
|
||||||
<header class="card-header">
|
<h3 class="title is-3">Found {{strains.length}} Strains</h3>
|
||||||
<p class="card-header-title">{{strain.name | capitalize}}</p>
|
</div>
|
||||||
<div class="tags" style="margin: 0 12px;">
|
|
||||||
<span class="tag is-rounded is-light">{{strain.rating | round}} ({{strain.rating_count}})</span>
|
<div class="cards">
|
||||||
</div>
|
<strain-card v-for="strain in strains" :strain="strain" />
|
||||||
</header>
|
|
||||||
<div class="card-content">
|
|
||||||
<span v-if="strain.category === 'indica'" class="tag is-rounded is-indica">{{strain.category}}</span>
|
|
||||||
<span v-if="strain.category === 'sativa'" class="tag is-rounded is-sativa">{{strain.category}}</span>
|
|
||||||
<span v-if="strain.category === 'hybrid'" class="tag is-rounded is-hybrid">{{strain.category}}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<script src="https://unpkg.com/lunr@2.3.1/lunr.js"></script>
|
<!-- dev build of vue, useful for debugging -->
|
||||||
<!-- <script src="https://unpkg.com/vue@2.5.17/dist/vue.js"></script> -->
|
<!-- <script src="https://unpkg.com/vue@2.5.17/dist/vue.js"></script> -->
|
||||||
|
<!-- production build of vue, with template compiler -->
|
||||||
<script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script>
|
<script src="https://unpkg.com/vue@2.5.17/dist/vue.min.js"></script>
|
||||||
|
<script src="https://unpkg.com/lunr@2.3.1/lunr.js"></script>
|
||||||
<script src="https://unpkg.com/mitt@1.1.3/dist/mitt.umd.js"></script>
|
<script src="https://unpkg.com/mitt@1.1.3/dist/mitt.umd.js"></script>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// lunr = window.lunr
|
// lunr = window.lunr
|
||||||
// mitt = window.mitt
|
// mitt = window.mitt
|
||||||
(function ({ mitt, lunr }) {
|
(function ({ mitt, lunr }, data) {
|
||||||
const data = <%- data %>;
|
|
||||||
const emitter = mitt();
|
const emitter = mitt();
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
@@ -188,6 +184,50 @@
|
|||||||
return Math.round(v * (10 * digits)) / (10 * digits);
|
return Math.round(v * (10 * digits)) / (10 * digits);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Vue.component('tag-list', {
|
||||||
|
props: {
|
||||||
|
tags: Array,
|
||||||
|
title: String,
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div v-if="tags.length" class="tag-list columns is-mobile">
|
||||||
|
<div class="tag-list--title column is-one-quarter">
|
||||||
|
{{title}}
|
||||||
|
</div>
|
||||||
|
<div class="tag-list--tag column">
|
||||||
|
<div v-if="tags.length" class="tags">
|
||||||
|
<span v-for="tag in tags" class="tag is-rounded">{{tag}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component('strain-card', {
|
||||||
|
props: {
|
||||||
|
strain: Object,
|
||||||
|
},
|
||||||
|
template: `
|
||||||
|
<div class="card">
|
||||||
|
<header class="card-header">
|
||||||
|
<p class="card-header-title">{{strain.name}}</p>
|
||||||
|
<div class="tags" style="margin: 0 12px; padding: 6px 0;">
|
||||||
|
<span v-if="strain.category === 'indica'" class="tag is-rounded is-indica">{{strain.category}}</span>
|
||||||
|
<span v-if="strain.category === 'sativa'" class="tag is-rounded is-sativa">{{strain.category}}</span>
|
||||||
|
<span v-if="strain.category === 'hybrid'" class="tag is-rounded is-hybrid">{{strain.category}}</span>
|
||||||
|
<span class="tag is-rounded is-light">{{strain.rating | round}} ({{strain.rating_count}})</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<div class="card-content">
|
||||||
|
<tag-list title="Effects" :tags="strain.effects" />
|
||||||
|
<tag-list title="Uses" :tags="strain.uses" />
|
||||||
|
<tag-list title="Conditions" :tags="strain.conditions" />
|
||||||
|
<tag-list title="Flavors" :tags="strain.flavors" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
});
|
||||||
|
|
||||||
// form handler
|
// form handler
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#search-form',
|
el: '#search-form',
|
||||||
@@ -208,7 +248,8 @@
|
|||||||
conditions: getMultiValues(this.$refs.conditions),
|
conditions: getMultiValues(this.$refs.conditions),
|
||||||
flavors: getMultiValues(this.$refs.flavors),
|
flavors: getMultiValues(this.$refs.flavors),
|
||||||
}
|
}
|
||||||
emitter.emit('search', requirements)
|
|
||||||
|
emitter.emit('search', requirements);
|
||||||
},
|
},
|
||||||
resetForm() {
|
resetForm() {
|
||||||
this.$el.reset();
|
this.$el.reset();
|
||||||
@@ -232,18 +273,30 @@
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
emitter.on('search', this.setRequirements);
|
// lunr setup
|
||||||
|
this.idx = window.idx = lunr(function () {
|
||||||
|
this.ref('id');
|
||||||
|
this.field('name');
|
||||||
|
this.field('effects');
|
||||||
|
this.field('uses');
|
||||||
|
this.field('conditions');
|
||||||
|
this.field('flavors');
|
||||||
|
data.strains.forEach(doc => this.add(doc));
|
||||||
|
});
|
||||||
|
|
||||||
|
this.searchListener = reqs => {
|
||||||
|
this.requirements = reqs;
|
||||||
|
this.updateStrains();
|
||||||
|
}
|
||||||
|
|
||||||
|
emitter.on('search', r => this.searchListener(r));
|
||||||
this.updateStrains();
|
this.updateStrains();
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
emitter.off('search', this.setRequirements);
|
emitter.off('search', r => this.searchListener(r));
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
setRequirements(reqs) {
|
updateStrains(limit = 40) {
|
||||||
// this.requirements = reqs;
|
|
||||||
reqs => console.log('search params', reqs);
|
|
||||||
},
|
|
||||||
updateStrains(limit = 20) {
|
|
||||||
const hasName = this.requirements.name.length > 0;
|
const hasName = this.requirements.name.length > 0;
|
||||||
const hasFilters =
|
const hasFilters =
|
||||||
this.requirements.effects.length > 0 ||
|
this.requirements.effects.length > 0 ||
|
||||||
@@ -252,13 +305,42 @@
|
|||||||
this.requirements.flavors.length > 0;
|
this.requirements.flavors.length > 0;
|
||||||
|
|
||||||
if (!hasName && !hasFilters) {
|
if (!hasName && !hasFilters) {
|
||||||
this.strains = this.all_strains.slice(0, limit);
|
this.strains = this
|
||||||
|
.all_strains
|
||||||
|
.slice(0, limit);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const searchParts = [this.requirements.name];
|
||||||
|
this.requirements.effects.forEach(t => searchParts.push(`+effects:${t}`));
|
||||||
|
this.requirements.uses.forEach(t => searchParts.push(`+uses:${t}`));
|
||||||
|
this.requirements.conditions.forEach(t => searchParts.push(`+conditions:${t}`));
|
||||||
|
this.requirements.flavors.forEach(t => searchParts.push(`+flavors:${t}`));
|
||||||
|
|
||||||
|
const hits = this.idx
|
||||||
|
.search(searchParts.join(' '))
|
||||||
|
// .slice(0, limit);
|
||||||
|
const refs = hits.map(({ ref }) => parseInt(ref, 10));
|
||||||
|
|
||||||
|
this.strains = this
|
||||||
|
.all_strains
|
||||||
|
.map((strain, i) => {
|
||||||
|
const idx = refs.indexOf(strain.id);
|
||||||
|
if (idx < 0) return;
|
||||||
|
return Object.assign({ score: hits[idx].score }, strain)
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
.sort((a, b) => {
|
||||||
|
if (a.score === b.score) {
|
||||||
|
if (a.rating === b.rating) return 0;
|
||||||
|
return a.rating > b.rating ? -1 : 1;
|
||||||
|
}
|
||||||
|
return a.score > b.score ? -1 : 1;
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
})(this, <%- data %>);
|
||||||
})(this);
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,8 @@ function getData() {
|
|||||||
async function build() {
|
async function build() {
|
||||||
const data = await getData();
|
const data = await getData();
|
||||||
const options = {};
|
const options = {};
|
||||||
|
|
||||||
|
// order strains by rating
|
||||||
data.strains = data.strains.sort((n, strain) => {
|
data.strains = data.strains.sort((n, strain) => {
|
||||||
if (strain.rating === n.rating) return 0;
|
if (strain.rating === n.rating) return 0;
|
||||||
return strain.rating < n.rating ? -1 : 1;
|
return strain.rating < n.rating ? -1 : 1;
|
||||||
|
|||||||
Reference in New Issue
Block a user