diff options
-rw-r--r-- | app.css | 21 | ||||
-rw-r--r-- | app.js | 29 | ||||
-rw-r--r-- | app.scss | 31 | ||||
-rw-r--r-- | index.html | 59 |
4 files changed, 100 insertions, 40 deletions
@@ -11,7 +11,7 @@ body { | |||
11 | font-size: 2rem; } | 11 | font-size: 2rem; } |
12 | body h2 { | 12 | body h2 { |
13 | font-size: 1.7rem; | 13 | font-size: 1.7rem; |
14 | margin-top: 3rem; | 14 | margin-top: 2rem; |
15 | margin-bottom: 1rem; } | 15 | margin-bottom: 1rem; } |
16 | body h2 .fas, body h2 .fab, body h2 .far { | 16 | body h2 .fas, body h2 .fab, body h2 .far { |
17 | margin-right: 10px; } | 17 | margin-right: 10px; } |
@@ -92,6 +92,8 @@ body { | |||
92 | border: none; | 92 | border: none; |
93 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | 93 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); |
94 | transition: cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; } | 94 | transition: cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; } |
95 | body .card a { | ||
96 | outline: none; } | ||
95 | body .card:hover { | 97 | body .card:hover { |
96 | background-color: #FFFFFF; | 98 | background-color: #FFFFFF; |
97 | transform: translate(0, -3px); } | 99 | transform: translate(0, -3px); } |
@@ -102,17 +104,26 @@ body { | |||
102 | body .card-content { | 104 | body .card-content { |
103 | height: 85px; | 105 | height: 85px; |
104 | padding: 1.3rem; } | 106 | padding: 1.3rem; } |
107 | body .layout-vertical .card { | ||
108 | border-radius: 0; } | ||
109 | body .layout-vertical .column div:first-of-type .card { | ||
110 | border-radius: 5px 5px 0 0; } | ||
111 | body .layout-vertical .column div:last-child .card { | ||
112 | border-radius: 0 0 5px 5px; } | ||
105 | body .footer { | 113 | body .footer { |
106 | position: fixed; | 114 | position: fixed; |
107 | left: 0; | 115 | left: 0; |
108 | right: 0; | 116 | right: 0; |
109 | bottom: 0; | 117 | bottom: 0; |
110 | padding: 1rem 0.5rem; | 118 | padding: 0.5rem; |
111 | text-align: left; | 119 | text-align: left; |
112 | background-color: #fafafa; | 120 | background-color: #fafafa; |
113 | border-top: 1px solid #F5F5F5; } | 121 | border-top: 1px solid #F5F5F5; |
122 | color: #676767; | ||
123 | font-size: 0.85rem; } | ||
114 | body .search-bar { | 124 | body .search-bar { |
115 | position: relative; } | 125 | position: relative; |
126 | display: inline-block; } | ||
116 | body .search-bar #search { | 127 | body .search-bar #search { |
117 | border: none; | 128 | border: none; |
118 | background-color: #5f98f6; | 129 | background-color: #5f98f6; |
@@ -137,6 +148,8 @@ body { | |||
137 | height: 20px; } | 148 | height: 20px; } |
138 | body .search-bar:focus-within .search-label::before { | 149 | body .search-bar:focus-within .search-label::before { |
139 | color: #4a4a4a; } | 150 | color: #4a4a4a; } |
151 | body .icon-button { | ||
152 | display: inline-block; } | ||
140 | body .offline-message { | 153 | body .offline-message { |
141 | text-align: center; | 154 | text-align: center; |
142 | margin: 35px 0; } | 155 | margin: 35px 0; } |
@@ -4,6 +4,7 @@ const app = new Vue({ | |||
4 | config: null, | 4 | config: null, |
5 | offline: false, | 5 | offline: false, |
6 | filter: '', | 6 | filter: '', |
7 | vlayout: true | ||
7 | }, | 8 | }, |
8 | created: function () { | 9 | created: function () { |
9 | let that = this; | 10 | let that = this; |
@@ -46,6 +47,34 @@ const app = new Vue({ | |||
46 | } | 47 | } |
47 | }); | 48 | }); |
48 | 49 | ||
50 | Vue.component('service', { | ||
51 | props: ['item'], | ||
52 | template: `<div> | ||
53 | <div class="card"> | ||
54 | <a :href="item.url"> | ||
55 | <div class="card-content"> | ||
56 | <div class="media"> | ||
57 | <div v-if="item.logo" class="media-left"> | ||
58 | <figure class="image is-48x48"> | ||
59 | <img :src="item.logo" /> | ||
60 | </figure> | ||
61 | </div> | ||
62 | <div v-if="item.icon" class="media-left"> | ||
63 | <figure class="image is-48x48"> | ||
64 | <i style="font-size: 35px" :class="item.icon"></i> | ||
65 | </figure> | ||
66 | </div> | ||
67 | <div class="media-content"> | ||
68 | <p class="title is-4">{{ item.name }}</p> | ||
69 | <p class="subtitle is-6">{{ item.subtitle }}</p> | ||
70 | </div> | ||
71 | </div> | ||
72 | <strong class="tag" v-if="item.tag">#{{ item.tag }}</strong> | ||
73 | </div> | ||
74 | </a> | ||
75 | </div></div>` | ||
76 | }); | ||
77 | |||
49 | if ('serviceWorker' in navigator) { | 78 | if ('serviceWorker' in navigator) { |
50 | window.addEventListener('load', function () { | 79 | window.addEventListener('load', function () { |
51 | navigator.serviceWorker.register('/worker.js'); | 80 | navigator.serviceWorker.register('/worker.js'); |
@@ -18,7 +18,7 @@ body { | |||
18 | 18 | ||
19 | h2 { | 19 | h2 { |
20 | font-size: 1.7rem; | 20 | font-size: 1.7rem; |
21 | margin-top: 3rem; | 21 | margin-top: 2rem; |
22 | margin-bottom: 1rem; | 22 | margin-bottom: 1rem; |
23 | 23 | ||
24 | .fas, .fab, .far { | 24 | .fas, .fab, .far { |
@@ -147,7 +147,11 @@ body { | |||
147 | border-radius: 5px; | 147 | border-radius: 5px; |
148 | border: none; | 148 | border: none; |
149 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | 149 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); |
150 | transition: cubic-bezier(0.165, 0.84, 0.44, 1) 300ms | 150 | transition: cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; |
151 | |||
152 | a { | ||
153 | outline: none; | ||
154 | } | ||
151 | } | 155 | } |
152 | 156 | ||
153 | .card:hover { | 157 | .card:hover { |
@@ -166,19 +170,36 @@ body { | |||
166 | padding: 1.3rem; | 170 | padding: 1.3rem; |
167 | } | 171 | } |
168 | 172 | ||
173 | .layout-vertical { | ||
174 | .card { | ||
175 | border-radius: 0; | ||
176 | } | ||
177 | |||
178 | .column div:first-of-type .card { | ||
179 | border-radius: 5px 5px 0 0; | ||
180 | } | ||
181 | |||
182 | .column div:last-child .card { | ||
183 | border-radius: 0 0 5px 5px; | ||
184 | } | ||
185 | } | ||
186 | |||
169 | .footer { | 187 | .footer { |
170 | position: fixed; | 188 | position: fixed; |
171 | left: 0; | 189 | left: 0; |
172 | right: 0; | 190 | right: 0; |
173 | bottom: 0; | 191 | bottom: 0; |
174 | padding: 1rem 0.5rem; | 192 | padding: 0.5rem; |
175 | text-align: left; | 193 | text-align: left; |
176 | background-color: #fafafa; | 194 | background-color: #fafafa; |
177 | border-top: 1px solid #F5F5F5; | 195 | border-top: 1px solid #F5F5F5; |
196 | color: #676767; | ||
197 | font-size: 0.85rem; | ||
178 | } | 198 | } |
179 | 199 | ||
180 | .search-bar { | 200 | .search-bar { |
181 | position: relative; | 201 | position: relative; |
202 | display: inline-block; | ||
182 | #search { | 203 | #search { |
183 | border: none; | 204 | border: none; |
184 | background-color: lighten( $secondary-color, 6% ); | 205 | background-color: lighten( $secondary-color, 6% ); |
@@ -213,6 +234,10 @@ body { | |||
213 | } | 234 | } |
214 | } | 235 | } |
215 | 236 | ||
237 | .icon-button { | ||
238 | display: inline-block; | ||
239 | } | ||
240 | |||
216 | .offline-message { | 241 | .offline-message { |
217 | text-align: center; | 242 | text-align: center; |
218 | margin: 35px 0; | 243 | margin: 35px 0; |
@@ -7,8 +7,8 @@ | |||
7 | <meta name="robots" content="noindex"> | 7 | <meta name="robots" content="noindex"> |
8 | <link rel="icon" type="image/png" href="assets/favicon.png"> | 8 | <link rel="icon" type="image/png" href="assets/favicon.png"> |
9 | <title>Homer</title> | 9 | <title>Homer</title> |
10 | <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.5.0/css/all.css" | 10 | <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.2/css/all.css" |
11 | integrity="sha384-B4dIYHKNBt8Bc12p+WXckhzcICo0wtJAoU8YZTY5qE0Id1GSseTk6S+L3BlXeVIU" crossorigin="anonymous"> | 11 | integrity="sha384-fnmOCqbTlWIlj8LyTjo7mOUStjsKC4pOpQbqyi7RrhN7udi9RwhKkMHpvLbHG9Sr" crossorigin="anonymous"> |
12 | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css"> | 12 | <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.2/css/bulma.css"> |
13 | <link href="https://fonts.googleapis.com/css?family=Lato|Raleway" rel="stylesheet"> | 13 | <link href="https://fonts.googleapis.com/css?family=Lato|Raleway" rel="stylesheet"> |
14 | <link rel="stylesheet" href="app.css"> | 14 | <link rel="stylesheet" href="app.css"> |
@@ -40,6 +40,8 @@ | |||
40 | </a> | 40 | </a> |
41 | </div> | 41 | </div> |
42 | <div class="end"> | 42 | <div class="end"> |
43 | <a v-on:click="vlayout = !vlayout" class="icon-button navbar-item"><i | ||
44 | :class="['fas', vlayout ? 'fa-list' : 'fa-columns']"></i></a> | ||
43 | <div class="search-bar"> | 45 | <div class="search-bar"> |
44 | <label for="search" class="search-label"></label> | 46 | <label for="search" class="search-label"></label> |
45 | <input type="text" id="search" v-model="filter" /> | 47 | <input type="text" id="search" v-model="filter" /> |
@@ -70,39 +72,30 @@ | |||
70 | 72 | ||
71 | <h2 v-if="filter"><i class="fas fa-search"></i> Search</h2> | 73 | <h2 v-if="filter"><i class="fas fa-search"></i> Search</h2> |
72 | 74 | ||
73 | <div v-for="(group, index) in config.services"> | 75 | <!-- Horizontal layout --> |
74 | <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span> | 76 | <div v-if="!vlayout || filter" class="columns is-multiline"> |
75 | {{ group.name }}</h2> | 77 | <template v-for="(group, index) in config.services"> |
76 | <div class="columns is-multiline"> | 78 | <h2 v-if="!filter && group.name" class="column is-full"><i v-if="group.icon" :class="group.icon"></i><span |
77 | <div v-for="item in group.items" | 79 | v-else>#</span> |
78 | v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))" | 80 | {{ group.name }}</h2> |
79 | class="column is-one-third-widescreen"> | 81 | <service v-for="item in group.items" v-bind:item="item" class="column is-one-third-widescreen" |
80 | <div v-if='item' class="card"> | 82 | v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))"> |
81 | <a :href="item.url"> | 83 | </service> |
82 | <div class="card-content"> | 84 | </template> |
83 | <div class="media"> | 85 | </div> |
84 | <div v-if="item.logo" class="media-left"> | 86 | |
85 | <figure class="image is-48x48"> | 87 | <!-- Vertical layout --> |
86 | <img :src="item.logo" /> | 88 | <div v-if="!filter && vlayout" class="columns is-multiline layout-vertical"> |
87 | </figure> | 89 | <div class="column is-one-third-widescreen" v-for="(group, index) in config.services"> |
88 | </div> | 90 | <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span> |
89 | <div v-if="item.icon" class="media-left"> | 91 | {{ group.name }}</h2> |
90 | <figure class="image is-48x48"> | 92 | <service v-for="item in group.items" v-bind:item="item" |
91 | <i style="font-size: 35px" :class="item.icon"></i> | 93 | v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))"> |
92 | </figure> | 94 | </service> |
93 | </div> | ||
94 | <div class="media-content"> | ||
95 | <p class="title is-4">{{ item.name }}</p> | ||
96 | <p class="subtitle is-6">{{ item.subtitle }}</p> | ||
97 | </div> | ||
98 | </div> | ||
99 | <strong class="tag" v-if="item.tag">#{{ item.tag }}</strong> | ||
100 | </div> | ||
101 | </a> | ||
102 | </div> | ||
103 | </div> | ||
104 | </div> | 95 | </div> |
105 | </div> | 96 | </div> |
97 | |||
98 | |||
106 | </div> | 99 | </div> |
107 | </div> | 100 | </div> |
108 | </section> | 101 | </section> |