diff options
-rw-r--r-- | .github/PULL_REQUEST_TEMPLATE.md | 4 | ||||
-rw-r--r-- | README.md | 9 | ||||
-rw-r--r-- | app.css | 644 | ||||
-rw-r--r-- | app.js | 49 | ||||
-rw-r--r-- | app.scss | 24 | ||||
-rw-r--r-- | index.html | 8 |
6 files changed, 373 insertions, 365 deletions
diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index e0bcfe2..d32ca78 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md | |||
@@ -6,15 +6,13 @@ Fixes # (issue) | |||
6 | 6 | ||
7 | ## Type of change | 7 | ## Type of change |
8 | 8 | ||
9 | Please delete options that are not relevant. | ||
10 | |||
11 | - [ ] Bug fix (non-breaking change which fixes an issue) | 9 | - [ ] Bug fix (non-breaking change which fixes an issue) |
12 | - [ ] New feature (non-breaking change which adds functionality) | 10 | - [ ] New feature (non-breaking change which adds functionality) |
13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) | 11 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) |
14 | 12 | ||
15 | ## Checklist: | 13 | ## Checklist: |
16 | 14 | ||
17 | - [ ] I read & comply with the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/master/.github/CONTRIBUTING.md) | 15 | - [ ] I read & comply with the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/master/CONTRIBUTING.md) |
18 | - [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers. | 16 | - [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers. |
19 | - [ ] I have made corresponding changes the documentation (README.md). | 17 | - [ ] I have made corresponding changes the documentation (README.md). |
20 | - [ ] I've check my modifications for any breaking change, especially in the `config.yml` file | 18 | - [ ] I've check my modifications for any breaking change, especially in the `config.yml` file |
@@ -1,7 +1,14 @@ | |||
1 | # Homer | 1 | # Homer |
2 | A dead simple static **HOM**epage for your serv**ER** to keep your services on hand, from a simple `yaml` configuration file. | 2 | A dead simple static **HOM**epage for your serv**ER** to keep your services on hand, from a simple `yaml` configuration file. |
3 | 3 | ||
4 | **Check out the live demo [here](https://homer-demo.netlify.com/).** | 4 | **Check out the live demo [here](https://homer-demo.netlify.app).** |
5 | |||
6 | It supports keyboard shortcuts: | ||
7 | |||
8 | * `/` Start searching. | ||
9 | * `Escape` Stop searching. | ||
10 | * `Enter` Open the first matching result (respects the bookmark's `_target` property). | ||
11 | * `Alt`/`Option` + `Enter` Open the first matching result in a new tab. | ||
5 | 12 | ||
6 | 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, ...) | 13 | 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, ...) |
7 | 14 | ||
@@ -1,372 +1,308 @@ | |||
1 | @charset "UTF-8"; | ||
2 | /* raleway-regular - latin */ | 1 | /* raleway-regular - latin */ |
3 | @font-face { | 2 | @font-face { |
4 | font-family: "Raleway"; | 3 | font-family: 'Raleway'; |
5 | font-style: normal; | 4 | font-style: normal; |
6 | font-weight: 400; | 5 | font-weight: 400; |
7 | font-display: swap; | 6 | font-display: swap; |
8 | src: local("Raleway"), local("Raleway-Regular"), url("./webfonts/raleway/raleway-v14-latin-regular.woff2") format("woff2"), url("./webfonts/raleway/raleway-v14-latin-regular.woff") format("woff"); | 7 | src: local("Raleway"), local("Raleway-Regular"), url("./webfonts/raleway/raleway-v14-latin-regular.woff2") format("woff2"), url("./webfonts/raleway/raleway-v14-latin-regular.woff") format("woff"); |
9 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ | 8 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } |
10 | } | 9 | |
11 | /* lato-regular - latin */ | 10 | /* lato-regular - latin */ |
12 | @font-face { | 11 | @font-face { |
13 | font-family: "Lato"; | 12 | font-family: 'Lato'; |
14 | font-style: normal; | 13 | font-style: normal; |
15 | font-weight: 400; | 14 | font-weight: 400; |
16 | font-display: swap; | 15 | font-display: swap; |
17 | src: local("Lato Regular"), local("Lato-Regular"), url("./webfonts/lato/lato-v16-latin-regular.woff2") format("woff2"), url("./webfonts/lato/lato-v16-latin-regular.woff") format("woff"); | 16 | src: local("Lato Regular"), local("Lato-Regular"), url("./webfonts/lato/lato-v16-latin-regular.woff2") format("woff2"), url("./webfonts/lato/lato-v16-latin-regular.woff") format("woff"); |
18 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ | 17 | /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */ } |
19 | } | 18 | |
20 | html { | 19 | html { |
21 | height: 100%; | 20 | height: 100%; } |
22 | } | ||
23 | 21 | ||
24 | body { | 22 | body { |
25 | font-family: "Raleway", sans-serif; | 23 | font-family: 'Raleway', sans-serif; |
26 | height: 100%; | 24 | height: 100%; } |
27 | } | ||
28 | body #app { | ||
29 | min-height: 100%; | ||
30 | transition: background-color cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; | ||
31 | background-color: #f5f5f5; | ||
32 | color: #363636; | ||
33 | } | ||
34 | body #app a:hover { | ||
35 | color: #363636; | ||
36 | } | ||
37 | body #app .title { | ||
38 | color: #303030; | ||
39 | } | ||
40 | body #app .subtitle { | ||
41 | color: #424242; | ||
42 | } | ||
43 | body #app .card { | ||
44 | background-color: #ffffff; | ||
45 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | ||
46 | } | ||
47 | body #app .card:hover { | ||
48 | background-color: #ffffff; | ||
49 | } | ||
50 | body #app .footer { | ||
51 | background-color: #ffffff; | ||
52 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | ||
53 | } | ||
54 | @media (prefers-color-scheme: light), (prefers-color-scheme: no-preference) { | ||
55 | body #app { | 25 | body #app { |
26 | min-height: 100%; | ||
27 | transition: background-color cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; | ||
56 | background-color: #f5f5f5; | 28 | background-color: #f5f5f5; |
57 | color: #363636; | 29 | color: #363636; } |
58 | } | 30 | body #app a:hover { |
59 | body #app a:hover { | 31 | color: #363636; } |
60 | color: #363636; | 32 | body #app .title { |
61 | } | 33 | color: #303030; } |
62 | body #app .title { | 34 | body #app .subtitle { |
63 | color: #303030; | 35 | color: #424242; } |
64 | } | 36 | body #app .card { |
65 | body #app .subtitle { | 37 | background-color: #ffffff; |
66 | color: #424242; | 38 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } |
67 | } | 39 | body #app .card:hover { |
68 | body #app .card { | 40 | background-color: #ffffff; } |
69 | background-color: #ffffff; | 41 | body #app .message { |
42 | background-color: #ffffff; } | ||
43 | body #app .message .message-body { | ||
44 | color: #363636; } | ||
45 | body #app .footer { | ||
46 | background-color: #ffffff; | ||
47 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } | ||
48 | @media (prefers-color-scheme: light), (prefers-color-scheme: no-preference) { | ||
49 | body #app { | ||
50 | background-color: #f5f5f5; | ||
51 | color: #363636; } | ||
52 | body #app a:hover { | ||
53 | color: #363636; } | ||
54 | body #app .title { | ||
55 | color: #303030; } | ||
56 | body #app .subtitle { | ||
57 | color: #424242; } | ||
58 | body #app .card { | ||
59 | background-color: #ffffff; | ||
60 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } | ||
61 | body #app .card:hover { | ||
62 | background-color: #ffffff; } | ||
63 | body #app .message { | ||
64 | background-color: #ffffff; } | ||
65 | body #app .message .message-body { | ||
66 | color: #363636; } | ||
67 | body #app .footer { | ||
68 | background-color: #ffffff; | ||
69 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } } | ||
70 | @media (prefers-color-scheme: dark) { | ||
71 | body #app { | ||
72 | background-color: #131313; | ||
73 | color: #eaeaea; } | ||
74 | body #app a:hover { | ||
75 | color: #ffdd57; } | ||
76 | body #app .title { | ||
77 | color: #fafafa; } | ||
78 | body #app .subtitle { | ||
79 | color: #f5f5f5; } | ||
80 | body #app .card { | ||
81 | background-color: #2b2b2b; | ||
82 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); } | ||
83 | body #app .card:hover { | ||
84 | background-color: #2b2b2b; } | ||
85 | body #app .message { | ||
86 | background-color: #2b2b2b; } | ||
87 | body #app .message .message-body { | ||
88 | color: #eaeaea; } | ||
89 | body #app .footer { | ||
90 | background-color: #2b2b2b; | ||
91 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); } } | ||
92 | body #app.is-light { | ||
93 | background-color: #f5f5f5; | ||
94 | color: #363636; } | ||
95 | body #app.is-light a:hover { | ||
96 | color: #363636; } | ||
97 | body #app.is-light .title { | ||
98 | color: #303030; } | ||
99 | body #app.is-light .subtitle { | ||
100 | color: #424242; } | ||
101 | body #app.is-light .card { | ||
102 | background-color: #ffffff; | ||
103 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } | ||
104 | body #app.is-light .card:hover { | ||
105 | background-color: #ffffff; } | ||
106 | body #app.is-light .message { | ||
107 | background-color: #ffffff; } | ||
108 | body #app.is-light .message .message-body { | ||
109 | color: #363636; } | ||
110 | body #app.is-light .footer { | ||
111 | background-color: #ffffff; | ||
112 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } | ||
113 | body #app.is-dark { | ||
114 | background-color: #131313; | ||
115 | color: #eaeaea; } | ||
116 | body #app.is-dark a:hover { | ||
117 | color: #ffdd57; } | ||
118 | body #app.is-dark .title { | ||
119 | color: #fafafa; } | ||
120 | body #app.is-dark .subtitle { | ||
121 | color: #f5f5f5; } | ||
122 | body #app.is-dark .card { | ||
123 | background-color: #2b2b2b; | ||
124 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); } | ||
125 | body #app.is-dark .card:hover { | ||
126 | background-color: #2b2b2b; } | ||
127 | body #app.is-dark .message { | ||
128 | background-color: #2b2b2b; } | ||
129 | body #app.is-dark .message .message-body { | ||
130 | color: #eaeaea; } | ||
131 | body #app.is-dark .footer { | ||
132 | background-color: #2b2b2b; | ||
133 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); } | ||
134 | body h1, body h2, body h3, body h4, body h5, body h6 { | ||
135 | font-family: 'Lato', sans-serif; } | ||
136 | body h1 { | ||
137 | font-size: 2rem; } | ||
138 | body h2 { | ||
139 | font-size: 1.7rem; | ||
140 | margin-top: 2rem; | ||
141 | margin-bottom: 1rem; } | ||
142 | body h2 .fas, body h2 .fab, body h2 .far { | ||
143 | margin-right: 10px; } | ||
144 | body h2 span { | ||
145 | font-weight: bold; | ||
146 | color: #4285f4; } | ||
147 | body [v-cloak] { | ||
148 | display: none; } | ||
149 | body #bighead { | ||
150 | color: #ffffff; } | ||
151 | body #bighead .dashboard-title { | ||
152 | padding: 6px 0 0 80px; } | ||
153 | body #bighead .first-line { | ||
154 | height: 100px; | ||
155 | vertical-align: center; | ||
156 | background-color: #3367d6; } | ||
157 | body #bighead .first-line h1 { | ||
158 | margin-top: -12px; | ||
159 | font-size: 2rem; } | ||
160 | body #bighead .first-line .headline { | ||
161 | margin-top: 5px; | ||
162 | font-size: 0.9rem; } | ||
163 | body #bighead .first-line .container { | ||
164 | height: 80px; | ||
165 | padding: 10px 0; } | ||
166 | body #bighead .first-line .logo { | ||
167 | float: left; } | ||
168 | body #bighead .first-line .logo i { | ||
169 | vertical-align: top; | ||
170 | padding: 8px 15px; | ||
171 | font-size: 50px; } | ||
172 | body #bighead .first-line .logo img { | ||
173 | padding: 10px; | ||
174 | max-height: 70px; | ||
175 | max-width: 70px; } | ||
176 | body #bighead .navbar, body #bighead .navbar-menu { | ||
177 | background-color: #4285f4; } | ||
178 | body #bighead .navbar a, body #bighead .navbar-menu a { | ||
179 | color: #ffffff; } | ||
180 | body #bighead .navbar a:hover, body #bighead .navbar a:focus, body #bighead .navbar-menu a:hover, body #bighead .navbar-menu a:focus { | ||
181 | color: #ffffff; | ||
182 | background-color: #5a95f5; } | ||
183 | body #bighead .navbar-end { | ||
184 | text-align: right; } | ||
185 | body #main-section { | ||
186 | margin-bottom: 2rem; | ||
187 | padding: 0; } | ||
188 | body #main-section h2 { | ||
189 | border-bottom: 1px dashed #ccc; | ||
190 | padding-bottom: 10px; | ||
191 | white-space: nowrap; | ||
192 | overflow: hidden; | ||
193 | text-overflow: ellipsis; } | ||
194 | body #main-section .title { | ||
195 | font-size: 1.1em; | ||
196 | white-space: nowrap; | ||
197 | overflow: hidden; | ||
198 | text-overflow: ellipsis; } | ||
199 | body #main-section .subtitle { | ||
200 | font-size: .9em; | ||
201 | white-space: nowrap; | ||
202 | overflow: hidden; | ||
203 | text-overflow: ellipsis; } | ||
204 | body #main-section .container { | ||
205 | padding: 1.2rem .75rem; } | ||
206 | body #main-section .message { | ||
207 | margin-top: 45px; | ||
208 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); } | ||
209 | body #main-section .message .message-header { | ||
210 | font-weight: bold; } | ||
211 | body #main-section .message .message-body { | ||
212 | border: none; } | ||
213 | body .media-content { | ||
214 | overflow: hidden; | ||
215 | text-overflow: inherit; } | ||
216 | body .tag { | ||
217 | color: #4285f4; | ||
218 | background-color: #4285f4; | ||
219 | position: absolute; | ||
220 | top: 1rem; | ||
221 | right: -0.2rem; | ||
222 | width: 3px; | ||
223 | overflow: hidden; | ||
224 | transition: all 0.2s ease-out; | ||
225 | padding: 0; } | ||
226 | body .tag .tag-text { | ||
227 | display: none; } | ||
228 | body .card { | ||
229 | border-radius: 5px; | ||
230 | border: none; | ||
70 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | 231 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); |
71 | } | 232 | transition: cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; } |
72 | body #app .card:hover { | 233 | body .card a { |
73 | background-color: #ffffff; | 234 | outline: none; } |
74 | } | 235 | body .card:hover { |
75 | body #app .footer { | 236 | transform: translate(0, -3px); } |
76 | background-color: #ffffff; | 237 | body .card:hover .tag { |
77 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | 238 | width: auto; |
78 | } | 239 | color: #ffffff; |
79 | } | 240 | padding: 0 0.75em; } |
80 | @media (prefers-color-scheme: dark) { | 241 | body .card:hover .tag .tag-text { |
81 | body #app { | 242 | display: block; } |
82 | background-color: #131313; | 243 | body .card-content { |
83 | color: #eaeaea; | 244 | height: 85px; |
84 | } | 245 | padding: 1.3rem; } |
85 | body #app a:hover { | 246 | body .layout-vertical .card { |
86 | color: #ffdd57; | 247 | border-radius: 0; } |
87 | } | 248 | body .layout-vertical .column div:first-of-type .card { |
88 | body #app .title { | 249 | border-radius: 5px 5px 0 0; } |
89 | color: #fafafa; | 250 | body .layout-vertical .column div:last-child .card { |
90 | } | 251 | border-radius: 0 0 5px 5px; } |
91 | body #app .subtitle { | 252 | body .footer { |
92 | color: #f5f5f5; | 253 | position: fixed; |
93 | } | 254 | left: 0; |
94 | body #app .card { | 255 | right: 0; |
95 | background-color: #2b2b2b; | 256 | bottom: 0; |
96 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); | 257 | padding: 0.5rem; |
97 | } | 258 | text-align: left; |
98 | body #app .card:hover { | 259 | color: #676767; |
99 | background-color: #2b2b2b; | 260 | font-size: 0.85rem; |
100 | } | 261 | transition: background-color cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; } |
101 | body #app .footer { | 262 | body .no-footer #main-section { |
102 | background-color: #2b2b2b; | 263 | margin-bottom: 0; } |
103 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); | 264 | body .no-footer .footer { |
104 | } | 265 | display: none; } |
105 | } | 266 | body .search-bar { |
106 | body #app.is-light { | 267 | position: relative; |
107 | background-color: #f5f5f5; | 268 | display: inline-block; } |
108 | color: #363636; | 269 | body .search-bar #search { |
109 | } | 270 | border: none; |
110 | body #app.is-light a:hover { | 271 | background-color: #5f98f6; |
111 | color: #363636; | 272 | border-radius: 5px; |
112 | } | 273 | padding: 2px 12px 2px 30px; |
113 | body #app.is-light .title { | 274 | margin: 0 0 0 12px; |
114 | color: #303030; | 275 | transition: all 100ms linear; |
115 | } | 276 | color: #ffffff; |
116 | body #app.is-light .subtitle { | 277 | height: 30px; |
117 | color: #424242; | 278 | width: 100px; } |
118 | } | 279 | body .search-bar #search:focus { |
119 | body #app.is-light .card { | 280 | color: #000000; |
120 | background-color: #ffffff; | 281 | width: 250px; |
121 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | 282 | background-color: #ffffff; } |
122 | } | 283 | body .search-bar .search-label::before { |
123 | body #app.is-light .card:hover { | 284 | font-family: 'Font Awesome 5 Free'; |
124 | background-color: #ffffff; | 285 | position: absolute; |
125 | } | 286 | top: 4px; |
126 | body #app.is-light .footer { | 287 | left: 16px; |
127 | background-color: #ffffff; | 288 | content: "\f002"; |
128 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | 289 | font-weight: 900; |
129 | } | 290 | width: 20px; |
130 | body #app.is-dark { | 291 | height: 20px; |
131 | background-color: #131313; | 292 | color: #ffffff; } |
132 | color: #eaeaea; | 293 | body .search-bar:focus-within .search-label::before { |
133 | } | 294 | color: #4a4a4a; } |
134 | body #app.is-dark a:hover { | 295 | body .icon-button { |
135 | color: #ffdd57; | 296 | display: inline-block; |
136 | } | 297 | padding: 0 12px; } |
137 | body #app.is-dark .title { | 298 | body .offline-message { |
138 | color: #fafafa; | 299 | text-align: center; |
139 | } | 300 | margin: 35px 0; } |
140 | body #app.is-dark .subtitle { | 301 | body .offline-message i { |
141 | color: #f5f5f5; | 302 | font-size: 2rem; } |
142 | } | 303 | body .offline-message i.fa-redo-alt { |
143 | body #app.is-dark .card { | 304 | font-size: 1.3rem; |
144 | background-color: #2b2b2b; | 305 | line-height: 1rem; |
145 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); | 306 | vertical-align: middle; |
146 | } | 307 | cursor: pointer; |
147 | body #app.is-dark .card:hover { | 308 | color: #3273dc; } |
148 | background-color: #2b2b2b; | ||
149 | } | ||
150 | body #app.is-dark .footer { | ||
151 | background-color: #2b2b2b; | ||
152 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.4); | ||
153 | } | ||
154 | body h1, body h2, body h3, body h4, body h5, body h6 { | ||
155 | font-family: "Lato", sans-serif; | ||
156 | } | ||
157 | body h1 { | ||
158 | font-size: 2rem; | ||
159 | } | ||
160 | body h2 { | ||
161 | font-size: 1.7rem; | ||
162 | margin-top: 2rem; | ||
163 | margin-bottom: 1rem; | ||
164 | } | ||
165 | body h2 .fas, body h2 .fab, body h2 .far { | ||
166 | margin-right: 10px; | ||
167 | } | ||
168 | body h2 span { | ||
169 | font-weight: bold; | ||
170 | color: #4285f4; | ||
171 | } | ||
172 | body [v-cloak] { | ||
173 | display: none; | ||
174 | } | ||
175 | body #bighead { | ||
176 | color: #ffffff; | ||
177 | } | ||
178 | body #bighead .dashboard-title { | ||
179 | padding: 6px 0 0 80px; | ||
180 | } | ||
181 | body #bighead .first-line { | ||
182 | height: 100px; | ||
183 | vertical-align: center; | ||
184 | background-color: #3367d6; | ||
185 | } | ||
186 | body #bighead .first-line h1 { | ||
187 | margin-top: -12px; | ||
188 | font-size: 2rem; | ||
189 | } | ||
190 | body #bighead .first-line .headline { | ||
191 | margin-top: 5px; | ||
192 | font-size: 0.9rem; | ||
193 | } | ||
194 | body #bighead .first-line .container { | ||
195 | height: 80px; | ||
196 | padding: 10px 0; | ||
197 | } | ||
198 | body #bighead .first-line .logo { | ||
199 | float: left; | ||
200 | } | ||
201 | body #bighead .first-line .logo i { | ||
202 | vertical-align: top; | ||
203 | padding: 8px 15px; | ||
204 | font-size: 50px; | ||
205 | } | ||
206 | body #bighead .first-line .logo img { | ||
207 | padding: 10px; | ||
208 | max-height: 70px; | ||
209 | max-width: 70px; | ||
210 | } | ||
211 | body #bighead .navbar, body #bighead .navbar-menu { | ||
212 | background-color: #4285f4; | ||
213 | } | ||
214 | body #bighead .navbar a, body #bighead .navbar-menu a { | ||
215 | color: #ffffff; | ||
216 | } | ||
217 | body #bighead .navbar a:hover, body #bighead .navbar a:focus, body #bighead .navbar-menu a:hover, body #bighead .navbar-menu a:focus { | ||
218 | color: #ffffff; | ||
219 | background-color: #5a95f5; | ||
220 | } | ||
221 | body #bighead .navbar-end { | ||
222 | text-align: right; | ||
223 | } | ||
224 | body #main-section { | ||
225 | margin-bottom: 2rem; | ||
226 | padding: 0; | ||
227 | } | ||
228 | body #main-section h2 { | ||
229 | border-bottom: 1px dashed #ccc; | ||
230 | padding-bottom: 10px; | ||
231 | } | ||
232 | body #main-section .title { | ||
233 | font-size: 1.1em; | ||
234 | } | ||
235 | body #main-section .subtitle { | ||
236 | font-size: 0.9em; | ||
237 | white-space: nowrap; | ||
238 | overflow: hidden; | ||
239 | text-overflow: ellipsis; | ||
240 | } | ||
241 | body #main-section .container { | ||
242 | padding: 1.2rem 0.75rem; | ||
243 | } | ||
244 | body #main-section .message { | ||
245 | margin-top: 45px; | ||
246 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | ||
247 | } | ||
248 | body #main-section .message .message-header { | ||
249 | font-weight: bold; | ||
250 | } | ||
251 | body #main-section .message .message-body { | ||
252 | border: none; | ||
253 | } | ||
254 | body .media-content { | ||
255 | overflow: inherit; | ||
256 | } | ||
257 | body .tag { | ||
258 | color: #4285f4; | ||
259 | background-color: #4285f4; | ||
260 | position: absolute; | ||
261 | top: 1rem; | ||
262 | right: -0.2rem; | ||
263 | width: 3px; | ||
264 | overflow: hidden; | ||
265 | transition: all 0.2s ease-out; | ||
266 | padding: 0; | ||
267 | } | ||
268 | body .tag .tag-text { | ||
269 | display: none; | ||
270 | } | ||
271 | body .card { | ||
272 | border-radius: 5px; | ||
273 | border: none; | ||
274 | box-shadow: 0 2px 15px 0 rgba(0, 0, 0, 0.1); | ||
275 | transition: cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; | ||
276 | } | ||
277 | body .card a { | ||
278 | outline: none; | ||
279 | } | ||
280 | body .card:hover { | ||
281 | transform: translate(0, -3px); | ||
282 | } | ||
283 | body .card:hover .tag { | ||
284 | width: auto; | ||
285 | color: #ffffff; | ||
286 | padding: 0 0.75em; | ||
287 | } | ||
288 | body .card:hover .tag .tag-text { | ||
289 | display: block; | ||
290 | } | ||
291 | body .card-content { | ||
292 | height: 85px; | ||
293 | padding: 1.3rem; | ||
294 | } | ||
295 | body .layout-vertical .card { | ||
296 | border-radius: 0; | ||
297 | } | ||
298 | body .layout-vertical .column div:first-of-type .card { | ||
299 | border-radius: 5px 5px 0 0; | ||
300 | } | ||
301 | body .layout-vertical .column div:last-child .card { | ||
302 | border-radius: 0 0 5px 5px; | ||
303 | } | ||
304 | body .footer { | ||
305 | position: fixed; | ||
306 | left: 0; | ||
307 | right: 0; | ||
308 | bottom: 0; | ||
309 | padding: 0.5rem; | ||
310 | text-align: left; | ||
311 | color: #676767; | ||
312 | font-size: 0.85rem; | ||
313 | transition: background-color cubic-bezier(0.165, 0.84, 0.44, 1) 300ms; | ||
314 | } | ||
315 | body .no-footer #main-section { | ||
316 | margin-bottom: 0; | ||
317 | } | ||
318 | body .no-footer .footer { | ||
319 | display: none; | ||
320 | } | ||
321 | body .search-bar { | ||
322 | position: relative; | ||
323 | display: inline-block; | ||
324 | } | ||
325 | body .search-bar #search { | ||
326 | border: none; | ||
327 | background-color: #5f98f6; | ||
328 | border-radius: 5px; | ||
329 | padding: 2px 12px 2px 30px; | ||
330 | margin: 0 0 0 12px; | ||
331 | transition: all 100ms linear; | ||
332 | color: #ffffff; | ||
333 | height: 30px; | ||
334 | width: 100px; | ||
335 | } | ||
336 | body .search-bar #search:focus { | ||
337 | color: #000000; | ||
338 | width: 250px; | ||
339 | background-color: #ffffff; | ||
340 | } | ||
341 | body .search-bar .search-label::before { | ||
342 | font-family: "Font Awesome 5 Free"; | ||
343 | position: absolute; | ||
344 | top: 4px; | ||
345 | left: 16px; | ||
346 | content: ""; | ||
347 | font-weight: 900; | ||
348 | width: 20px; | ||
349 | height: 20px; | ||
350 | color: #ffffff; | ||
351 | } | ||
352 | body .search-bar:focus-within .search-label::before { | ||
353 | color: #4a4a4a; | ||
354 | } | ||
355 | body .icon-button { | ||
356 | display: inline-block; | ||
357 | padding: 0 12px; | ||
358 | } | ||
359 | body .offline-message { | ||
360 | text-align: center; | ||
361 | margin: 35px 0; | ||
362 | } | ||
363 | body .offline-message i { | ||
364 | font-size: 2rem; | ||
365 | } | ||
366 | body .offline-message i.fa-redo-alt { | ||
367 | font-size: 1.3rem; | ||
368 | line-height: 1rem; | ||
369 | vertical-align: middle; | ||
370 | cursor: pointer; | ||
371 | color: #3273dc; | ||
372 | } | ||
@@ -84,7 +84,56 @@ const app = new Vue({ | |||
84 | }, | 84 | }, |
85 | toggleMenu: function() { | 85 | toggleMenu: function() { |
86 | this.showMenu = !this.showMenu; | 86 | this.showMenu = !this.showMenu; |
87 | }, | ||
88 | matchesFilter: function(item) { | ||
89 | return (item.name.toLowerCase().includes(this.filter.toLowerCase()) | ||
90 | || (item.tag && item.tag.toLowerCase().includes(this.filter.toLowerCase()))) | ||
91 | }, | ||
92 | firstMatchingService: function() { | ||
93 | for (group of this.config.services) { | ||
94 | for (item of group.items) { | ||
95 | if (this.matchesFilter(item)) { | ||
96 | return item; | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | return null; | ||
101 | }, | ||
102 | navigateToFirstService: function(target) { | ||
103 | service = this.firstMatchingService(); | ||
104 | if (service) { | ||
105 | window.open(service.url, target || service.target || '_self'); | ||
106 | } | ||
107 | } | ||
108 | }, | ||
109 | mounted() { | ||
110 | function isSmallScreen() { | ||
111 | return window.matchMedia('screen and (max-width: 1023px)').matches; | ||
87 | } | 112 | } |
113 | this._keyListener = function(e) { | ||
114 | if (e.key === '/') { | ||
115 | if (isSmallScreen()) { | ||
116 | this.showMenu = true; | ||
117 | } | ||
118 | Vue.nextTick(() => { | ||
119 | this.$refs.search.focus(); | ||
120 | }); | ||
121 | |||
122 | e.preventDefault(); | ||
123 | } | ||
124 | if (e.key === 'Escape') { | ||
125 | this.filter = ''; | ||
126 | this.$refs.search.blur(); | ||
127 | if (isSmallScreen()) { | ||
128 | this.showMenu = false; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | |||
133 | document.addEventListener('keydown', this._keyListener.bind(this)); | ||
134 | }, | ||
135 | beforeDestroy() { | ||
136 | document.removeEventListener('keydown', this._keyListener); | ||
88 | } | 137 | } |
89 | }); | 138 | }); |
90 | 139 | ||
@@ -68,12 +68,27 @@ $theme-dark: ( | |||
68 | } | 68 | } |
69 | } | 69 | } |
70 | 70 | ||
71 | .message { | ||
72 | background-color: map-get($theme, "card-background"); | ||
73 | .message-body { | ||
74 | color: map-get($theme, "text"); | ||
75 | } | ||
76 | } | ||
77 | |||
71 | .footer { | 78 | .footer { |
72 | background-color: map-get($theme, "card-background"); | 79 | background-color: map-get($theme, "card-background"); |
73 | box-shadow: 0 2px 15px 0 map-get($theme, "card-shadow"); | 80 | box-shadow: 0 2px 15px 0 map-get($theme, "card-shadow"); |
74 | } | 81 | } |
75 | } | 82 | } |
76 | 83 | ||
84 | |||
85 | @mixin ellipsis() { | ||
86 | white-space: nowrap; | ||
87 | overflow: hidden; | ||
88 | text-overflow: ellipsis; | ||
89 | } | ||
90 | |||
91 | |||
77 | html { | 92 | html { |
78 | height: 100%; | 93 | height: 100%; |
79 | } | 94 | } |
@@ -198,17 +213,17 @@ body { | |||
198 | h2 { | 213 | h2 { |
199 | border-bottom: 1px dashed #ccc; | 214 | border-bottom: 1px dashed #ccc; |
200 | padding-bottom: 10px; | 215 | padding-bottom: 10px; |
216 | @include ellipsis(); | ||
201 | } | 217 | } |
202 | 218 | ||
203 | .title { | 219 | .title { |
204 | font-size: 1.1em; | 220 | font-size: 1.1em; |
221 | @include ellipsis(); | ||
205 | } | 222 | } |
206 | 223 | ||
207 | .subtitle { | 224 | .subtitle { |
208 | font-size: .9em; | 225 | font-size: .9em; |
209 | white-space: nowrap; | 226 | @include ellipsis(); |
210 | overflow: hidden; | ||
211 | text-overflow: ellipsis; | ||
212 | } | 227 | } |
213 | 228 | ||
214 | .container { | 229 | .container { |
@@ -230,7 +245,8 @@ body { | |||
230 | } | 245 | } |
231 | 246 | ||
232 | .media-content { | 247 | .media-content { |
233 | overflow: inherit; | 248 | overflow: hidden; |
249 | text-overflow: inherit; | ||
234 | } | 250 | } |
235 | 251 | ||
236 | .tag { | 252 | .tag { |
@@ -59,7 +59,9 @@ | |||
59 | :class="['fas', vlayout ? 'fa-list' : 'fa-columns']"></i></a> | 59 | :class="['fas', vlayout ? 'fa-list' : 'fa-columns']"></i></a> |
60 | <div class="search-bar"> | 60 | <div class="search-bar"> |
61 | <label for="search" class="search-label"></label> | 61 | <label for="search" class="search-label"></label> |
62 | <input type="text" id="search" v-model="filter" /> | 62 | <input type="text" id="search" ref="search" v-model="filter" |
63 | v-on:keyup.enter.exact="navigateToFirstService()" | ||
64 | v-on:keyup.alt.enter="navigateToFirstService('_blank')" /> | ||
63 | </div> | 65 | </div> |
64 | </div> | 66 | </div> |
65 | </div> | 67 | </div> |
@@ -95,7 +97,7 @@ | |||
95 | v-else>#</span> | 97 | v-else>#</span> |
96 | {{ group.name }}</h2> | 98 | {{ group.name }}</h2> |
97 | <service v-for="item in group.items" v-bind:item="item" class="column is-one-third-widescreen" | 99 | <service v-for="item in group.items" v-bind:item="item" class="column is-one-third-widescreen" |
98 | v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))"> | 100 | v-if="!filter || (item && matchesFilter(item))"> |
99 | </service> | 101 | </service> |
100 | </template> | 102 | </template> |
101 | </div> | 103 | </div> |
@@ -106,7 +108,7 @@ | |||
106 | <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span> | 108 | <h2 v-if="!filter && group.name"><i v-if="group.icon" :class="group.icon"></i><span v-else>#</span> |
107 | {{ group.name }}</h2> | 109 | {{ group.name }}</h2> |
108 | <service v-for="item in group.items" v-bind:item="item" | 110 | <service v-for="item in group.items" v-bind:item="item" |
109 | v-if="!filter || (item && (item.name.toLowerCase().includes(filter.toLowerCase()) || (item.tag && item.tag.toLowerCase().includes(filter.toLowerCase()))))"> | 111 | v-if="!filter || (item && matchesFilter(item))"> |
110 | </service> | 112 | </service> |
111 | </div> | 113 | </div> |
112 | </div> | 114 | </div> |