body {
font-family: 'Raleway', sans-serif;
background-color: #F5F5F5;
- height: 100%; }
+ min-height: 100%; }
body h1, body h2, body h3, body h4, body h5, body h6 {
font-family: 'Lato', sans-serif; }
body h1 {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis; }
- body #main-section .column {
+ body #main-section .container {
padding: 1.2rem .75rem; }
body #main-section .message {
margin-top: 45px;
background-color: #4285f4;
position: absolute;
top: 1rem;
- right: -0.3rem;
+ right: -0.2rem;
width: 3px;
overflow: hidden;
transition: all 0.2s ease-out;
height: 20px; }
body .search-bar:focus-within .search-label::before {
color: #4a4a4a; }
+ body .offline-message {
+ text-align: center;
+ margin: 35px 0; }
+ body .offline-message i {
+ font-size: 2rem; }
+ body .offline-message i.fa-redo-alt {
+ font-size: 1.3rem;
+ line-height: 1rem;
+ vertical-align: middle;
+ cursor: pointer;
+ color: #3273dc; }
-var app = new Vue({
+const app = new Vue({
el: '#app',
data: {
config: null,
- filter: ''
+ offline: false,
+ filter: '',
},
- beforeCreate() {
+ created: function () {
let that = this;
- return getConfig().then(function (config) {
- const size = 3;
- config.services.forEach(function (service) {
- service.rows = [];
- items = service.items;
- while (items.length) {
- service.rows.push(items.splice(0, size));
- }
-
- if (service.rows.length) {
- let last = service.rows.length - 1;
- service.rows[last] = service.rows[last].concat(Array(size - service.rows[last].length));
- }
- });
+ this.checkOffline();
+ that.getConfig().then(function (config) {
that.config = config;
}).catch(function () {
- console.error('Fail to get config');
+ that.offline = true;
});
+
+ 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);
+ });
+ });
+ },
}
});
-
-function getConfig() {
- return fetch('config.yml').then(function (response) {
- if (response.status !== 200) {
- return;
- }
-
- return response.text().then(function (body) {
- return jsyaml.load(body);
- });
+if ('serviceWorker' in navigator) {
+ window.addEventListener('load', function () {
+ navigator.serviceWorker.register('/worker.js');
});
}
<meta name="robots" content="noindex">
<link rel="icon" type="image/png" href="assets/favicon.png">
<title>Homer</title>
- <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU"
- crossorigin="anonymous">
+ <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css"
+ integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css">
<link href="https://fonts.googleapis.com/css?family=Lato|Raleway" rel="stylesheet">
<link rel="stylesheet" href="app.css">
<div id="app" v-if="config">
<div id="bighead">
<section class="first-line">
- <div class="container">
+ <div v-cloak class="container">
<div class="logo">
<img v-if="config.logo" :src="config.logo" />
<i v-if="config.icon" :class="config.icon"></i>
</div>
<div class="dashboard-title">
- <span v-cloak class="headline">{{ config.subtitle }}</span>
- <h1 v-cloak>{{ config.title }}</h1>
+ <span class="headline">{{ config.subtitle }}</span>
+ <h1>{{ config.title }}</h1>
</div>
</div>
</section>
- <div v-if="config.links" class="container-fluid">
+ <div v-cloak v-if="config.links" class="container-fluid">
<nav class="navbar" role="navigation" aria-label="main navigation">
<div class="container">
<div class="navbar-menu">
</div>
<section id="main-section" class="section">
- <div class="container">
- <!-- Optional messages -->
- <article v-cloak v-if="config && config.message" class="message" :class="config.message.style">
- <div v-if="config.message.title" class="message-header">
- <p>{{ config.message.title }}</p>
- </div>
- <div v-if="config.message.content" class="message-body">
- {{ config.message.content }}
- </div>
- </article>
+ <div v-cloak class="container">
+ <div v-if="offline" class="offline-message">
+ <i class="far fa-dizzy"></i>
+ <h1>You're offline bro. <i class="fas fa-redo-alt" v-on:click="checkOffline()"></i></h1>
+ </div>
+ <div v-else>
+ <!-- Optional messages -->
+ <article v-if="config && config.message" class="message" :class="config.message.style">
+ <div v-if="config.message.title" class="message-header">
+ <p>{{ config.message.title }}</p>
+ </div>
+ <div v-if="config.message.content" class="message-body">
+ {{ config.message.content }}
+ </div>
+ </article>
- <h2 v-cloak v-if="filter"><i class="fas fa-search"></i> Search</h2>
+ <h2 v-if="filter"><i class="fas fa-search"></i> Search</h2>
- <div v-for="(group, index) in config.services">
- <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span>
- {{ group.name }}</h2>
- <div v-for="items in group.rows">
- <div class="columns">
- <div v-for="item in items" v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))"
- class="column">
- <div>
- <div v-if='item' class="card">
- <a :href="item.url">
- <div class="card-content">
- <div class="media">
- <div v-if="item.logo" class="media-left">
- <figure class="image is-48x48">
- <img :src="item.logo" />
- </figure>
- </div>
- <div v-if="item.icon" class="media-left">
- <figure class="image is-48x48">
- <i style="font-size: 35px" :class="item.icon"></i>
- </figure>
- </div>
- <div class="media-content">
- <p class="title is-4">{{ item.name }}</p>
- <p class="subtitle is-6">{{ item.subtitle }}</p>
- </div>
+ <div v-for="(group, index) in config.services">
+ <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span>
+ {{ group.name }}</h2>
+ <div class="columns is-multiline">
+ <div v-for="item in group.items"
+ v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))"
+ class="column is-one-third-widescreen">
+ <div v-if='item' class="card">
+ <a :href="item.url">
+ <div class="card-content">
+ <div class="media">
+ <div v-if="item.logo" class="media-left">
+ <figure class="image is-48x48">
+ <img :src="item.logo" />
+ </figure>
+ </div>
+ <div v-if="item.icon" class="media-left">
+ <figure class="image is-48x48">
+ <i style="font-size: 35px" :class="item.icon"></i>
+ </figure>
+ </div>
+ <div class="media-content">
+ <p class="title is-4">{{ item.name }}</p>
+ <p class="subtitle is-6">{{ item.subtitle }}</p>
</div>
- <strong v-if="item.tag" class="tag">#{{ item.tag }}</strong>
</div>
- </a>
- </div>
+ <strong class="tag" v-if="item.tag">#{{ item.tag }}</strong>
+ </div>
+ </a>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<div class="content has-text-centered">
- <p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a href="https://vuejs.org/">vuejs</a>
- & <a href="#">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>
+ <p>Created with <span class="has-text-danger">❤️</span> with <a href="https://bulma.io/">bulma</a>, <a
+ href="https://vuejs.org/">vuejs</a>
+ & <a href="#">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i
+ class="fab fa-github-alt"></i></a></p>
</div>
</div>
</footer>
- <script src="https://unpkg.com/vue"></script>
+ <script src="https://cdn.jsdelivr.net/npm/vue@2.6.2/dist/vue.min.js"></script>
<script src="vendors/js-yaml.min.js"></script>
<script src="app.js"></script>
</body>