1
0
mirror of https://github.com/taigrr/homer synced 2025-01-18 04:53:12 -08:00

Compare commits

...

46 Commits

Author SHA1 Message Date
707fc0e7ba
Merge pull request #1 from bastienwirtz/main
FF to base
2020-11-05 02:49:58 -08:00
Bastien Wirtz
f8d0761d0c
Merge pull request #156 from my-flow/main
Use gender-neutral terminology
2020-11-02 20:48:33 -08:00
Florian J. Breunig
c701075dfa
Use gender-neutral terminology
Fix #155
2020-11-02 22:56:39 +01:00
6297655a34
style: satiate prettify 2020-10-28 22:04:47 -07:00
e207e58f6a
bug: adds is-clickable class to tags 2020-10-28 21:59:40 -07:00
af9037991b
chore: merges tagJump 2020-10-28 21:58:18 -07:00
0b8ea779f3
chore: fix merge conflict on Generic 2020-10-28 21:53:55 -07:00
c30533045a
feat: allows for searching by tag (note: requires #149) 2020-10-28 21:44:00 -07:00
Bastien Wirtz
ff0b5150f1
Merge pull request #151 from taigrr/spellcheck
chore: applies spell-check against entire repo (aspell)
2020-10-26 14:04:15 -07:00
Bastien Wirtz
5a85322c92
Merge pull request #146 from taigrr/fixDuplicateKeys
bug: Fix duplicate URL keys #145
2020-10-26 14:02:54 -07:00
553076011b
Merge branch 'info' into main 2020-10-26 05:01:20 -07:00
837446bc33
hotfix: extract inline style to satiate prettify 2020-10-26 04:59:52 -07:00
8ada6cca70
Merge branches 'fixDuplicateKeys', 'info' and 'scheme+layout' into main 2020-10-26 04:41:53 -07:00
e028716b18
docs: Adds documentation supporting info and infotarget options 2020-10-26 04:22:28 -07:00
7bab0dbdd9
feat: Adds feature to include info button to top right of cards 2020-10-26 04:18:37 -07:00
4a31e1e146
move tag to bottom of service to make room for info 2020-10-26 03:30:58 -07:00
1f12c43da8
Fix duplicate URL keys #145 2020-10-26 03:19:40 -07:00
188bcb4f21
chore: cleans up linter issues 2020-10-26 03:14:25 -07:00
6b17544aa0
docs: adds documentation on vlayout and theme_use_dark configuration options 2020-10-26 03:04:26 -07:00
ae8d62958b
feat: adds support for vlayout config option 2020-10-26 03:01:52 -07:00
729d1b5309
feat: adds support for theme_use_dark 2020-10-26 02:47:18 -07:00
1fc60ffe4f
chore: alphebetizes config states, refactors SettingToggle => LayoutToggle 2020-10-25 22:00:39 -07:00
2662b17049
chore: applies spell-check against entire repo (aspell) 2020-10-25 21:27:09 -07:00
Bastien Wirtz
d1b29caaa6
Update README.md 2020-10-23 22:57:35 -07:00
Bastien Wirtz
e75945851c
Fix screenshot url 2020-10-23 22:56:51 -07:00
Bastien Wirtz
13071ae3d1
Merge pull request #140 from Genymobile/dynamic-services
Custom service components
2020-10-23 18:29:14 -07:00
Bastien Wirtz
5b727eee02
Merge branch 'main' into dynamic-services 2020-10-23 18:29:06 -07:00
Bastien Wirtz
37dfd2a132
Merge pull request #139 from Genymobile/update-deps-and-fix-code-styles
Update deps & fix lint issues
2020-10-23 18:26:41 -07:00
Bastien Wirtz
9a14de007e Implement custom service component 2020-10-23 18:16:16 -07:00
Bastien Wirtz
ed8b17e0df Update deps & fix lint issues 2020-10-23 15:24:16 -07:00
Bastien Wirtz
c368290e32
Merge pull request #127 from NotWoods/pwa-icons
Reduce number of PWA icons, fix paths
2020-10-23 14:46:36 -07:00
Bastien Wirtz
00b069fc6f
Merge pull request #136 from gabe565/message-icon
Add support for a message icon
2020-10-23 14:32:49 -07:00
Tiger Oakes
40d3e8de76 Pull all values from manifest 2020-10-23 13:59:55 -07:00
Tiger Oakes
1017cc9864 Update vue config 2020-10-23 13:56:51 -07:00
Tiger Oakes
b04e718367 Update paths and style 2020-10-23 13:44:46 -07:00
Bastien Wirtz
ab8136bab7
Merge pull request #138 from taigrr/master
Fix config doc for sample application
2020-10-23 09:29:37 -07:00
488e4bbe7f
docs: Fixes spelling error in filename 2020-10-18 22:43:23 -07:00
62ec6fa099
docs: Updates code-fork to code-branch 2020-10-18 22:42:43 -07:00
Bastien Wirtz
67fd101a38 Dark theme improvements 2020-10-16 21:58:37 -07:00
Gabe Cook
0e045b4c55
Add support for a message icon 2020-10-15 13:22:51 -05:00
Bastien Wirtz
e608701404 Minor css adjustement.
Fixes #114 & #117
2020-10-14 22:41:55 -07:00
Bastien Wirtz
2b5f88db18
Merge pull request #135 from AlexGustafsson/master
Update @fortawesome/fontawesome-free to 5.15.1
2020-10-14 22:04:28 -07:00
Alex Gustafsson
b8c81389dc Update @fortawesome/fontawesome-free to 5.15.1 2020-10-12 16:46:23 +02:00
Bastien Wirtz
5b05842512
Merge pull request #129 from Crayon2000/fix-typo
Fix typos
2020-09-13 17:52:19 -07:00
Crayon
80f6a13140 Fix typos
Changed Optionnal to Optional
2020-09-11 17:14:57 -04:00
Tiger Oakes
f70fc3ecae Reduce number of PWA icons, fix paths 2020-09-02 22:02:14 -07:00
41 changed files with 1678 additions and 1274 deletions

View File

@ -12,7 +12,7 @@ Fixes # (issue)
## Checklist:
- [ ] I read & comply with the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/master/CONTRIBUTING.md)
- [ ] I've read & comply with the [contributing guidelines](https://github.com/bastienwirtz/homer/blob/master/CONTRIBUTING.md)
- [ ] I have tested my code for new features & regressions on both mobile & desktop devices, using the latest version of major browsers.
- [ ] I have made corresponding changes the documentation (README.md).
- [ ] I've check my modifications for any breaking change, especially in the `config.yml` file
- [ ] I've checked my modifications for any breaking changes, especially in the `config.yml` file

