doesitarm/components/search.vue
2020-09-19 22:05:21 -05:00

211 lines
8.7 KiB
Vue

<template>
<div class="flex flex-col items-center">
<div class="search-input container relative">
<input
id="search"
ref="search"
v-model="query"
aria-label="Type here to Search"
class="appearance-none w-full text-white font-hairline sm:text-5xl outline-none bg-transparent p-3"
type="search"
placeholder="Type to Search"
autofocus
autocomplete="off"
@keyup="queryResults(query)"
>
<div class="search-input-separator border-white border-t-2" />
</div>
<div
ref="search-container"
class="search-container relative w-full"
>
<div class="search-wrapper flex justify-center pb-32">
<div class="search-scroller container w-full relative px-5">
<div class="search-results py-8">
<ul class="results-container rounded-lg border neumorphic-shadow">
<li
v-for="(app, i) in results"
:key="`${app.slug}-${i}`"
>
<a
:href="`/app/${ app.slug }`"
class="block hover:neumorphic-shadow hover:bg-gradient-to-tr from-darkest to-darker focus:outline-none focus:bg-gray-50 transition duration-300 ease-in-out rounded-lg">
<div class="flex items-center px-4 py-4 sm:px-6">
<div class="min-w-0 flex-1 flex items-center">
<div class="flex-shrink-0">
<div
class="h-12 w-12 rounded-full flex items-center justify-center neumorphic-shadow-inner"
>
<div>{{ app.name.charAt(0) }}</div>
</div>
</div>
<div class="min-w-0 flex-1 px-4 md:grid md:grid-cols-2 md:gap-4">
<div>
<div class="text-sm leading-5 font-light truncate">{{ app.name }}</div>
<div class="mt-2 flex items-center text-sm leading-5 text-gray-500">
<span class="truncate">{{ app.text }}</span>
</div>
</div>
<div class="hidden md:block">
<div>
<!-- <div class="text-sm leading-5 text-gray-900">
Applied on
<time datetime="2020-01-07">January 7, 2020</time>
</div> -->
<!-- <div class="mt-2 flex items-center text-sm leading-5 text-gray-500">
{{ app.text }}
</div> -->
</div>
</div>
</div>
</div>
<div>
<!-- Heroicon name: chevron-right -->
<svg
class="h-5 w-5 text-gray-400"
viewBox="0 0 20 20"
fill="currentColor">
<path
fill-rule="evenodd"
d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"
clip-rule="evenodd" />
</svg>
</div>
</div>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import appList from '~/assets/app-list.json'
// import overlayStore from './mixins/store'
// import modalRouter from '~/components/modals/mixins/router'
// import Card from '~/components/cards/Default.vue'
// import CardsRow from '~/components/cards/Row.vue'
// import ComingSoonImage from '~/components/partials/ComingSoonImage.vue'
// import InfoCircle from '~/assets/svg/info-circle.svg?inline'
// import PlayCircle from '~/assets/svg/play-circle.svg?inline'
export default {
data: function () {
return {
appList,
query: '',
// results: [],
titleStartsWithResults: [],
titleContainsResults: [],
descriptionContainsResults: [],
// store: overlayStore.state
}
},
computed: {
results () {
if (!this.hasSearchInputText) return appList
return [
...this.titleStartsWithResults,
...this.titleContainsResults,
...this.descriptionContainsResults
]
},
hasSearchInputText () {
return this.query.length > 0
},
},
// watch: {
// 'store.mode': function (newMode) {
// // If we're showing the search
// // then focus on the search input
// // on the next tick when our input
// // exists
// if (newMode === 'search') {
// this.$nextTick(() => {
// this.$refs.search.focus()
// })
// }
// }
// },
// mounted () {
// },
methods: {
// Search priorities
titleStartsWith (query, app) {
const matches = app.name.toLowerCase().startsWith(query)
if (matches) {
this.titleStartsWithResults.push(app)
}
return matches
},
titleContains (query, app) {
const matches = app.name.toLowerCase().includes(query)
if (matches) {
this.titleContainsResults.push(app)
}
return matches
},
descriptionContains (query, app) {
const matches = app.description.toLowerCase().includes(query)
if (matches) {
this.descriptionContainsResults.push(app)
}
return matches
},
// Search tools
pluck (array, index) {
const pluckedItem = array[index]
array.splice(index, 1)
return pluckedItem
},
queryResults (rawQuery) {
// Clear any results from before
this.titleStartsWithResults = []
this.titleContainsResults = []
this.descriptionContainsResults = []
// Snap results scroll position back to top
this.$refs['search-container'].scrollTop = 0
// If our query is empty
// then bail
if (rawQuery.length === 0) return
const query = rawQuery.toLowerCase()
// Search App List
this.appList.forEach(app => {
const matchers = [
this.titleStartsWith,
this.titleContains,
// this.descriptionContains
]
// Run through our search priorities
for (const method of matchers){
// iterations++
const appMatches = method(query, app)
if (appMatches) {
// We've found a match for this app
// so let's stop trying match methods
// and search the next app
break
}
}
})
// console.log('query', query)
// console.log('iterations', iterations)
}
}
}
</script>