X-Git-Url: https://git.immae.eu/?a=blobdiff_plain;f=app.js;h=e79611069f9d779d4a09e969157ec805b0c24628;hb=abe6df52b500199ff4b379e0370427267a16992b;hp=26979755f3acb2bb43eac226bf92207f271c9181;hpb=09763dbf6a6f24263cdff535a3aca64da35a0abb;p=github%2Fbastienwirtz%2Fhomer.git diff --git a/app.js b/app.js index 2697975..e796110 100644 --- a/app.js +++ b/app.js @@ -1,58 +1,174 @@ -var app = new Vue({ +const app = new Vue({ el: '#app', data: { config: null, - filter: '' + offline: false, + filter: '', + vlayout: true, + isDark: null, + showMenu: false }, - beforeCreate () { - var that = this; - return getConfig().then(function (config) { - // Splice services list into groups of 3 for flex column display - var size = 3; - config.services.forEach(function(service) { - service.rows = []; - items = service.items; - while (items.length) { - service.rows.push(items.splice(0, size)); + created: async function () { + let that = this; + + this.isDark = 'overrideDark' in localStorage ? + JSON.parse(localStorage.overrideDark) : matchMedia("(prefers-color-scheme: dark)").matches; + + if ('vlayout' in localStorage) { + this.vlayout = JSON.parse(localStorage.vlayout) + } + + this.checkOffline(); + try { + this.config = await this.getConfig(); + document.title = this.config.title + ' | Homer'; + } catch (error) { + this.offline = true; + } + + // Look for a new message if an endpoint is provided. + if (this.config.message && this.config.message.url) { + this.getMessage(this.config.message.url).then(function(message){ + // keep the original config value if no value is provided by the endpoint + for (const prop of ['title','style','content']) { + if (prop in message && message[prop] !== null) { + that.config.message[prop] = message[prop]; + } } + }); + } - if (service.rows.length) { - var last = service.rows.length-1; - service.rows[last] = service.rows[last].concat(Array(size - service.rows[last].length)); + document.addEventListener('visibilitychange', function () { + if (document.visibilityState == "visible") { + that.checkOffline(); + } + }, false); + }, + methods: { + checkOffline: function () { + let that = this; + return fetch(window.location.href + "?alive", { + method: 'HEAD', + cache: 'no-store' + }).then(function () { + that.offline = false; + }).catch(function () { + that.offline = true; + }); + }, + getConfig: function (event) { + return fetch('config.yml').then(function (response) { + if (response.status != 200) { + return + } + return response.text().then(function (body) { + return jsyaml.load(body); + }); + }); + }, + getMessage: function (url) { + return fetch(url).then(function (response) { + if (response.status != 200) { + return; } + return response.json(); }); - that.config = config; - }); + }, + toggleTheme: function() { + this.isDark = !this.isDark; + localStorage.overrideDark = this.isDark; + }, + toggleLayout: function() { + this.vlayout = !this.vlayout; + localStorage.vlayout = this.vlayout; + }, + 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() { + function isSmallScreen() { + return window.matchMedia('screen and (max-width: 1023px)').matches; + } + this._keyListener = function(e) { + if (e.key === '/') { + if (isSmallScreen()) { + this.showMenu = true; + } + Vue.nextTick(() => { + this.$refs.search.focus(); + }); + + e.preventDefault(); + } + if (e.key === 'Escape') { + this.filter = ''; + this.$refs.search.blur(); + if (isSmallScreen()) { + this.showMenu = false; + } + } + } + + document.addEventListener('keydown', this._keyListener.bind(this)); + }, + beforeDestroy() { + document.removeEventListener('keydown', this._keyListener); } }); +Vue.component('service', { + props: ['item'], + template: `
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+

{{ item.name }}

+

{{ item.subtitle }}

+
+
+
+ #{{ item.tag }} +
+
+
+
` +}); -function getConfig() { - return new Promise(function (resolve, reject) { - var xhr = new XMLHttpRequest(); - xhr.open('GET', 'config.yml'); - xhr.onload = function () { - if (this.status >= 200 && this.status < 300) { - try { - var data = jsyaml.load(xhr.response); - resolve(data); - } catch (e) { - console.error('fail to parse config file'); - reject(); - } - } else { - reject({ - status: this.status, - statusText: xhr.statusText - }); - } - }; - xhr.onerror = function () { - reject({ - status: this.status, - statusText: xhr.statusText - }); - }; - xhr.send(); +if ('serviceWorker' in navigator) { + window.addEventListener('load', function () { + navigator.serviceWorker.register('worker.js'); }); -} \ No newline at end of file +}