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

Compare commits

...

88 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
Bastien Wirtz
f2eacfcba1
Merge pull request #120 from tpansino/feature/custom-document-title
Feature/custom document title
2020-09-05 10:08:58 -07:00
Tom Pansino
a02961b70b Add documentTitle example to documentation 2020-09-04 16:09:43 -07:00
Tom Pansino
9d0ec9e348 Support custom document title 2020-09-04 16:07:20 -07:00
Bastien Wirtz
ffe3404a2a Simplify service structure 2020-09-04 15:52:34 -07:00
Bastien Wirtz
bcf0e1bec2
Merge pull request #119 from tpansino/feature/custom-card-colors
Feature/custom card colors
2020-09-04 15:30:01 -07:00
Tiger Oakes
f70fc3ecae Reduce number of PWA icons, fix paths 2020-09-02 22:02:14 -07:00
Tom Pansino
e9afa4d7dd Rewrite custom card colors to use custom CSS classes instead of styles 2020-09-02 00:34:37 -07:00
Tom Pansino
fbe9338fd3 Merge remote-tracking branch 'upstream/master' into feature/custom-card-colors 2020-09-01 23:47:59 -07:00
Bastien Wirtz
83665e4f48
Merge pull request #113 from gabe565/custom-stylesheet
Add support for a custom stylesheet
2020-08-29 10:50:42 -07:00
Gabe Cook
8e5ee54a78
🔧 Make stylesheet config be an array of files 2020-08-29 02:43:02 -05:00
Gabe Cook
71cf63eb3b
📝 Document new stylesheet config 2020-08-29 02:21:09 -05:00
Gabe Cook
6777bc347b
Add support for a custom stylesheet 2020-08-29 02:21:09 -05:00
Bastien Wirtz
2644101276
Merge pull request #118 from vosdev/patch-1
Add chrome extension for a custom new tab page
2020-08-28 23:36:41 -07:00
Bastien Wirtz
607fb898f8
Merge pull request #115 from gabe565/navbar-alignment
Fix alignment when navbar link name is empty
2020-08-28 23:35:08 -07:00
Bastien Wirtz
2e7eb41f8c
Merge pull request #112 from gabe565/fa-fw-logo-alignment
Remove fa-fw from main logo to fix Font Awesome duotone issues
2020-08-28 23:15:00 -07:00
Bastien Wirtz
db738288fa
Merge pull request #101 from simonporte/master
Added docker-compose.yml
2020-08-28 23:12:22 -07:00
Tom Pansino
7e5ad02248 Add example card colors to configuration.md 2020-08-10 23:31:34 -07:00
Tom Pansino
118d3e5ac0 Rename color: to colors: 2020-08-10 17:25:43 -07:00
Tom Pansino
687a9e4086 Add support for custom card colors 2020-08-09 23:03:00 -07:00
Daniel Vos
4f04feb2da
Add chrome extension for a custom new tab page
I finally found a chrome extension that gives the same functionality as the firefox extension for the custom new tab page. I have updated the docs accordingly!
2020-08-03 20:00:52 +02:00
Gabe Cook
68c36d6c54
🐛 Fix alignment when navbar link name is empty 2020-07-28 17:18:41 -05:00
simonporte
e4537f134b Added docker-compose.yml
Plus short explanation in readme
Changed the commit as pointed by @Shuro
Explained readme more as asked by @bastienwirtz
2020-07-24 14:38:42 +02:00
Gabe Cook
239ef1688d
🐛 Remove fa-fw from main logo to fix Font Awesome duotone issues 2020-07-22 15:06:26 -05:00
Bastien Wirtz
154e6efe80 Adding support for section backgrounf images 2020-07-15 14:26:01 -07:00
Bastien Wirtz
d05b8d3bf0 Uniformise dockerfile 2020-07-15 14:23:29 -07:00
Bastien Wirtz
0ae40f78f8 Auth redirection support 2020-07-13 09:16:47 -07:00
Bastien Wirtz
6de53c49b3
Merge pull request #108 from GlennToms/master
Added su-exec to ARM dockerfiles and removed USER line
2020-07-12 21:09:42 -07:00
Bastien Wirtz
ab40c4e007 Adding support for release build. 2020-07-12 20:12:53 -07:00
Bastien Wirtz
1f92e1746d Dependancies update 2020-07-12 20:12:31 -07:00
Bastien Wirtz
8ae1fe8a4e Lint clean 2020-07-12 20:11:54 -07:00
AgileVirus
fd9237eb52 Added su-exec to ARM dockerfiles and removed USER line 2020-07-09 18:47:33 +01:00
Bastien Wirtz
4bfcc5bc95
Merge pull request #100 from fbartels/start_url
Explicitly define start_url
2020-07-04 18:11:08 -07:00
Bastien Wirtz
d3da4cfe93
Merge pull request #105 from fbartels/deduplicate
Removing duplicated dependencies
2020-07-04 18:10:22 -07:00
Felix Bartels
d1cc18761f deduplicate dependencies with https://github.com/atlassian/yarn-deduplicate
Signed-off-by: Felix Bartels <felix@host-consultants.de>
2020-07-01 11:56:54 +02:00
Felix Bartels
a503c5743e Explicitly define start_url
Relates to #99

