diff options
| author | David T. Sadler <davidtsadler@googlemail.com> | 2020-02-17 19:59:15 +0000 |
|---|---|---|
| committer | David T. Sadler <davidtsadler@googlemail.com> | 2020-02-17 19:59:15 +0000 |
| commit | 498913806182905cc0c14bd12a61f9af26fa16b4 (patch) | |
| tree | 0c36a6df72900c184e900b274bad14aa5114fc5d /source/_assets/js | |
| parent | 12b052b1f480c5a95acd1477e28ce76f84ff7932 (diff) | |
Switch over to Jigsaw
Diffstat (limited to 'source/_assets/js')
| -rw-r--r-- | source/_assets/js/components/Search.vue | 133 | ||||
| -rw-r--r-- | source/_assets/js/main.js | 30 |
2 files changed, 163 insertions, 0 deletions
diff --git a/source/_assets/js/components/Search.vue b/source/_assets/js/components/Search.vue new file mode 100644 index 0000000..c5715a9 --- /dev/null +++ b/source/_assets/js/components/Search.vue @@ -0,0 +1,133 @@ +<template> + <div class="flex flex-1 justify-end items-center text-right px-4"> + <div + class="absolute md:relative w-full justify-end bg-white left-0 top-0 z-10 mt-7 md:mt-0 px-4 md:px-0" + :class="{'hidden md:flex': ! searching}" + > + <label for="search" class="hidden">Search</label> + + <input + id="search" + v-model="query" + ref="search" + class="transition-fast relative block h-10 w-full lg:w-1/2 lg:focus:w-3/4 bg-gray-100 border border-gray-500 focus:border-blue-400 outline-none cursor-pointer text-gray-700 px-4 pb-0 pt-px" + :class="{ 'transition-border': query }" + autocomplete="off" + name="search" + placeholder="Search" + type="text" + @keyup.esc="reset" + @blur="reset" + > + + <button + v-if="query || searching" + class="absolute top-0 right-0 leading-snug font-400 text-3xl text-blue-500 hover:text-blue-600 focus:outline-none pr-7 md:pr-3" + @click="reset" + >×</button> + + <transition name="fade"> + <div v-if="query" class="absolute left-0 right-0 md:inset-auto w-full lg:w-3/4 text-left mb-4 md:mt-10"> + <div class="flex flex-col bg-white border border-b-0 border-t-0 border-blue-400 rounded-b-lg shadow-lg mx-4 md:mx-0"> + <a + v-for="(result, index) in results" + class="bg-white hover:bg-blue-100 border-b border-blue-400 text-xl cursor-pointer p-4" + :class="{ 'rounded-b-lg' : (index === results.length - 1) }" + :href="result.link" + :title="result.title" + :key="result.link" + @mousedown.prevent + > + {{ result.title }} + + <span class="block font-normal text-gray-700 text-sm my-1" v-html="result.snippet"></span> + </a> + + <div + v-if="! results.length" + class="bg-white w-full hover:bg-blue-100 border-b border-blue-400 rounded-b-lg shadow cursor-pointer p-4" + > + <p class="my-0">No results for <strong>{{ query }}</strong></p> + </div> + </div> + </div> + </transition> + </div> + + <button + title="Start searching" + type="button" + class="flex md:hidden bg-gray-100 hover:bg-blue-100 justify-center items-center border border-gray-500 rounded-full focus:outline-none h-10 px-3" + @click.prevent="showInput" + > + <img src="/assets/img/magnifying-glass.svg" alt="search icon" class="h-4 w-4 max-w-none"> + </button> + </div> +</template> + +<script> +export default { + data() { + return { + fuse: null, + searching: false, + query: '', + }; + }, + computed: { + results() { + return this.query ? this.fuse.search(this.query) : []; + }, + }, + methods: { + showInput() { + this.searching = true; + this.$nextTick(() => { + this.$refs.search.focus(); + }) + }, + reset() { + this.query = ''; + this.searching = false; + }, + }, + created() { + axios('/index.json').then(response => { + this.fuse = new fuse(response.data, { + minMatchCharLength: 6, + keys: ['title', 'snippet', 'categories'], + }); + }); + }, +}; +</script> + +<style> +input[name='search'] { + background-image: url('/assets/img/magnifying-glass.svg'); + background-position: 0.8em; + background-repeat: no-repeat; + border-radius: 25px; + text-indent: 1.2em; +} + +input[name='search'].transition-border { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; + border-top-left-radius: .5rem; + border-top-right-radius: .5rem; +} + +.fade-enter-active { + transition: opacity .5s; +} + +.fade-leave-active { + transition: opacity 0s; +} + +.fade-enter, +.fade-leave-to { + opacity: 0; +} +</style> diff --git a/source/_assets/js/main.js b/source/_assets/js/main.js new file mode 100644 index 0000000..d3a9909 --- /dev/null +++ b/source/_assets/js/main.js @@ -0,0 +1,30 @@ +window.axios = require('axios'); +window.fuse = require('fuse.js'); +window.Vue = require('vue'); + +import Search from './components/Search.vue'; +import hljs from 'highlight.js/lib/highlight'; + +// Syntax highlighting +hljs.registerLanguage('bash', require('highlight.js/lib/languages/bash')); +hljs.registerLanguage('css', require('highlight.js/lib/languages/css')); +hljs.registerLanguage('html', require('highlight.js/lib/languages/xml')); +hljs.registerLanguage('javascript', require('highlight.js/lib/languages/javascript')); +hljs.registerLanguage('json', require('highlight.js/lib/languages/json')); +hljs.registerLanguage('markdown', require('highlight.js/lib/languages/markdown')); +hljs.registerLanguage('php', require('highlight.js/lib/languages/php')); +hljs.registerLanguage('scss', require('highlight.js/lib/languages/scss')); +hljs.registerLanguage('yaml', require('highlight.js/lib/languages/yaml')); + +document.querySelectorAll('pre code').forEach((block) => { + hljs.highlightBlock(block); +}); + +Vue.config.productionTip = false; + +new Vue({ + components: { + Search, + }, +}).$mount('#vue-search'); + |
