]> git.immae.eu Git - github/bastienwirtz/homer.git/commitdiff
Add keyboard shortcuts to navigate to the first search result. 37/head
authorJozef Selesi <jozef.selesi@sky.uk>
Thu, 26 Mar 2020 19:12:43 +0000 (19:12 +0000)
committerJozef Selesi <jozef.selesi@sky.uk>
Sat, 4 Apr 2020 09:59:10 +0000 (10:59 +0100)
README.md
app.js
index.html

index 5ab7c26e3c9c759cd9071f621cae5df38be88d1d..f052fc9074939580702289034951413228ee13f8 100644 (file)
--- a/README.md
+++ b/README.md
@@ -3,6 +3,13 @@ A dead simple static **HOM**epage for your serv**ER** to keep your services on h
 
 **Check out the live demo [here](https://homer-demo.netlify.com/).**
 
+It supports keyboard shortcuts:
+
+* `/` Start searching.
+* `Escape` Stop searching.
+* `Enter` Open the first matching result (respects the bookmark's `_target` property).
+* `Alt`/`Option` + `Enter` Open the first matching result in a new tab.
+
 If you need authentication support, you're on your own (it can be secured using a web server auth module or exposing it only through a VPN network / SSH tunnel, ...)
 
 ![screenshot](https://raw.github.com/bastienwirtz/homer/master/screenshot.png)
diff --git a/app.js b/app.js
index 36508abb694ef108fc0ecbfd552f3cda62a71f81..e79611069f9d779d4a09e969157ec805b0c24628 100644 (file)
--- a/app.js
+++ b/app.js
@@ -84,6 +84,26 @@ const app = new Vue({
         },
         toggleMenu: function() {
             this.showMenu = !this.showMenu;
+        },
+        matchesFilter: function(item) {
+            return (item.name.toLowerCase().includes(this.filter.toLowerCase())
+                || (item.tag && item.tag.toLowerCase().includes(this.filter.toLowerCase())))
+        },
+        firstMatchingService: function() {
+            for (group of this.config.services) {
+                for (item of group.items) {
+                    if (this.matchesFilter(item)) {
+                        return item;
+                    }
+                }
+            }
+            return null;
+        },
+        navigateToFirstService: function(target) {
+            service = this.firstMatchingService();
+            if (service) {
+                window.open(service.url, target || service.target || '_self');
+            }
         }
     },
     mounted() {
index 85c9b789f62e0ec95168e9f5333a96f2599d278c..d427002693e385cf11e86c96346824ef989e7e0e 100644 (file)
@@ -59,7 +59,9 @@
                       :class="['fas', vlayout ? 'fa-list' : 'fa-columns']"></i></a>
                   <div class="search-bar">
                     <label for="search" class="search-label"></label>
-                    <input type="text" id="search" ref="search" v-model="filter" />
+                    <input type="text" id="search" ref="search" v-model="filter"
+                      v-on:keyup.enter.exact="navigateToFirstService()"
+                      v-on:keyup.alt.enter="navigateToFirstService('_blank')" />
                   </div>
                 </div>
               </div>
@@ -95,7 +97,7 @@
                   v-else>#</span>
                 {{ group.name }}</h2>
               <service v-for="item in group.items" v-bind:item="item" class="column is-one-third-widescreen"
-                v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))">
+                v-if="!filter || (item && matchesFilter(item))">
               </service>
             </template>
           </div>
               <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span>
                 {{ group.name }}</h2>
               <service v-for="item in group.items" v-bind:item="item"
-                v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))">
+                v-if="!filter || (item && matchesFilter(item))">
               </service>
             </div>
           </div>