Signed-off-by: Felix Bartels <felix@host-consultants.de>
2020-06-29 20:03:52 +02:00
Bastien Wirtz
a9aed9f9e2 Modernize readme 2020-06-28 21:42:07 -07:00
Bastien Wirtz
7ef65940ee Fix dynamic message override. 2020-06-28 18:31:42 -07:00
Bastien Wirtz
d1b9dea287 Donut's back! 2020-06-28 15:24:44 -07:00
Bastien Wirtz
ae73d7a5a0
Merge pull request #97 from gabe565/fa-fw
Add fa-fw to icons by default to fix variable width icons
2020-06-28 11:55:50 -07:00
Bastien Wirtz
25b6367aa1
Merge pull request #94 from bastienwirtz/avoid-file-volume
Regroup all editable files in one place
2020-06-28 11:07:37 -07:00
Bastien Wirtz
b102c9b2b3 Regroup all editable files in one place 2020-06-28 11:05:40 -07:00
Gabe Cook
da6e676d6e
💄 Add fa-fw to icons by default to fix variable width icons
Fixes #93
2020-06-25 17:56:26 -05:00
Bastien Wirtz
796a16c8da
Fix Github action trigger syntax 2020-06-19 08:22:34 -07:00
59 changed files with 2135 additions and 1664 deletions

View File

