🔀 Merge pull request #47 from Lissy93/FEATURE_better-icons

[FEARURE] More icon options. Also fixes #14 and fixes #46
This commit is contained in:
Alicia Sykes 2021-06-21 19:42:48 +01:00 committed by GitHub
commit b11abac422
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 117 additions and 23 deletions

View File

@ -53,6 +53,12 @@
You will need [Docker](https://docs.docker.com/get-docker/) installed on your system
```
docker run -p 8080:80 lissy93/dashy
```
Or
```docker
docker run -d \
-p 4000:80 \
@ -123,6 +129,20 @@ You can also apply custom CSS overrides directly through the UI (Under Config me
---
## Icons 🧸
> For full iconography documentation, see: [**Icons**](./docs/icons.md)
Both sections and items can have an icon associated with them, and defined under the `icon` attribute. There are many options for icons, including Font Awesome support, automatic fetching from favicon, programmatically generated icons and of course URLs.
<p align="center">
<img width="400" src="https://i.ibb.co/GTVmZnc/dashy-example-icons.png" />
</p>
If icon is set to `favicon`, then it will be automatically fetched from the URL of the corresponding application. To use any font-awesome icon, specify the category, followed by the icon name, e.g. `fas fa-rocket`, `fab fa-monero` or `fas fa-unicorn`, you can also use Pro icons, by setting your API key under `appConfig.fontAwesomeKey`. If the icon is set to `generative`, then a unique icon is generated from the apps URL or IP. You can also host an icon either locally or using any CDN service, and pass it's URL into the `icon` attribute, e.g. `https://i.ibb.co/710B3Yc/space-invader-x256.png`. To use a local image, store it in `./public/item-icons/` (or `-v /app/public/item-icons/` in Docker) , and reference it by name and extension - e.g. set `icon: image.png` to use `./public/item-icon/image.png`, you can also use sub-folders here if you have a lot of icons, to keep them organised.
---
## Cloud Backup & Sync ☁
> For full backup documentation, see: [**Cloud Backup & Sync**](./docs/backup-restore.md)
@ -231,6 +251,7 @@ For more general questions about any of the technologies used, [StackOverflow](h
- [Troubleshooting](/docs/troubleshooting.md)
- [Backup & Restore](/docs/backup-restore.md)
- [Theming](/docs/theming.md)
- [Icons](/docs/icons.md)
- [Authentication](/docs/authentication.md)
**[⬆️ Back to Top](#dashy)**

View File

@ -58,6 +58,7 @@ All fields are optional, unless otherwise stated.
**`backgroundImg`** | `string` | _Optional_ | Path to an optional full-screen app background image. This can be either remote (http) or local (/). Note that this will slow down initial load
**`enableFontAwesome`** | `boolean` | _Optional_ | Where `true` is enabled, if left blank font-awesome will be enabled only if required by 1 or more icons
**`fontAwesomeKey`** | `string` | _Optional_ | If you have a font-awesome key, then you can use it here and make use of premium icons. It is a 10-digit alpha-numeric string from you're FA kit URL (e.g. `13014ae648`)
**`faviconApi`** | `string` | _Optional_ | Which service to use to resolve favicons. Set to `local` to do this locally, without using an API. Available options are: `local`, `faviconkit`, `google`, `clearbit`, `webmasterapi` and `allesedv`. Defaults to `faviconkit`. See [Icons](/docs/icons.md#favicons) for more info
**`layout`** | `string` | _Optional_ | App layout, either `horizontal`, `vertical`, `auto` or `sidebar`. Defaults to `auto`. This specifies the layout and direction of how sections are positioned on the home screen. This can also be modified from the UI.
**`iconSize`** | `string` | _Optional_ | The size of link items / icons. Can be either `small`, `medium,` or `large`. Defaults to `medium`. This can also be set directly from the UI.
**`theme`** | `string` | _Optional_ | The default theme for first load (you can change this later from the UI)
@ -125,7 +126,7 @@ All fields are optional, unless otherwise stated.
**Field** | **Type** | **Required**| **Description**
--- | --- | --- | ---
**`icon`** | `string` | _Optional_ | The icon for a given item or section. Can be a font-awesome icon, favicon, remote URL or local URL. If set to `favicon`, the icon will be automatically fetched from the items website URL. To use font-awesome, specify the category, followed by the icon name, e.g. `fas fa-rocket`, `fab fa-monero` or `fal fa-duck` - note that to use pro icons, you mut specify `appConfig.fontAwesomeKey`. You can also use hosted any by specifying it's URL, e.g. `https://i.ibb.co/710B3Yc/space-invader-x256.png`. To use a local image, first store it in `./public/item-icons/` (or `-v /app/public/item-icons/` in Docker) , and reference it by name and extension - e.g. set `image.png` to use `./public/item-icon/image.png`, you can also use sub-folders if you have a lot of icons, to keep them organised.
**`icon`** | `string` | _Optional_ | The icon for a given item or section. Can be a font-awesome icon, favicon, remote URL or local URL. If set to `favicon`, the icon will be automatically fetched from the items website URL. To use font-awesome, specify the category, followed by the icon name, e.g. `fas fa-rocket`, `fab fa-monero` or `fal fa-duck` - note that to use pro icons, you mut specify `appConfig.fontAwesomeKey`. If set to `generative`, then a unique icon is generated from the apps URL or IP. You can also use hosted any by specifying it's URL, e.g. `https://i.ibb.co/710B3Yc/space-invader-x256.png`. To use a local image, first store it in `./public/item-icons/` (or `-v /app/public/item-icons/` in Docker) , and reference it by name and extension - e.g. set `image.png` to use `./public/item-icon/image.png`, you can also use sub-folders if you have a lot of icons, to keep them organised.
**[⬆️ Back to Top](#configuring)**

43
docs/icons.md Normal file
View File

@ -0,0 +1,43 @@
## Icons
Both sections and items can have an icon, which is specified using the `icon` attribute. Using icons improves the aesthetics of your UI and makes the app more intuitive to use. There are several options when it comes to setting icons, and this article outlines each of them
- [Font Awesome Icons](#font-awesome)
- [Favicons](#favicons)
- [Generative Icons](#generative-icons)
- [Icons by URL](#icons-by-url)
- [Local Icons](#local-icons)
- [No Icon](#no-icon)
### Font Awesome
You can use any [Font Awesome Icon](https://fontawesome.com/icons) simply by specifying it's identifier. This is in the format of `[category] [name]` and can be found on the page for any given icon on the Font Awesome site. For example: `fas fa-rocket`, `fab fa-monero` or `fas fa-unicorn`.
Font-Awesome has a wide variety of free icons, but you can also use their pro icons if you have a membership. To do so, you need to specify your license key under: `appConfig.fontAwesomeKey`. This is usually a 10-digit string, for example `13014ae648`.
### Favicons
Dashy can auto-fetch the favicon for a given service using it's URL. Just set `icon: favicon` to use this feature. If the services URL is a local IP, then Dashy will attempt to find the favicon from `http://[ip]/favicon.ico`. This has two issues, favicons are not always hosted at the same location for every service, and often the default favicon is a low resolution. Therefore to fix this, for remote services an API is used to return a high-quality icon for any online service.
The default favicon API is [Favicon Kit](https://faviconkit.com/), a free and reliable service for returning images from any given URL. However several other API's are supported. To change the API used, under `appConfig`, set `faviconApi` to one of the following values:
- `faviconkit` - [faviconkit.com](https://faviconkit.com/) (Recommend)
- `google` - Official Google favicon API service, good support for all sites, but poor quality
- `clearbit` - [Clearbit](https://clearbit.com/logo) returns high-quality logos from mainstream websites
- `webmasterapi` - [WebMasterAPI](https://www.webmasterapi.com/get-favicons)
- `allesedv` - [allesedv.com](https://favicon.allesedv.com/) is a highly efficient IPv6-enabled service
You can also force Dashy to always get favicons from the root of the domain, and not use an external service, by setting `appConfig.faviconApi` to `local`.
### Generative Icons
Uses a unique and programmatically generated icon for a given service. This is particularly useful when you have a lot of similar services with a different IP or port, and no specific icon. These icons are generated with [ipsicon.io](https://ipsicon.io/). To use this option, just set an item's to: `icon: generative`.
### Icons by URL
You can also set an icon by passing in a valid URL pointing to the icons location. For example `icon: https://i.ibb.co/710B3Yc/space-invader-x256.png`, this can be in .png, .jpg or .svg format, and hosted anywhere- so long as it's accessible from where you are hosting Dashy. The icon will be automatically scaled to fit, however loading in a lot of large icons may have a negative impact on performance, especially if you visit Dashy from new devices often.
### Local Icons
You may also want to store your icons locally, bundled within Dashy so that there is no reliance on outside services. This can be done by putting the icons within Dashy's ./public/item-icons/` directory. If you are using Docker, then the easiest option is to map a volume from your host system, for example: `-v /local/image/directory:/app/public/item-icons/`. To reference an icon stored locally, just specify it's name and extension. For example, if my icon was stored in `/app/public/item-icons/maltrail.png`, then I would just set `icon: maltrail.png`.
You can also use sub-folders within the `item-icons` directory to keep things organised. You would then specify an icon with it's folder name slash image name. For example: `networking/monit.png`
### No Icon
If you don't wish for a given item or section to have an icon, just leave out the `icon` attribute.

View File

@ -9,4 +9,5 @@
- [Backup & Restore](/docs/backup-restore.md)
- [Status Indicators](/docs/status-indicators.md)
- [Theming](/docs/theming.md)
- [Icons](/docs/icons.md)
- [Authentication](/docs/authentication.md)

View File

@ -3,7 +3,7 @@
<TabItem name="Config" class="main-tab">
<div class="main-options-container">
<h2>Configuration Options</h2>
<a href="/conf.yml" download class="hyperlink-wrapper">
<a class="hyperlink-wrapper" @click="downloadConfigFile('conf.yml', yaml)">
<button class="config-button center">
<DownloadIcon class="button-icon"/>
Download Config
@ -13,10 +13,6 @@
<EditIcon class="button-icon"/>
Edit Config
</button>
<button class="config-button center" @click="goToMetaEdit()">
<MetaDataIcon class="button-icon"/>
Edit Meta Data
</button>
<button class="config-button center" @click="goToCustomCss()">
<CustomCssIcon class="button-icon"/>
Edit Custom CSS
@ -59,9 +55,6 @@
<TabItem name="Edit Config">
<JsonEditor :config="config" />
</TabItem>
<TabItem name="Edit Site Meta">
<EditSiteMeta :config="config" />
</TabItem>
<TabItem name="Custom Styles">
<CustomCssEditor :config="config" initialCss="hello" />
</TabItem>
@ -76,7 +69,6 @@ import 'highlight.js/styles/mono-blue.css';
import JsonToYaml from '@/utils/JsonToYaml';
import { localStorageKeys, modalNames } from '@/utils/defaults';
import EditSiteMeta from '@/components/Configuration/EditSiteMeta';
import JsonEditor from '@/components/Configuration/JsonEditor';
import CustomCssEditor from '@/components/Configuration/CustomCss';
import RebuildApp from '@/components/Configuration/RebuildApp';
@ -84,7 +76,6 @@ import RebuildApp from '@/components/Configuration/RebuildApp';
import DownloadIcon from '@/assets/interface-icons/config-download-file.svg';
import DeleteIcon from '@/assets/interface-icons/config-delete-local.svg';
import EditIcon from '@/assets/interface-icons/config-edit-json.svg';
import MetaDataIcon from '@/assets/interface-icons/config-meta-data.svg';
import CustomCssIcon from '@/assets/interface-icons/config-custom-css.svg';
import CloudIcon from '@/assets/interface-icons/cloud-backup-restore.svg';
import RebuildIcon from '@/assets/interface-icons/application-rebuild.svg';
@ -109,7 +100,6 @@ export default {
},
},
components: {
EditSiteMeta,
JsonEditor,
CustomCssEditor,
RebuildApp,
@ -117,7 +107,6 @@ export default {
DeleteIcon,
EditIcon,
CloudIcon,
MetaDataIcon,
CustomCssIcon,
RebuildIcon,
},
@ -156,7 +145,7 @@ export default {
localStorage.clear();
this.$toasted.show('Data cleared succesfully');
setTimeout(() => {
location.reload(); // eslint-disable-line no-restricted-globals
location.reload(true); // eslint-disable-line no-restricted-globals
}, 1900);
}
},

View File

@ -11,7 +11,7 @@
tabIndex="-1"
>
<label :for="`collapsible-${uniqueKey}`" class="lbl-toggle" tabindex="-1">
<Icon v-if="icon" :icon="icon" size="small" class="section-icon" />
<Icon v-if="icon" :icon="icon" size="small" :url="title" class="section-icon" />
<h3>{{ title }}</h3>
</label>
<div class="collapsible-content">

View File

@ -11,9 +11,11 @@
<script>
import BrokenImage from '@/assets/interface-icons/broken-icon.svg';
import ErrorHandler from '@/utils/ErrorHandler';
import { faviconApi as defaultFaviconApi, faviconApiEndpoints } from '@/utils/defaults';
export default {
name: 'Icon',
inject: ['config'],
props: {
icon: String, // Path to icon asset
url: String, // Used for fetching the favicon
@ -33,6 +35,7 @@ export default {
data() {
return {
broken: false,
// faviconApi: this.config.appConfig.faviconApi || defaultFaviconApi,
};
},
methods: {
@ -51,26 +54,36 @@ export default {
},
/* Get favicon URL, for items which use the favicon as their icon */
getFavicon(fullUrl) {
const isLocalIP = /(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(::1$)|([fF][cCdD])|(localhost)/;
if (isLocalIP.test(fullUrl)) { // Check if using a local IP format or localhost
if (this.shouldUseDefaultFavicon(fullUrl)) { // Check if we should use local icon
const urlParts = fullUrl.split('/');
// For locally running services, use the default path for favicon
if (urlParts.length >= 2) return `${urlParts[0]}/${urlParts[1]}/${urlParts[2]}/favicon.ico`;
} else if (fullUrl.includes('http')) {
// For publicly accessible sites, a more reliable method is using Google's API
return `https://s2.googleusercontent.com/s2/favicons?domain=${fullUrl}`;
} else if (fullUrl.includes('http')) { // Service is running publicly
const host = this.getHostName(fullUrl);
const faviconApi = this.config.appConfig.faviconApi || defaultFaviconApi;
const endpoint = faviconApiEndpoints[faviconApi];
return endpoint.replace('$URL', host);
}
return '';
},
/* If using favicon for icon, and if service is running locally (determined by local IP) */
/* or if user prefers local favicon, then return true */
shouldUseDefaultFavicon(fullUrl) {
const isLocalIP = /(127\.)|(192\.168\.)|(10\.)|(172\.1[6-9]\.)|(172\.2[0-9]\.)|(172\.3[0-1]\.)|(::1$)|([fF][cCdD])|(localhost)/;
return (isLocalIP.test(fullUrl) || this.config.appConfig.faviconApi === 'local');
},
getLocalImagePath(img) {
return `/item-icons/${img}`;
},
getGenerativeIcon(url) {
return `https://ipsicon.io/${this.getHostName(url)}.svg`;
},
/* Checks if the icon is from a local image, remote URL, SVG or font-awesome */
getIconPath(img, url) {
switch (this.determineImageType(img)) {
case 'url': return img;
case 'img': return this.getLocalImagePath(img);
case 'favicon': return this.getFavicon(url);
case 'generative': return this.getGenerativeIcon(url);
case 'svg': return img;
default: return '';
}
@ -84,9 +97,13 @@ export default {
else if (this.isImage(img)) imgType = 'img';
else if (img.includes('fa-')) imgType = 'font-awesome';
else if (img === 'favicon') imgType = 'favicon';
else if (img === 'generative') imgType = 'generative';
else imgType = 'none';
return imgType;
},
getHostName(url) {
try { return new URL(url).hostname; } catch (e) { return url; }
},
/* Called when the path to the image cannot be resolved */
imageNotFound() {
this.broken = true;

View File

@ -90,7 +90,7 @@ export default {
registerLogout();
this.$toasted.show('Logged Out');
setTimeout(() => {
location.reload(); // eslint-disable-line no-restricted-globals
location.reload(true); // eslint-disable-line no-restricted-globals
}, 100);
},
isUserLoggedIn() {

View File

@ -69,6 +69,18 @@
"pattern": "^[a-z0-9]{10}$",
"description": "API key for font-awesome"
},
"faviconApi": {
"enum": [
"local",
"faviconkit",
"google",
"clearbit",
"webmasterapi",
"allesedv"
],
"default": "faviconkit",
"description": "Which service to use to resolve favicons. Set to local to do this locally instead"
},
"layout": {
"enum": [
"horizontal",
@ -263,7 +275,7 @@
"icon": {
"type": "string",
"nullable": true,
"description": "An icon, either as a font-awesome identifier, local or remote URL, or auto-fetched favicon"
"description": "An icon, either as a font-awesome identifier, local or remote URL, or the word favicon or generative"
},
"url": {
"type": "string",

View File

@ -13,6 +13,7 @@ module.exports = {
layout: 'auto',
theme: 'default',
fontAwesomeKey: '0821c65656',
faviconApi: 'faviconkit',
builtInThemes: [
'callisto',
'thebe',
@ -81,4 +82,13 @@ module.exports = {
metaTagData: [
{ name: 'description', content: 'A simple static homepage for you\'re server' },
],
faviconApiEndpoints: {
mcapi: 'https://eu.mc-api.net/v3/server/favicon/$URL',
clearbit: 'https://logo.clearbit.com/$URL',
faviconkit: 'https://api.faviconkit.com/$URL/64',
// favicongrabber: 'https://favicongrabber.com//api/grab/$URL',
google: 'https://www.google.com/s2/favicons?sz=128&domain_url=$URL',
allesedv: 'https://f1.allesedv.com/128/$URL',
webmasterapi: 'https://api.webmasterapi.com/v1/favicon/yEwx0ZFs0CSPshHq/$URL',
},
};