@ -1,3 +0,0 @@
|
||||
> 1%
|
||||
last 2 versions
|
||||
not dead
|
17
.eslintrc.cjs
Normal file
@ -0,0 +1,17 @@
|
||||
/* eslint-env node */
|
||||
require("@rushstack/eslint-patch/modern-module-resolution");
|
||||
|
||||
module.exports = {
|
||||
root: true,
|
||||
extends: [
|
||||
"plugin:vue/vue3-essential",
|
||||
"eslint:recommended",
|
||||
"@vue/eslint-config-prettier",
|
||||
],
|
||||
env: {
|
||||
"vue/setup-compiler-macros": true,
|
||||
},
|
||||
rules: {
|
||||
"vue/multi-word-component-names": "off",
|
||||
},
|
||||
};
|
15
.eslintrc.js
@ -1,15 +0,0 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: ["plugin:vue/essential", "eslint:recommended", "@vue/prettier"],
|
||||
parserOptions: {
|
||||
parser: "babel-eslint",
|
||||
},
|
||||
rules: {
|
||||
"no-console": "off",
|
||||
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
|
||||
"vue/require-v-for-key": "off",
|
||||
},
|
||||
};
|
15
.github/workflows/integration.yml
vendored
@ -20,12 +20,19 @@ jobs:
|
||||
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
cache: 'yarn'
|
||||
- run: yarn install
|
||||
- run: yarn lint
|
||||
-
|
||||
name: install dependencies
|
||||
run: yarn install
|
||||
-
|
||||
name: Check code style & potentential issues
|
||||
run: yarn lint
|
||||
|
||||
|
13
.github/workflows/release.yml
vendored
@ -10,15 +10,20 @@ jobs:
|
||||
name: Upload Release Asset
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Build project
|
||||
-
|
||||
name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
-
|
||||
name: Build project
|
||||
run: |
|
||||
yarn install
|
||||
yarn build
|
||||
- name: Create artifact
|
||||
-
|
||||
name: Create artifact
|
||||
working-directory: "dist"
|
||||
run: zip -r ../homer.zip ./*
|
||||
- name: Create Release
|
||||
-
|
||||
name: Create Release
|
||||
id: create_release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
|
@ -1,3 +0,0 @@
|
||||
module.exports = {
|
||||
presets: ["@vue/cli-plugin-babel/preset"],
|
||||
};
|
@ -152,7 +152,7 @@ services:
|
||||
# background: red # optional color for card to set color directly without custom stylesheet
|
||||
```
|
||||
|
||||
View [Custom Services](customservices.md) for details about all available custom services (like PiHole) and how to configure them.
|
||||
View **[Custom Services](customservices.md)** for details about all available custom services (like `PiHole`) and how to configure them.
|
||||
|
||||
If you choose to fetch message information from an endpoint, the output format should be as follows (or you can [custom map fields as shown in tips-and-tricks](./tips-and-tricks.md#mapping-fields)):
|
||||
|
||||
@ -180,27 +180,4 @@ You can read the [bulma modifiers page](https://bulma.io/documentation/modifiers
|
||||
|
||||
## 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}
|
||||
```
|
||||
|
||||
## Supported services
|
||||
|
||||
Currently the following services are supported for showing quick infos on the card. They can be used by setting the type to one of the following values at the item.
|
||||
|
||||
- PiHole
|
||||
- AdGuardHome
|
||||
- PaperlessNG
|
||||
- Mealie
|
||||
|
||||
## Additional configuration
|
||||
|
||||
### Paperless
|
||||
|
||||
For Paperless you need an API-Key which you have to store at the item in the field `apikey`.
|
||||
|
||||
### Mealie
|
||||
|
||||
First off make sure to remove an existing `subtitle` as it will take precedence if set. Setting `type: "Mealie"` will then show the number of recipes Mealie is keeping organized or the planned meal for today if one is planned. You will have to set an API key in the field `apikey` which can be created in your Mealie installation.
|
||||
See icons documentation [here](https://github.com/bastienwirtz/homer/blob/main/public/assets/icons/README.md).
|
||||
|
@ -19,6 +19,7 @@ within Homer:
|
||||
+ [Emby / Jellyfin](#emby--jellyfin)
|
||||
+ [Uptime Kuma](#uptime-kuma)
|
||||
+ [Tautulli](#tautulli)
|
||||
+ [Mealie](#mealie)
|
||||
+ [Healthchecks](#healthchecks)
|
||||
|
||||
If you experiencing any issue, please have a look to the [troubleshooting](troubleshooting.md) page.
|
||||
@ -225,6 +226,11 @@ endpoint pointing to Tautulli!
|
||||
apikey: "MY-SUPER-SECRET-API-KEY"
|
||||
```
|
||||
|
||||
## Mealie
|
||||
|
||||
First off make sure to remove an existing `subtitle` as it will take precedence if set.
|
||||
Setting `type: "Mealie"` will then show the number of recipes Mealie is keeping organized or the planned meal for today if one is planned. You will have to set an API key in the field `apikey` which can be created in your Mealie installation.
|
||||
|
||||
## Healthchecks
|
||||
|
||||
This service displays information about the configured status checks from the Healthchecks application.
|
||||
|
@ -5,11 +5,11 @@ If you want to contribute to Homer, please read the [contributing guidelines](ht
|
||||
```sh
|
||||
# Using yarn (recommended)
|
||||
yarn install
|
||||
yarn serve
|
||||
yarn dev
|
||||
|
||||
# **OR** Using npm
|
||||
npm install
|
||||
npm run serve
|
||||
npm run dev
|
||||
```
|
||||
|
||||
## Custom services
|
||||
|
15
index.html
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="assets/icons/favicon.ico" />
|
||||
<link rel="apple-touch-icon" href="assets/icons/apple-touch-icon.png" sizes="180x180">
|
||||
<link rel="mask-icon" href="assets/icons/logo.svg">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
|
||||
<title>Homer</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-mount"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -8,4 +8,4 @@ server.document-root = "/www"
|
||||
alias.url = ( env.SUBFOLDER => "/www" )
|
||||
server.indexfiles = ("index.html")
|
||||
server.follow-symlink = "enable"
|
||||
server.feature-flags += ( "server.clock-jump-restart" => 0 )
|
||||
server.feature-flags += ( "server.clock-jump-restart" => 0 )
|
||||
|
36
package.json
@ -1,35 +1,29 @@
|
||||
{
|
||||
"name": "homer",
|
||||
"version": "21.09.1",
|
||||
"version": "22.07.2",
|
||||
"scripts": {
|
||||
"serve": "vue-cli-service serve",
|
||||
"build": "vue-cli-service build",
|
||||
"lint": "vue-cli-service lint"
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview --port 5050",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.1.1",
|
||||
"bulma": "^0.9.4",
|
||||
"core-js": "^3.22.7",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"register-service-worker": "^1.7.2",
|
||||
"vue": "^2.6.14"
|
||||
"vue": "^3.2.33"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.19",
|
||||
"@vue/cli-plugin-eslint": "~4.5.19",
|
||||
"@vue/cli-plugin-pwa": "~4.5.19",
|
||||
"@vue/cli-service": "~4.5.19",
|
||||
"@vue/eslint-config-prettier": "^6.0.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"prettier": "^2.2.1",
|
||||
"raw-loader": "^4.0.2",
|
||||
"sass": "^1.26.5",
|
||||
"sass-loader": "^8.0.2",
|
||||
"vue-template-compiler": "^2.6.12"
|
||||
"@rushstack/eslint-patch": "^1.1.0",
|
||||
"@vitejs/plugin-vue": "^2.3.1",
|
||||
"@vue/eslint-config-prettier": "^7.0.0",
|
||||
"eslint": "^8.5.0",
|
||||
"eslint-plugin-vue": "^9.2.0",
|
||||
"prettier": "^2.5.1",
|
||||
"sass": "^1.52.2",
|
||||
"vite": "^2.9.14",
|
||||
"vite-plugin-pwa": "^0.12.3"
|
||||
},
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
|
12
public/assets/icons/README.md
Normal file
@ -0,0 +1,12 @@
|
||||
# PWA Icons / Images
|
||||
|
||||
We suggest you to create a svg or png icon (if it is a png icon, with the maximum resolution possible) for your application and use it to generate a favicon package in [Favicon Generator](https://realfavicongenerator.net/).
|
||||
|
||||
Once generated, download the ZIP and use android-* icons for pwa-*:
|
||||
|
||||
- use `android-chrome-192x192.png` for `pwa-192x192.png`
|
||||
- use `android-chrome-512x512.png` for `pwa-512x512.png`
|
||||
- `apple-touch-icon.png` is `apple-touch-icon.png`
|
||||
- `favicon.ico` is `favicon.ico`
|
||||
|
||||
`
|
BIN
public/assets/icons/apple-touch-icon.png
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 790 B |
Before Width: | Height: | Size: 2.3 KiB |
BIN
public/assets/icons/favicon.ico
Normal file
After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 124 KiB |
1
public/assets/icons/logo.svg
Normal file
After Width: | Height: | Size: 5.8 KiB |
BIN
public/assets/icons/pwa-192x192.png
Normal file
After Width: | Height: | Size: 14 KiB |
BIN
public/assets/icons/pwa-512x512.png
Normal file
After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 6.7 KiB |
@ -1,42 +0,0 @@
|
||||
{
|
||||
"name": "Homer Dashboard",
|
||||
"short_name": "Homer",
|
||||
"theme_color": "#3367D6",
|
||||
"start_url": "../",
|
||||
"icons": [
|
||||
{
|
||||
"src": "./icons/favicon-16x16.png",
|
||||
"sizes": "16x16",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./icons/favicon-32x32.png",
|
||||
"sizes": "32x32",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "./icons/icon-any.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0,viewport-fit=cover">
|
||||
<meta name="robots" content="noindex">
|
||||
<link rel="icon" href="<%= BASE_URL %>favicon.png">
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
|
||||
</noscript>
|
||||
<div id="app"></div>
|
||||
<!-- built files will be auto injected -->
|
||||
</body>
|
||||
</html>
|
BIN
public/logo.png
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 27 KiB |
@ -1,2 +0,0 @@
|
||||
User-agent: *
|
||||
Disallow:
|
22
src/App.vue
@ -49,10 +49,10 @@
|
||||
<SearchInput
|
||||
class="navbar-item is-inline-block-mobile"
|
||||
:hotkey="searchHotkey()"
|
||||
@input="filterServices"
|
||||
@input="filterServices($event.target?.value)"
|
||||
@search-focus="showMenu = true"
|
||||
@search-open="navigateToFirstService"
|
||||
@search-cancel="filterServices"
|
||||
@search-open="navigateToFirstService($event?.target?.value)"
|
||||
@search-cancel="filterServices()"
|
||||
/>
|
||||
</Navbar>
|
||||
</div>
|
||||
@ -140,8 +140,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const jsyaml = require("js-yaml");
|
||||
const merge = require("lodash.merge");
|
||||
import jsyaml from "js-yaml";
|
||||
import merge from "lodash.merge";
|
||||
|
||||
import Navbar from "./components/Navbar.vue";
|
||||
import GetStarted from "./components/GetStarted.vue";
|
||||
@ -153,7 +153,7 @@ import SettingToggle from "./components/SettingToggle.vue";
|
||||
import DarkMode from "./components/DarkMode.vue";
|
||||
import DynamicTheme from "./components/DynamicTheme.vue";
|
||||
|
||||
import defaultConfig from "./assets/defaults.yml";
|
||||
import defaultConfig from "./assets/defaults.yml?raw";
|
||||
|
||||
export default {
|
||||
name: "App",
|
||||
@ -255,11 +255,12 @@ export default {
|
||||
});
|
||||
},
|
||||
matchesFilter: function (item) {
|
||||
const needle = this.filter?.toLowerCase();
|
||||
return (
|
||||
item.name.toLowerCase().includes(this.filter) ||
|
||||
(item.subtitle && item.subtitle.toLowerCase().includes(this.filter)) ||
|
||||
(item.tag && item.tag.toLowerCase().includes(this.filter)) ||
|
||||
(item.keywords && item.keywords.toLowerCase().includes(this.filter))
|
||||
item.name.toLowerCase().includes(needle) ||
|
||||
(item.subtitle && item.subtitle.toLowerCase().includes(needle)) ||
|
||||
(item.tag && item.tag.toLowerCase().includes(needle)) ||
|
||||
(item.keywords && item.keywords.toLowerCase().includes(needle))
|
||||
);
|
||||
},
|
||||
navigateToFirstService: function (target) {
|
||||
@ -271,6 +272,7 @@ export default {
|
||||
}
|
||||
},
|
||||
filterServices: function (filter) {
|
||||
console.log(filter);
|
||||
this.filter = filter;
|
||||
|
||||
if (!filter) {
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
@import "./webfonts/webfonts.scss";
|
||||
|
||||
@import "bulma";
|
||||
@import "../../node_modules/bulma/bulma";
|
||||
|
||||
// Themes import
|
||||
@import "./themes/sui.scss";
|
||||
@ -13,7 +13,7 @@
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
html, body, body #app {
|
||||
html, body, body #app-mount, body #app {
|
||||
height: 100%;
|
||||
background-color: var(--background);
|
||||
}
|
||||
|
@ -56,7 +56,9 @@ export default {
|
||||
|
||||
// extra check to make sure we're not offline
|
||||
let that = this;
|
||||
const aliveCheckUrl = window.location.href + "?t=" + new Date().valueOf();
|
||||
const aliveCheckUrl = `${window.location.origin}${
|
||||
window.location.pathname
|
||||
}/index.html?t=${new Date().valueOf()}`;
|
||||
return fetch(aliveCheckUrl, {
|
||||
method: "HEAD",
|
||||
cache: "no-store",
|
||||
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<a
|
||||
v-on:click="toggleTheme()"
|
||||
@click="toggleTheme()"
|
||||
aria-label="Toggle dark mode"
|
||||
class="navbar-item is-inline-block-mobile"
|
||||
>
|
||||
|
@ -47,7 +47,6 @@ export default {
|
||||
}
|
||||
if (this.item.url) {
|
||||
let fetchedMessage = await this.downloadMessage(this.item.url);
|
||||
console.log("done");
|
||||
if (this.item.mapping) {
|
||||
fetchedMessage = this.mapRemoteMessage(fetchedMessage);
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ export default {
|
||||
this.$emit("input", value.toLowerCase());
|
||||
},
|
||||
},
|
||||
beforeDestroy() {
|
||||
beforeUnmount() {
|
||||
document.removeEventListener("keydown", this._keyListener);
|
||||
},
|
||||
};
|
||||
|
@ -1,8 +1,9 @@
|
||||
<template>
|
||||
<component v-bind:is="component" :item="item" :proxy="proxy"></component>
|
||||
<component :is="component" :item="item" :proxy="proxy"></component>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { defineAsyncComponent } from "vue";
|
||||
import Generic from "./services/Generic.vue";
|
||||
|
||||
export default {
|
||||
@ -17,7 +18,7 @@ export default {
|
||||
if (type === "Generic") {
|
||||
return Generic;
|
||||
}
|
||||
return () => import(`./services/${type}.vue`);
|
||||
return defineAsyncComponent(() => import(`./services/${type}.vue`));
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,5 +1,8 @@
|
||||
<template>
|
||||
<a v-on:click="toggleSetting()" class="navbar-item is-inline-block-mobile">
|
||||
<a
|
||||
@click.prevent="toggleSetting()"
|
||||
class="navbar-item is-inline-block-mobile"
|
||||
>
|
||||
<span><i :class="['fas', 'fa-fw', value ? icon : secondaryIcon]"></i></span>
|
||||
<slot></slot>
|
||||
</a>
|
||||
|
@ -22,7 +22,7 @@
|
||||
<div v-else>
|
||||
<p class="title is-4">{{ name }}</p>
|
||||
<p class="subtitle is-6">
|
||||
{{ temp | tempSuffix(this.item.units) }}
|
||||
{{ temperature }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -50,6 +50,19 @@ export default {
|
||||
conditions: null,
|
||||
error: false,
|
||||
}),
|
||||
computed: {
|
||||
temperature: function () {
|
||||
if (!this.temp) return "";
|
||||
|
||||
let unit = "K";
|
||||
if (this.item.units === "metric") {
|
||||
unit = "°C";
|
||||
} else if (this.item.units === "imperial") {
|
||||
unit = "°F";
|
||||
}
|
||||
return `${this.temp} ${unit}`;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchWeather();
|
||||
},
|
||||
@ -86,19 +99,6 @@ export default {
|
||||
});
|
||||
},
|
||||
},
|
||||
filters: {
|
||||
tempSuffix: function (value, type) {
|
||||
if (!value) return "";
|
||||
|
||||
let unit = "K";
|
||||
if (type === "metric") {
|
||||
unit = "°C";
|
||||
} else if (type === "imperial") {
|
||||
unit = "°F";
|
||||
}
|
||||
return `${value} ${unit}`;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
@ -99,6 +99,7 @@ export default {
|
||||
},
|
||||
},
|
||||
created() {
|
||||
/* eslint-disable */
|
||||
this.item.url = `${this.item.url}/status/${this.dashboard}`;
|
||||
this.fetchStatus();
|
||||
},
|
||||
|
16
src/main.js
@ -1,19 +1,13 @@
|
||||
import Vue from "vue";
|
||||
import { createApp, h } from "vue";
|
||||
import App from "./App.vue";
|
||||
import "./registerServiceWorker";
|
||||
|
||||
import "@fortawesome/fontawesome-free/css/all.css";
|
||||
|
||||
import "./assets/app.scss";
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
const app = createApp(App);
|
||||
|
||||
Vue.component("DynamicStyle", {
|
||||
render: function (createElement) {
|
||||
return createElement("style", this.$slots.default);
|
||||
},
|
||||
app.component("DynamicStyle", (_props, context) => {
|
||||
return h("style", {}, context.slots);
|
||||
});
|
||||
|
||||
new Vue({
|
||||
render: (h) => h(App),
|
||||
}).$mount("#app");
|
||||
app.mount("#app-mount");
|
||||
|
@ -1,34 +0,0 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from "register-service-worker";
|
||||
|
||||
if (process.env.NODE_ENV === "production") {
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
console.log(
|
||||
"App is being served from cache by a service worker.\n" +
|
||||
"For more details, visit https://goo.gl/AFskqB"
|
||||
);
|
||||
},
|
||||
registered() {
|
||||
console.log("Service worker has been registered.");
|
||||
},
|
||||
cached() {
|
||||
console.log("Content has been cached for offline use.");
|
||||
},
|
||||
updatefound() {
|
||||
console.log("New content is downloading.");
|
||||
},
|
||||
updated() {
|
||||
console.log("New content is available; please refresh.");
|
||||
},
|
||||
offline() {
|
||||
console.log(
|
||||
"No internet connection found. App is running in offline mode."
|
||||
);
|
||||
},
|
||||
error(error) {
|
||||
console.error("Error during service worker registration:", error);
|
||||
},
|
||||
});
|
||||
}
|
44
vite.config.js
Normal file
@ -0,0 +1,44 @@
|
||||
import { VitePWA } from "vite-plugin-pwa";
|
||||
import { fileURLToPath, URL } from "url";
|
||||
|
||||
import { defineConfig } from "vite";
|
||||
import vue from "@vitejs/plugin-vue";
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: "",
|
||||
build: {
|
||||
assetsDir: "resources",
|
||||
},
|
||||
plugins: [
|
||||
vue(),
|
||||
VitePWA({
|
||||
registerType: "autoUpdate",
|
||||
useCredentials: true,
|
||||
manifestFilename: "assets/manifest.json",
|
||||
manifest: {
|
||||
name: "Homer dashboard",
|
||||
short_name: "Homer",
|
||||
description: "Home Server Dashboard",
|
||||
theme_color: "#3367D6",
|
||||
icons: [
|
||||
{
|
||||
src: "./icons/pwa-192x192.png",
|
||||
sizes: "192x192",
|
||||
type: "image/png",
|
||||
},
|
||||
{
|
||||
src: "./icons/pwa-512x512.png",
|
||||
sizes: "512x512",
|
||||
type: "image/png",
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
"@": fileURLToPath(new URL("./src", import.meta.url)),
|
||||
},
|
||||
},
|
||||
});
|
@ -1,32 +0,0 @@
|
||||
const manifestOptions = require("./public/assets/manifest.json");
|
||||
|
||||
module.exports = {
|
||||
chainWebpack: (config) => {
|
||||
config.module
|
||||
.rule("yaml")
|
||||
.test(/\.ya?ml$/)
|
||||
.use("raw-loader")
|
||||
.loader("raw-loader")
|
||||
.end();
|
||||
},
|
||||
publicPath: "",
|
||||
pwa: {
|
||||
manifestPath: "assets/manifest.json",
|
||||
manifestCrossorigin: "use-credentials",
|
||||
appleMobileWebAppStatusBarStyle: "black",
|
||||
appleMobileWebAppCapable: "yes",
|
||||
name: manifestOptions.name,
|
||||
themeColor: manifestOptions.theme_color,
|
||||
manifestOptions,
|
||||
iconPaths: {
|
||||
favicon32: "assets/icons/favicon-32x32.png",
|
||||
favicon16: "assets/icons/favicon-16x16.png",
|
||||
appleTouchIcon: "assets/icons/icon-maskable.png",
|
||||
maskIcon: "assets/icons/safari-pinned-tab.svg",
|
||||
msTileImage: "assets/icons/icon-any.png",
|
||||
},
|
||||
},
|
||||
devServer: {
|
||||
disableHostCheck: true,
|
||||
},
|
||||
};
|