@ -2,4 +2,5 @@ assets/*
dockerfile
*.md
.git
screenshot.png
screenshot.png
node_modules

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

@ -3,8 +3,7 @@ name: Upload Release Asset
on:
push:
tags:
- *
tags: [v*]
jobs:
build:

4
.gitignore vendored
View File

@ -21,4 +21,6 @@ yarn-error.log*
*.sw?
# App configuration
public/config.yml
config.yml
.drone.yml

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

@ -19,12 +19,12 @@ ENV UID 911
ENV PORT 8080
RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \
apk add -U darkhttpd
apk add -U --no-cache su-exec darkhttpd
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/
COPY --chown=${USER}:${GROUP} entrypoint.sh /entrypoint.sh
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets
COPY entrypoint.sh /entrypoint.sh
USER ${USER}
EXPOSE ${PORT}
VOLUME [ "/www/config.yml", "/www/assets" ]
VOLUME /www/assets
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]

View File

@ -28,13 +28,13 @@ ENV UID 911
ENV PORT 8080
RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \
apk add -U darkhttpd && \
apk add -U --no-cache darkhttpd su-exec && \
rm /usr/bin/qemu-arm-static
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/
COPY --chown=${USER}:${GROUP} entrypoint.sh /entrypoint.sh
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets
COPY entrypoint.sh /entrypoint.sh
USER ${USER}
EXPOSE ${PORT}
VOLUME [ "/www/config.yml", "/www/assets" ]
VOLUME /www/assets
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]

View File

@ -28,13 +28,13 @@ ENV UID 911
ENV PORT 8080
RUN addgroup -S ${GROUP} -g ${GID} && adduser -D -S -u ${UID} ${USER} ${GROUP} && \
apk add -U darkhttpd && \
apk add -U --no-cache darkhttpd su-exec && \
rm /usr/bin/qemu-aarch64-static
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist /www/
COPY --chown=${USER}:${GROUP} entrypoint.sh /entrypoint.sh
COPY --from=build-stage --chown=${USER}:${GROUP} /app/dist/assets /www/default-assets
COPY entrypoint.sh /entrypoint.sh
USER ${USER}
EXPOSE ${PORT}
VOLUME [ "/www/config.yml", "/www/assets" ]
VOLUME /www/assets
ENTRYPOINT ["/bin/sh", "/entrypoint.sh"]

View File

@ -1,15 +1,43 @@
# Homer
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
[![Contribution Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](http://makeapullrequest.com)
[![Gitter](https://badges.gitter.im/homer-dashboard/community.svg)](https://gitter.im/homer-dashboard/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![Dowload](https://img.shields.io/badge/Dowload-homer.zip-orange)](https://github.com/bastienwirtz/homer/releases/latest/download/homer.zip)
[![Awesome](https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg)](https://github.com/awesome-selfhosted/awesome-selfhosted)
<h1 align="center">
<img
width="180"
alt="Homer's donut"
src="https://raw.githubusercontent.com//bastienwirtz/homer/main/public/logo.png">
<br/>
Homer
</h1>
A dead simple static **HOM**epage for your serv**ER** to keep your s
ervices on hand, from a simple `yaml` configuration file.
<h4 align="center">
A dead simple static <strong>HOM</strong>epage for your serv<strong>ER</strong> to keep your services on hand, from a simple `yaml` configuration file.
</h4>
## [Live demo](https://homer-demo.netlify.app) • [Chat](https://gitter.im/homer-dashboard/community)
![screenshot](https://raw.github.com/bastienwirtz/homer/master/screenshot.png)
<p align="center">
<strong>
<a href="https://homer-demo.netlify.app">Demo</a>
<a href="https://gitter.im/homer-dashboard/community">Chat</a>
<a href="#getting-started">Getting started</a>
</strong>
</p>
<p align="center">
<a href="https://opensource.org/licenses/Apache-2.0"><img
alt="License: Apache 2"
src="https://img.shields.io/badge/License-Apache%202.0-blue.svg"></a>
<a href="https://gitter.im/homer-dashboard/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge"><img
alt="Gitter chat"
src="https://badges.gitter.im/homer-dashboard/community.svg"></a>
<a href="https://github.com/bastienwirtz/homer/releases/latest/download/homer.zip"><img
alt="Download homer static build"
src="https://img.shields.io/badge/Download-homer.zip-orange"></a>
<a href="https://github.com/awesome-selfhosted/awesome-selfhosted"><img
alt="Awesome"
src="https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg"></a>
</p>
<p align="center">
<img src="https://raw.github.com/bastienwirtz/homer/main/docs/screenshot.png" width="100%">
</p>
## Table of Contents
- [Features](#features)
@ -17,7 +45,7 @@ ervices on hand, from a simple `yaml` configuration file.
- [Configuration](docs/configuration.md)
- [Tips & tricks](docs/tips-and-tricks.md)
- [Roadmap](#roadmap)
- [Developement](docs/developement.md)
- [Development](docs/development.md)
## Features
@ -38,31 +66,54 @@ ervices on hand, from a simple `yaml` configuration file.
Homer is a full static html/js dashboard, generated from the source in `/src` using webpack. It's meant to be served by an HTTP server, **it will not work if you open dist/index.html directly over file:// protocol**.
For more information about the `config.yml` file see [configuration](docs/configuration.md) the section.
See [documentation](docs/configuration.md) for information about the configuration (`assets/config.yml`) options.
### Using docker
To launch container :
```sh
docker run -p 8080:8080 -v /your/local/config.yml:/www/config.yml -v /your/local/assets/:/www/assets b4bz/homer:latest
docker run -p 8080:8080 -v /your/local/assets/:/www/assets b4bz/homer:latest
```
As a bind mount is used here, docker will not copy the initial content of the `assets` directory to the mounted directory.
You can initialise your assets directory with the content provided in this repository
```sh
cp -r /public/assets/* /your/local/assets/
Default assets will be automatically installed in the `/www/assets` directory. Use `UID` and/or `GID` env var to change the assets owner (`docker run -e "UID=1000" -e "GID=1000" [...]`).
### Using docker-compose
The `docker-compose.yml` file must be edited to match your needs.
Set the port and volume (equivalent to -p and -v arguments) :
```yaml
volumes:
- /your/local/assets/:/www/assets
ports:
- 8080:8080
```
**Alternatively** if you just want to provide images/icons without customizing the other files (app manifest & pwa icons), you can mount a custom directory in the `www` directory and use it in your `config.yml` for icons path.
To launch container :
```sh
cd /path/to/docker-compose.yml
docker-compose up -d
```
Default assets will be automatically installed in the `/www/assets` directory. Use `UID` and/or `GID` env var to change the assets owner, also in `docker-compose.yml` :
```yaml
environment:
- UID=1000
- GID=1000
```
### Using the release tarball (prebuilt, ready to use)
Download and extract the latest the latest release (`homer.zip`) from the [release page](https://github.com/bastienwirtz/homer/releases), rename the `config.yml.dist` file to `config.yml`, and put it behind a webserver.
Download and extract the latest the latest release (`homer.zip`) from the [release page](https://github.com/bastienwirtz/homer/releases), rename the `assets/config.yml.dist` file to `assets/config.yml`, and put it behind a webserver.
```sh
wget https://github.com/bastienwirtz/homer/releases/latest/download/homer.zip
unzip homer.zip
cd homer
cp config.yml.dist config.yml
cp assets/config.yml.dist assets/config.yml
npx serve # or python -m http.server 8010 or apache, nginx ...
```

14
docker-compose.yml Normal file
View File

@ -0,0 +1,14 @@
---
version: "2"
services:
homer:
image: b4bz/homer
container_name: homer
volumes:
- /your/local/assets/:/www/assets
ports:
- 8080:8080
#environment:
# - UID=1000
# - GID=1000
restart: unless-stopped

View File

@ -1,6 +1,6 @@
## Configuration
Title, icons, links, colors, and services can be configured in the `config.yml` file (located in project root directory once built, or in the `public/` 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
---
@ -13,7 +13,8 @@ Title, icons, links, colors, and services can be configured in the `config.yml`
title: "App dashboard"
subtitle: "Homer"
logo: "assets/homer.png"
# documentTitle: "Welcome" # Customize the browser tab text
logo: "assets/logo.png"
# Alternatively a fa icon can be provided:
# icon: "fas fa-skull-crossbones"
@ -21,10 +22,17 @@ 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.
# stylesheet:
# - "assets/custom.css"
# Here is the exaustive list of customization parameters
# However all value are optional and will fallback to default if not set.
@ -42,6 +50,7 @@ colors:
text-subtitle: "#424242"
card-shadow: rgba(0, 0, 0, 0.1)
link-hover: "#363636"
background-image: "assets/your/light/bg.png"
dark:
highlight-primary: "#3367d6"
highlight-secondary: "#4285f4"
@ -54,12 +63,14 @@ colors:
text-subtitle: "#f5f5f5"
card-shadow: rgba(0, 0, 0, 0.4)
link-hover: "#ffdd57"
background-image: "assets/your/dark/bg.png"
# Optional message
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
@ -78,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"
@ -88,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"
@ -98,12 +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/"
target: "_blank" # optionnal html a tag target attribute
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:
@ -129,3 +145,11 @@ Homer uses [bulma CSS](https://bulma.io/), which provides a [modifiers syntax](h
- `is-danger` (red)
You can read the [bulma modifiers page](https://bulma.io/documentation/modifiers/syntax/) for other options regarding size, style, or state.
### PWA Icons
In order to easily generate all required icon preset for the PWA to work, a tool like [vue-pwa-asset-generator](https://www.npmjs.com/package/vue-pwa-asset-generator) can be used:
```bash
npx vue-pwa-asset-generator -a {your_512x512_source_png} -o {your_output_folder}
```

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`

BIN
docs/screenshot.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -5,9 +5,9 @@ Here is a collection of neat tips and tricks that Homer users have come up with!
## Use Homer as a custom "new tab" page
#### `by @vosdev`
This [extension](https://addons.mozilla.org/firefox/addon/custom-new-tab-page) allows 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.
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 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 extension loads Homer in an iframe on your new tab page, meaning you have to
## 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,15 +66,15 @@ 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!
You can setup and use [Code-Server](https://github.com/cdr/code-server) to edit your `config.yml` file from anywhere!
If you're running Homer in docker, you can setup a Code-Server container and pass your homer config directory into it.
Simply pass your homer config directory as and extra -v parameter to your code-server container:
@ -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

@ -1,6 +1,15 @@
#!/bin/sh
yes n | cp -i /www/config.yml.dist /www/config.yml
while true; do echo n; done | cp -Ri /app/dist/www/assets /www/assets 2>/dev/null
# Ensure default assets are present.
while true; do echo n; done | cp -Ri /www/default-assets/* /www/assets/ &> /dev/null
darkhttpd /www/ --no-listing --port $PORT
# Ensure compatibility with previous version (config.yml was in the root directory)
if [ -f "/www/config.yml" ]; then
yes n | cp -i /www/config.yml /www/assets/ &> /dev/null
fi
# Install default config if no one is available.
yes n | cp -i /www/default-assets/config.yml.dist /www/assets/config.yml &> /dev/null
chown -R $UID:$GID /www/assets
exec su-exec $UID:$GID darkhttpd /www/ --no-listing --port "$PORT"

View File

@ -1,7 +1,8 @@
#!/bin/bash
docker manifest push --purge b4bz/homer:latest
docker manifest create b4bz/homer:latest b4bz/homer:latest-amd64 b4bz/homer:latest-arm32v7 b4bz/homer:latest-arm64v8
docker manifest annotate b4bz/homer:latest b4bz/homer:latest-arm32v7 --os linux --arch arm
docker manifest annotate b4bz/homer:latest b4bz/homer:latest-arm64v8 --os linux --arch arm64 --variant v8
docker manifest push --purge b4bz/homer:latest
IFS='-' read -r TAG string <<< "$DOCKER_TAG"
docker manifest create b4bz/homer:$TAG b4bz/homer:$TAG-amd64 b4bz/homer:$TAG-arm32v7 b4bz/homer:$TAG-arm64v8
docker manifest annotate b4bz/homer:$TAG b4bz/homer:$TAG-arm32v7 --os linux --arch arm
docker manifest annotate b4bz/homer:$TAG b4bz/homer:$TAG-arm64v8 --os linux --arch arm64 --variant v8
docker manifest push --purge b4bz/homer:$TAG

View File

@ -8,28 +8,28 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@fortawesome/fontawesome-free": "^5.13.0",
"bulma": "^0.8.2",
"@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.1",
"@vue/cli-plugin-eslint": "~4.4.1",
"@vue/cli-plugin-pwa": "~4.4.1",
"@vue/cli-service": "~4.4.1",
"@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.2.0",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-vue": "^6.2.2",
"prettier": "^2.0.5",
"raw-loader": "^4.0.1",
"sass": "^1.26.8",
"sass-loader": "^8.0.2",
"vue-template-compiler": "^2.6.11"
"eslint": "^7.11.0",
"eslint-plugin-prettier": "^3.1.4",
"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:

View File

@ -0,0 +1,8 @@
@charset "UTF-8";
/* Custom card colors */
/* Use with `class:` property of services in config.yml */
body #app .card.green {
background-color: #006600;
color: #00ff00;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 425 B