View File

@ -6,10 +6,10 @@ First off, thank you for considering contributing to Homer!
### Project philosophy
Homer is meant to be a light and very simple dashboard that keeps all your usefull utilities at hands. The few features implemented in Homer focus on
Homer is meant to be a light and very simple dashboard that keeps all your useful utilities at hands. The few features implemented in Homer focus on
UX and usability. If you are looking for a full featured dashboard, there is tons of great stuff out there like https://heimdall.site/, https://github.com/rmountjoy92/DashMachine or https://organizr.app/.
- Configuration is stored in a simple config file, avoiding the need for a backend/database while making possible to use versionning or [config template](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html).
- Configuration is stored in a simple config file, avoiding the need for a backend/database while making possible to use versioning or [config template](https://docs.ansible.com/ansible/latest/user_guide/playbooks_templating.html).
- Only modern browsers are supported, feel free to use any JS features without any polyfill as soon as the latest version of the major browsers supports them.
### Roadmap
@ -21,7 +21,7 @@ Feel free to open an issue if you have any question.
### Code of conduct and guidelines
First of all, we expect everyone (contributors and maintainers alike) to respect the [Code of conduct](https://github.com/bastienwirtz/homer/blob/master/CODE_OF_CONDUCT.md). It is not a recomandation, it is mandatory.
First of all, we expect everyone (contributors and maintainers alike) to respect the [Code of conduct](https://github.com/bastienwirtz/homer/blob/master/CODE_OF_CONDUCT.md). It is not a recommendation, it is mandatory.
For all contributions, please respect the following guidelines:

View File

@ -2,7 +2,7 @@
<img
width="180"
alt="Homer's donut"
src="https://raw.githubusercontent.com//bastienwirtz/homer/master/public/logo.png">
src="https://raw.githubusercontent.com//bastienwirtz/homer/main/public/logo.png">
<br/>
Homer
</h1>
@ -36,7 +36,7 @@
</p>
<p align="center">
<img src="https://raw.github.com/bastienwirtz/homer/master/docs/screenshot.png" width="100%">
<img src="https://raw.github.com/bastienwirtz/homer/main/docs/screenshot.png" width="100%">
</p>
## Table of Contents
@ -45,7 +45,7 @@
- [Configuration](docs/configuration.md)
- [Tips & tricks](docs/tips-and-tricks.md)
- [Roadmap](#roadmap)
- [Developement](docs/developement.md)
- [Development](docs/development.md)
## Features

View File

@ -1,6 +1,6 @@
## Configuration
Title, icons, links, colors, and services can be configured in the `config.yml` file (located in `/assets` directory once built, or in the `public/assets` directory in developement mode), using [yaml](http://yaml.org/) format.
Title, icons, links, colors, and services can be configured in the `config.yml` file (located in `/assets` directory once built, or in the `public/assets` directory in development mode), using [yaml](http://yaml.org/) format.
```yaml
---
@ -22,10 +22,12 @@ header: true # Set to false to hide the header
footer: '<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="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it.
columns: "3" # "auto" or number (must be a factor of 12: 1, 2, 3, 4, 6, 12)
vlayout: true # default to the vertical layout
connectivityCheck: true # whether you want to display a message when the apps are not accessible anymore (VPN disconnected for example)
# Optional theming
theme: default # 'default' or one of the theme available in 'src/assets/themes'.
theme_use_dark: false # true or false, useful for overriding browser default in new sessions
# Optional custom stylesheet
# Will load custom CSS files. Especially useful for custom icon sets.
@ -68,6 +70,7 @@ message:
# url: "https://<my-api-endpoint>" # Can fetch information from an endpoint to override value below.
style: "is-warning"
title: "Optional message!"
icon: "fa fa-exclamation-triangle"
content: "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
# Optional navbar
@ -86,7 +89,7 @@ links:
# Leave only a "items" key if not using group (group name, icon & tagstyle are optional, section separation will not be displayed).
services:
- name: "Application"
icon: "fa fa-code-fork"
icon: "fas fa-code-branch"
items:
- name: "Awesome app"
logo: "assets/tools/sample.png"
@ -96,6 +99,8 @@ services:
tag: "app"
url: "https://www.reddit.com/r/selfhosted/"
target: "_blank" # optional html tag target attribute
info: "https://github.com/bastienwirtz/homer/tree/main/docs" # optional link to documentation
infotarget: "_blank" # same as target, but for icon link
- name: "Another one"
logo: "assets/tools/sample2.png"
subtitle: "Another application"
@ -106,13 +111,15 @@ services:
- name: "Other group"
icon: "fas fa-heartbeat"
items:
- name: "Another app"
- name: "Pi-hole"
logo: "assets/tools/sample.png"
subtitle: "Another example"
subtitle: "Network-wide Ad Blocking"
tag: "other"
url: "https://www.reddit.com/r/selfhosted/"
url: "http://192.168.0.151/admin"
type: "PiHole" # optional, loads a specific component that provides extra features. MUST MATCH a file name (without file extension) available in `src/components/services`
target: "_blank" # optional html a tag target attribute
# class: "green" # optional custom CSS class for card, useful with custom stylesheet
# background: red # optional color for card to set color directly without custom stylesheet
```
If you choose to fetch message information from an endpoint, the output format should be:

View File

@ -1,4 +1,4 @@
## Developement
## Development
```sh
# Using yarn (recommended)
@ -13,7 +13,7 @@ npm run serve
### Themes
Themes are meant to be simple customization (written in [scss](https://sass-lang.com/documentation/syntax)).
To addd a new theme, just add a file in the theme directory, and put all style in the `body #app.theme-<name>` scope. Then import it in the main style file.
To add a new theme, just add a file in the theme directory, and put all style in the `body #app.theme-<name>` scope. Then import it in the main style file.
```scss
// `src/assets/themes/my-awesome-theme.scss`

View File

@ -7,7 +7,7 @@ Here is a collection of neat tips and tricks that Homer users have come up with!
These extensions for [Firefox](https://addons.mozilla.org/firefox/addon/custom-new-tab-page) and [Chrome & Friends](https://chrome.google.com/webstore/detail/new-tab-changer/occbjkhimchkolibngmcefpjlbknggfh) allow you to have your homer dashboard in your new tab page, while leaving focus on the address bar meaning you can still type right away if you want to search or go to a page that is not on your homer dash.
The firefox extension loads Homer in an iframe on your new tab page, meaning you have to add `target: '_top'` to each of your items.
The Firefox extension loads Homer in an iframe on your new tab page, meaning you have to add `target: '_top'` to each of your items.
```yaml
- name: "Reddit"
@ -24,7 +24,7 @@ The firefox extension loads Homer in an iframe on your new tab page, meaning you
## YAML Anchors
#### `by @JamiePhonic`
Since Homer is configured using YAML, it supports all of YAML's helpful fetaures, such as anchoring!
Since Homer is configured using YAML, it supports all of YAML's helpful features, such as anchoring!
For example, you can define tags and tag styles for each "item" in a service.
Using Anchoring, you can define all your tags and their styles once like this: (for example)
@ -66,13 +66,13 @@ Then when Homer reads your config, it will substitute your anchors automatically
target: "_blank" # optional html tag target attribute
```
The end result is that if you want to update the name or style of any perticular tag, just update it once, in the tags section!
The end result is that if you want to update the name or style of any particular tag, just update it once, in the tags section!
Great if you have a lot of services or a lot of tags!
## Remotely edit your config with Code Server
#### `by @JamiePhonic`
Homer doesn't yet provide a way to edit your configuration from inside Homer itself, but that doesnt mean it cant be done!
Homer doesn't yet provide a way to edit your configuration from inside Homer itself, but that doesn't mean it cant be done!
You can setup and use [Code-Server](https://github.com/cdr/code-server) to edit your `config.yml` file from anywhere!
@ -123,4 +123,4 @@ So, using [Node-Red](https://nodered.org/docs/getting-started/) and a quick flow
To get started, simply import [this flow](https://flows.nodered.org/flow/4b6406c9a684c26ace0430dd1826e95d) into your Node-Red instance and change the RSS feed in the "Get News RSS Feed" node to one of your choosing!
So far, the flow has been tested with BBC News and Sky News, however it should be easy to modify the flow to work with other RSS feeds if they dont work out of the box!
So far, the flow has been tested with BBC News and Sky News, however it should be easy to modify the flow to work with other RSS feeds if they don't work out of the box!

View File

@ -8,28 +8,28 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.13.1",
"bulma": "^0.9.0",
"@fortawesome/fontawesome-free": "^5.15.1",
"bulma": "^0.9.1",
"core-js": "^3.6.4",
"js-yaml": "^3.14.0",
"lodash.merge": "^4.6.2",
"register-service-worker": "^1.7.1",
"vue": "^2.6.11"
"vue": "^2.6.12"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.4.6",
"@vue/cli-plugin-eslint": "~4.4.6",
"@vue/cli-plugin-pwa": "~4.4.6",
"@vue/cli-service": "~4.4.6",
"@vue/cli-plugin-babel": "~4.5.8",
"@vue/cli-plugin-eslint": "~4.5.8",
"@vue/cli-plugin-pwa": "~4.5.8",
"@vue/cli-service": "~4.5.8",
"@vue/eslint-config-prettier": "^6.0.0",
"babel-eslint": "^10.1.0",
"eslint": "^7.4.0",
"eslint": "^7.11.0",
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-vue": "^6.2.2",
"prettier": "^2.0.5",
"raw-loader": "^4.0.1",
"sass": "^1.26.10",
"sass-loader": "^9.0.2",
"vue-template-compiler": "^2.6.11"
"eslint-plugin-vue": "^7.1.0",
"prettier": "^2.1.2",
"raw-loader": "^4.0.2",
"sass": "^1.27.0",
"sass-loader": "^10.0.4",
"vue-template-compiler": "^2.6.12"
}
}

View File

@ -10,7 +10,7 @@ logo: "logo.png"
header: true
footer: '<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="https://fontawesome.com/">font awesome</a> // Fork me on <a href="https://github.com/bastienwirtz/homer"><i class="fab fa-github-alt"></i></a></p>' # set false if you want to hide it.
# Optionnal theme customization
# Optional theme customization
theme: default
colors:
light:
@ -42,7 +42,8 @@ colors:
message:
#url: https://b4bz.io
style: "is-dark" # See https://bulma.io/documentation/components/message/#colors for styling options.
title: "đź‘‹ Demo !"
title: "Demo !"
icon: "fa fa-grin"
content: "This is a dummy homepage demo. <br /> Find more information on <a href='https://github.com/bastienwirtz/homer'>github.com/bastienwirtz/homer</a>"
# Optional navbar
@ -51,7 +52,7 @@ links:
- name: "Contribute"
icon: "fab fa-github"
url: "https://github.com/bastienwirtz/homer"
target: "_blank" # optionnal html a tag target attribute
target: "_blank" # optional html a tag target attribute
- name: "Wiki"
icon: "fas fa-book"
url: "https://www.wikipedia.org/"
@ -68,7 +69,7 @@ services:
subtitle: "Bookmark example"
tag: "app"
url: "https://www.reddit.com/r/selfhosted/"
target: "_blank" # optionnal html a tag target attribute
target: "_blank" # optional html a tag target attribute
- name: "Another one"
logo: "assets/tools/sample2.png"
subtitle: "Another application"

View File

@ -9,7 +9,7 @@ logo: false
header: true
# Optionnal theme customization
# Optional theme customization
theme: sui
colors:
light:

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

View File

@ -1,79 +1,42 @@
{
"name": "Dashboard",
"short_name": "homer",
"name": "Homer Dashboard",
"short_name": "Homer",
"theme_color": "#3367D6",
"start_url": "../",
"icons": [
{
"src": "./assets/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "./assets/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
},
{
"src": "./assets/icons/android-chrome-maskable-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "./assets/icons/android-chrome-maskable-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "./assets/icons/apple-touch-icon-60x60.png",
"sizes": "60x60",
"type": "image/png"
},
{
"src": "./assets/icons/apple-touch-icon-76x76.png",
"sizes": "76x76",
"type": "image/png"
},
{
"src": "./assets/icons/apple-touch-icon-120x120.png",
"sizes": "120x120",
"type": "image/png"
},
{
"src": "./assets/icons/apple-touch-icon-152x152.png",
"sizes": "152x152",
"type": "image/png"
},
{
"src": "./assets/icons/apple-touch-icon-180x180.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "./assets/icons/apple-touch-icon.png",
"sizes": "180x180",
"type": "image/png"
},
{
"src": "./assets/icons/favicon-16x16.png",
"src": "./icons/favicon-16x16.png",
"sizes": "16x16",
"type": "image/png"
},
{
"src": "./assets/icons/favicon-32x32.png",
"src": "./icons/favicon-32x32.png",
"sizes": "32x32",
"type": "image/png"
},
{
"src": "./assets/icons/msapplication-icon-144x144.png",
"sizes": "144x144",
"type": "image/png"
"src": "./icons/icon-any.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any"
},
{
"src": "./assets/icons/mstile-150x150.png",
"sizes": "150x150",
"type": "image/png"
"src": "./icons/icon-any.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "any"
},
{
"src": "./icons/icon-maskable.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "./icons/safari-pinned-tab.svg",
"sizes": "any",
"type": "image/svg+xml",
"purpose": "monochrome"
}
]
}

View File

@ -26,11 +26,12 @@
<Navbar
:open="showMenu"
:links="config.links"
@navbar:toggle="showMenu = !showMenu"
@navbar-toggle="showMenu = !showMenu"
>
<DarkMode @updated="isDark = $event" />
<DarkMode :isDark="this.isDark" @updated="isDark = $event" />
<SettingToggle
<LayoutToggle
:vlayout="this.vlayout"
@updated="vlayout = $event"
name="vlayout"
icon="fa-list"
@ -40,9 +41,10 @@
<SearchInput
class="navbar-item is-inline-block-mobile"
@input="filterServices"
@search:focus="showMenu = true"
@search:open="navigateToFirstService"
@search:cancel="filterServices"
:value="filter"
@search-focus="showMenu = true"
@search-open="navigateToFirstService"
@search-cancel="filterServices"
/>
</Navbar>
</div>
@ -51,7 +53,7 @@
<div v-cloak class="container">
<ConnectivityChecker
v-if="config.connectivityCheck"
@network:status-update="offline = $event"
@network-status-update="offline = $event"
/>
<div v-if="!offline">
<!-- Optional messages -->
@ -68,6 +70,7 @@
v-for="item in group.items"
:key="item.name"
v-bind:item="item"
@filter="filterTag"
:class="['column', `is-${12 / config.columns}`]"
/>
</template>
@ -90,6 +93,7 @@
<Service
v-for="item in group.items"
v-bind:item="item"
@filter="filterTag"
:key="item.url"
/>
</div>
@ -119,7 +123,7 @@ import ConnectivityChecker from "./components/ConnectivityChecker.vue";
import Service from "./components/Service.vue";
import Message from "./components/Message.vue";
import SearchInput from "./components/SearchInput.vue";
import SettingToggle from "./components/SettingToggle.vue";
import LayoutToggle from "./components/LayoutToggle.vue";
import DarkMode from "./components/DarkMode.vue";
import DynamicTheme from "./components/DynamicTheme.vue";
@ -128,24 +132,24 @@ import defaultConfig from "./assets/defaults.yml";
export default {
name: "App",
components: {
Navbar,
ConnectivityChecker,
Service,
Message,
SearchInput,
SettingToggle,
DarkMode,
DynamicTheme,
Message,
Navbar,
SearchInput,
Service,
LayoutToggle,
},
data: function () {
return {
config: null,
services: null,
offline: false,
filter: "",
vlayout: true,
isDark: null,
offline: false,
services: null,
showMenu: false,
vlayout: null,
};
},
created: async function () {
@ -159,7 +163,11 @@ export default {
}
this.config = merge(defaults, config);
this.services = this.config.services;
document.title = this.config.documentTitle || `${this.config.title} | ${this.config.subtitle}`;
this.isDark = this.config.theme_use_dark;
this.vlayout = this.config.vlayout;
document.title =
this.config.documentTitle ||
`${this.config.title} | ${this.config.subtitle}`;
if (this.config.stylesheet) {
let stylesheet = "";
for (const file of this.config.stylesheet) {
@ -208,6 +216,35 @@ export default {
console.warning("fail to open service");
}
},
filterTag: function (filter) {
this.showMenu = true;
this.$nextTick(() => {
document.getElementById("searchBox").focus();
});
this.filter = filter;
if (!filter) {
this.services = this.config.services;
return;
}
const searchResultItems = [];
for (const group of this.config.services) {
for (const item of group.items) {
if (this.matchesFilter(item)) {
searchResultItems.push(item);
}
}
}
this.services = [
{
name: filter,
icon: "fas fa-search",
items: searchResultItems,
},
];
},
filterServices: function (filter) {
this.filter = filter;

View File

@ -13,17 +13,17 @@
text-overflow: ellipsis;
}
html {
html, body, body #app {
height: 100%;
background-color: var(--background);
}
body {
font-family: "Raleway", sans-serif;
height: 100%;
#app {
height: auto;
min-height: 100%;
background-color: var(--background);
background-image: var(--background-image);
background-size: cover;
background-position: center;
@ -49,6 +49,17 @@ body {
&:hover {
background-color: var(--card-background);
}
.linkoverlay {
position:absolute;
left:0;
top:0;
bottom:0;
right:0;
}
.thirty-five {
font-size: 35px;
}
}
.message {
@ -170,6 +181,7 @@ body {
.title {
font-size: 1.1em;
line-height: 1.2em;
@include ellipsis();
}
@ -195,17 +207,27 @@ body {
}
}
}
.media-left {
pointer-events: none;
z-index: 1;
}
.media-content {
overflow: hidden;
text-overflow: inherit;
}
.infolink {
font-family: "Font Awesome 5 Free";
position: absolute;
top: 0.5rem;
right: 0.5rem;
padding: 0;
}
.tag {
color: var(--highlight-secondary);
background-color: var(--highlight-secondary);
position: absolute;
top: 1rem;
bottom: 1rem;
right: -0.2rem;
width: 3px;
overflow: hidden;

View File

@ -1,6 +1,6 @@
/*
* SUI theme
* Inpired by the great https://github.com/jeroenpardon/sui start page
* Inspired by the great https://github.com/jeroenpardon/sui start page
* Author: @bastienwirtz
*/
body #app.theme-sui {

View File

@ -2,7 +2,7 @@
<div v-if="offline" class="offline-message">
<i class="far fa-dizzy"></i>
<h1>
You're offline bro.
You're offline friend.
<span @click="checkOffline"> <i class="fas fa-redo-alt"></i></span>
</h1>
</div>
@ -44,7 +44,7 @@ export default {
that.offline = true;
})
.finally(function () {
that.$emit("network:status-update", that.offline);
that.$emit("network-status-update", that.offline);
});
},
},

View File

@ -11,23 +11,23 @@
<script>
export default {
name: "Darkmode",
data: function () {
return {
isDark: null,
};
props: {
isDark: Boolean,
},
created: function () {
this.isDark =
let isDark =
"overrideDark" in localStorage
? JSON.parse(localStorage.overrideDark)
: matchMedia("(prefers-color-scheme: dark)").matches;
this.$emit("updated", this.isDark);
: this.isDark === null
? matchMedia("(prefers-color-scheme: dark)").matches
: this.isDark;
this.$emit("updated", isDark);
},
methods: {
toggleTheme: function () {
this.isDark = !this.isDark;
localStorage.overrideDark = this.isDark;
this.$emit("updated", this.isDark);
let isDark = !this.isDark;
localStorage.overrideDark = isDark;
this.$emit("updated", isDark);
},
},
};

View File

@ -1,17 +1,15 @@
<template>
<DynamicStyle>
/* light / dark theme switch based on system pref if available */ body #app
{
:root, body #app.is-light {
{{ getVars(themes.light) }}
} @media (prefers-color-scheme: light), (prefers-color-scheme:
no-preference) { body #app {
no-preference) { :root, body #app {
{{ getVars(themes.light) }}
} } @media (prefers-color-scheme: dark) { body #app { } } /* light / dark
theme override base on user choice. */ body #app.is-dark {
} } body #app.is-dark {
{{ getVars(themes.dark) }}
} body #app.is-light {
{{ getVars(themes.light) }}
}
} @media (prefers-color-scheme: dark) { :root, body #app {
{{ getVars(themes.dark) }}
} }
</DynamicStyle>
</template>
@ -27,7 +25,7 @@ export default {
for (const themeVars in theme) {
let value = `${theme[themeVars]}`;
if (!value) {
value = "inital";
value = "initial";
} else if (themeVars == "background-image") {
value = `url(${theme[themeVars]})`;
}

View File

@ -0,0 +1,43 @@
<template>
<a v-on:click="toggleLayout()" class="navbar-item is-inline-block-mobile">
<span>
<i :class="['fas', 'fa-fw', vlayout ? icon : secondaryIcon]"></i>
</span>
<slot></slot>
</a>
</template>
<script>
export default {
name: "LayoutToggle",
props: {
name: String,
icon: String,
iconAlt: String,
vlayout: Boolean,
},
data: function () {
return {
secondaryIcon: null,
};
},
created: function () {
this.secondaryIcon = this.iconAlt || this.icon;
let vlayout;
if (this.name in localStorage) {
vlayout = JSON.parse(localStorage[this.name]);
} else {
vlayout = this.vlayout === null ? true : this.vlayout;
}
this.$emit("updated", vlayout);
},
methods: {
toggleLayout: function () {
let vlayout = !this.vlayout;
localStorage[this.name] = vlayout;
this.$emit("updated", vlayout);
},
},
};
</script>

View File

@ -1,7 +1,10 @@
<template>
<article v-if="show" class="message" :class="message.style">
<div v-if="message.title" class="message-header">
<p>{{ message.title }}</p>
<div v-if="message.title || message.icon" class="message-header">
<p>
<i v-if="message.icon" :class="`fa-fw ${message.icon}`"></i>
{{ message.title }}
</p>
</div>
<div
v-if="message.content"

View File

@ -9,7 +9,7 @@
aria-expanded="false"
class="navbar-burger"
:class="{ 'is-active': showMenu }"
v-on:click="$emit('navbar:toggle')"
v-on:click="$emit('navbar-toggle')"
>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
@ -21,8 +21,8 @@
<a
class="navbar-item"
rel="noreferrer"
v-for="link in links"
:key="link.url"
v-for="(link, key) in links"
:key="key"
:href="link.url"
:target="link.target"
>

View File

@ -2,12 +2,13 @@
<div class="search-bar">
<label for="search" class="search-label"></label>
<input
id="searchBox"
type="text"
ref="search"
:value="value"
@input="$emit('input', $event.target.value.toLowerCase())"
@keyup.enter.exact="$emit('search:open')"
@keyup.alt.enter="$emit('search:open', '_blank')"
@keyup.enter.exact="$emit('search-open')"
@keyup.alt.enter="$emit('search-open', '_blank')"
/>
</div>
</template>
@ -20,7 +21,7 @@ export default {
this._keyListener = function (event) {
if (event.key === "/") {
event.preventDefault();
this.$emit("search:focus");
this.$emit("search-focus");
this.$nextTick(() => {
this.$refs.search.focus();
});
@ -28,7 +29,7 @@ export default {
if (event.key === "Escape") {
this.$refs.search.value = "";
this.$refs.search.blur();
this.$emit("search:cancel");
this.$emit("search-cancel");
}
};
document.addEventListener("keydown", this._keyListener.bind(this));

View File

@ -1,40 +1,26 @@
<template>
<div>
<div class="card" :class="item.class">
<a :href="item.url" :target="item.target" rel="noreferrer">
<div class="card-content">
<div class="media">
<div v-if="item.logo" class="media-left">
<figure class="image is-48x48">
<img :src="item.logo" :alt="`${item.name} logo`" />
</figure>
</div>
<div v-if="item.icon" class="media-left">
<figure class="image is-48x48">
<i style="font-size: 35px;" :class="['fa-fw', 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>
<div class="tag" :class="item.tagstyle" v-if="item.tag">
<strong class="tag-text">#{{ item.tag }}</strong>
</div>
</div>
</a>
</div>
</div>
<component v-on="$listeners" v-bind:is="component" :item="item"></component>
</template>
<script>
import Generic from "./services/Generic.vue";
export default {
name: "Service",
components: {
Generic,
},
props: {
item: Object,
},
computed: {
component() {
const type = this.item.type || "Generic";
if (type == "Generic") {
return Generic;
}
return () => import(`./services/${type}.vue`);
},
},
};
</script>
<style scoped lang="scss"></style>

View File

@ -1,40 +0,0 @@
<template>
<a v-on:click="toggleSetting()" class="navbar-item is-inline-block-mobile">
<span><i :class="['fas', 'fa-fw', value ? icon : iconAlt]"></i></span>
<slot></slot>
</a>
</template>
<script>
export default {
name: "SettingToggle",
props: {
name: String,
icon: String,
iconAlt: String,
},
data: function () {
return {
value: true,
};
},
created: function () {
if (!this.iconAlt) {
this.iconAlt = this.icon;
}
if (this.name in localStorage) {
this.value = JSON.parse(localStorage[this.name]);
}
this.$emit("updated", this.value);
},
methods: {
toggleSetting: function () {
this.value = !this.value;
localStorage[this.name] = this.value;
this.$emit("updated", this.value);
},
},
};
</script>

View File

@ -0,0 +1,84 @@
<script>
export default {};
</script>
<style></style>
<script>
export default {};
</script>
<style></style>
<template>
<div>
<div
class="card"
:style="`background-color:${item.background};`"
:class="item.class"
>
<a
:href="item.url"
class="linkoverlay"
:target="item.target"
rel="noreferrer"
></a>
<div class="card-content">
<div class="media">
<div v-if="item.logo" class="media-left">
<figure class="image is-48x48">
<img :src="item.logo" :alt="`${item.name} logo`" />
</figure>
</div>
<div v-if="item.icon" class="media-left">
<figure class="image is-48x48">
<i class="thirty-five" :class="['fa-fw', 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>
<a
v-if="item.info"
:href="item.info"
:target="item.infotarget"
rel="noreferrer"
>
<div class="infolink">
<i class="fas fa-info-circle"></i>
</div>
</a>
<div
v-on:click="filterTag()"
class="tag is-clickable"
:class="item.tagstyle"
v-if="item.tag"
>
<strong class="tag-text">#{{ item.tag }}</strong>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "Generic",
props: {
item: Object,
},
methods: {
filterTag: function () {
this.$emit("filter", this.item.tag.toLowerCase());
},
},
};
</script>
<style scoped lang="scss">
.media-left img {
max-height: 100%;
}
</style>

View File

@ -0,0 +1,96 @@
<template>
<div>
<div class="card" :class="item.class">
<a :href="item.url" :target="item.target" rel="noreferrer">
<div class="card-content">
<div class="media">
<div v-if="item.logo" class="media-left">
<figure class="image is-48x48">
<img :src="item.logo" :alt="`${item.name} logo`" />
</figure>
</div>
<div v-if="item.icon" class="media-left">
<figure class="image is-48x48">
<i class="thirty-five" :class="['fa-fw', 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-if="status" class="status" :class="status.status">
{{ status.status }}
</div>
</div>
<div
v-on:click="filterTag()"
class="tag is-clickable"
:class="item.tagstyle"
v-if="item.tag"
>
<strong class="tag-text">#{{ item.tag }}</strong>
</div>
</div>
</a>
</div>
</div>
</template>
<script>
export default {
name: "PiHole",
props: {
item: Object,
},
data: () => {
return {
status: null,
};
},
created: function () {
this.fetchStatus();
},
methods: {
fetchStatus: async function () {
this.status = await fetch(`${this.item.url}/api.php`).then((response) =>
response.json()
);
},
filterTag: function () {
this.$emit("filter", this.item.tag.toLowerCase());
},
},
};
</script>
<style scoped lang="scss">
.media-left img {
max-height: 100%;
}
.status {
font-size: 0.8rem;
color: var(--text-title);
&.enabled:before {
background-color: #94e185;
border-color: #78d965;
box-shadow: 0px 0px 4px 1px #94e185;
}
&.disabled:before {
background-color: #c9404d;
border-color: #c42c3b;
box-shadow: 0px 0px 4px 1px #c9404d;
}
&:before {
content: " ";
display: inline-block;
width: 7px;
height: 7px;
margin-right: 10px;
border: 1px solid #000;
border-radius: 7px;
}
}
</style>

View File

@ -1,3 +1,5 @@
const manifestOptions = require("./public/assets/manifest.json");
module.exports = {
chainWebpack: (config) => {
config.module
@ -10,94 +12,17 @@ module.exports = {
publicPath: "",
pwa: {
manifestPath: "assets/manifest.json",
manifestOptions: {
start_url: "../",
},
appleMobileWebAppStatusBarStyle: "black",
appleMobileWebAppCapable: "yes",
name: "Homer Dashboard",
short_name: "Homer",
theme_color: "#3367D6",
icons: [
{
src: "./assets/icons/android-chrome-192x192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "./assets/icons/android-chrome-512x512.png",
sizes: "512x512",
type: "image/png",
},
{
src: "./assets/icons/android-chrome-maskable-192x192.png",
sizes: "192x192",
type: "image/png",
purpose: "maskable",
},
{
src: "./assets/icons/android-chrome-maskable-512x512.png",
sizes: "512x512",
type: "image/png",
purpose: "maskable",
},
{
src: "./assets/icons/apple-touch-icon-60x60.png",
sizes: "60x60",
type: "image/png",
},
{
src: "./assets/icons/apple-touch-icon-76x76.png",
sizes: "76x76",
type: "image/png",
},
{
src: "./assets/icons/apple-touch-icon-120x120.png",
sizes: "120x120",
type: "image/png",
},
{
src: "./assets/icons/apple-touch-icon-152x152.png",
sizes: "152x152",
type: "image/png",
},
{
src: "./assets/icons/apple-touch-icon-180x180.png",
sizes: "180x180",
type: "image/png",
},
{
src: "./assets/icons/apple-touch-icon.png",
sizes: "180x180",
type: "image/png",
},
{
src: "./assets/icons/favicon-16x16.png",
sizes: "16x16",
type: "image/png",
},
{
src: "./assets/icons/favicon-32x32.png",
sizes: "32x32",
type: "image/png",
},
{
src: "./assets/icons/msapplication-icon-144x144.png",
sizes: "144x144",
type: "image/png",
},
{
src: "./assets/icons/mstile-150x150.png",
sizes: "150x150",
type: "image/png",
},
],
name: manifestOptions.name,
themeColor: manifestOptions.theme_color,
manifestOptions,
iconPaths: {
favicon32: "assets/icons/favicon-32x32.png",
favicon16: "assets/icons/favicon-16x16.png",
appleTouchIcon: "assets/icons/apple-touch-icon-152x152.png",
appleTouchIcon: "assets/icons/icon-maskable.png",
maskIcon: "assets/icons/safari-pinned-tab.svg",
msTileImage: "assets/icons/msapplication-icon-144x144.png",
msTileImage: "assets/icons/icon-any.png",
},
},
};

2215
yarn.lock

File diff suppressed because it is too large Load Diff