After

Width:  |  Height:  |  Size: 790 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 2.3 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: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 6.7 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"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

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 -->
@ -61,13 +63,14 @@
<div v-if="!vlayout || filter" class="columns is-multiline">
<template v-for="group in services">
<h2 v-if="group.name" class="column is-full group-title">
<i v-if="group.icon" :class="group.icon"></i>
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
{{ group.name }}
</h2>
<Service
v-for="item in group.items"
:key="item.name"
v-bind:item="item"
@filter="filterTag"
:class="['column', `is-${12 / config.columns}`]"
/>
</template>
@ -84,12 +87,13 @@
:key="group.name"
>
<h2 v-if="group.name" class="group-title">
<i v-if="group.icon" :class="group.icon"></i>
<i v-if="group.icon" :class="['fa-fw', group.icon]"></i>
{{ group.name }}
</h2>
<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,38 +132,60 @@ 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 () {
const defaults = jsyaml.load(defaultConfig);
let config = await this.getConfig();
let config;
try {
config = await this.getConfig();
} catch (error) {
console.log(error);
config = this.handleErrors("⚠️ Error loading configuration", error);
}
this.config = merge(defaults, config);
this.services = this.config.services;
document.title = `${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) {
stylesheet += `@import "${file}";`;
}
this.createStylesheet(stylesheet);
}
},
methods: {
getConfig: function (path = "config.yml") {
getConfig: function (path = "assets/config.yml") {
return fetch(path).then((response) => {
if (response.redirected) {
// This allows to work with authentication proxies.
window.location.href = response.url;
return;
}
if (!response.ok) {
throw Error(response.statusText);
throw Error(`${response.statusText}: ${response.body}`);
}
const that = this;
@ -173,9 +199,6 @@ export default {
return that.getConfig(config.externalConfig);
}
return config;
})
.catch((error) => {
return this.handleErrors("⚠️ Error loading configuration", error);
});
});
},
@ -193,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;
@ -227,6 +279,11 @@ export default {
},
};
},
createStylesheet: function (css) {
let style = document.createElement("style");
style.appendChild(document.createTextNode(css));
document.head.appendChild(style);
},
},
};
</script>

View File

@ -13,17 +13,20 @@
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;
color: var(--text);
transition: background-color cubic-bezier(0.165, 0.84, 0.44, 1) 300ms;
@ -46,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 {
@ -167,6 +181,7 @@ body {
.title {
font-size: 1.1em;
line-height: 1.2em;
@include ellipsis();
}
@ -192,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

@ -24,6 +24,7 @@ colors:
text-subtitle: "#424242"
card-shadow: rgba(0, 0, 0, 0.1)
link-hover: "#363636"
background-image: ""
dark:
highlight-primary: "#3367d6"
highlight-secondary: "#4285f4"
@ -36,6 +37,7 @@ colors:
text-subtitle: "#f5f5f5"
card-shadow: rgba(0, 0, 0, 0.4)
link-hover: "#ffdd57"
background-image: ""
message: ~
links: []

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

@ -4,30 +4,30 @@
aria-label="Toggle dark mode"
class="navbar-item is-inline-block-mobile"
>
<i class="fas fa-adjust"></i>
<i class="fas fa-fw fa-adjust"></i>
</a>
</template>
<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>
@ -25,7 +23,13 @@ export default {
getVars: function (theme) {
let vars = [];
for (const themeVars in theme) {
vars.push(`--${themeVars}: ${theme[themeVars]}`);
let value = `${theme[themeVars]}`;
if (!value) {
value = "initial";
} else if (themeVars == "background-image") {
value = `url(${theme[themeVars]})`;
}
vars.push(`--${themeVars}: ${value}`);
}
return vars.join(";");
},

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,9 +1,16 @@
<template>
<article v-if="item" class="message" :class="item.style">
<div v-if="item.title" class="message-header">
<p>{{ item.title }}</p>
<article v-if="show" class="message" :class="message.style">
<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="item.content" class="message-body" v-html="item.content"></div>
<div
v-if="message.content"
class="message-body"
v-html="message.content"
></div>
</article>
</template>
@ -13,19 +20,25 @@ export default {
props: {
item: Object,
},
created: function () {
data: function () {
return {
show: false,
message: {},
};
},
created: async function () {
// Look for a new message if an endpoint is provided.
let that = this;
this.message = Object.assign({}, this.item);
if (this.item && this.item.url) {
this.getMessage(this.item.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.item[prop] = message[prop];
}
const fetchedMessage = await this.getMessage(this.item.url);
// keep the original config value if no value is provided by the endpoint
for (const prop of ["title", "style", "content"]) {
if (prop in fetchedMessage && fetchedMessage[prop] !== null) {
this.message[prop] = fetchedMessage[prop];
}
});
}
}
this.show = this.message.title || this.message.content;
},
methods: {
getMessage: function (url) {

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,15 +21,14 @@
<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"
>
<i
v-if="link.icon"
style="margin-right: 6px;"
:class="link.icon"
:class="['fa-fw', link.icon, { 'mr-2': link.name }]"
></i>
{{ link.name }}
</a>

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">
<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="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', 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
@ -12,89 +14,15 @@ module.exports = {
manifestPath: "assets/manifest.json",
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",
},
},
};

2783
yarn.lock

File diff suppressed because it is too large Load Diff