🔀 Merge pull request #76 from Lissy93/FEATURE_support-emoji-icons

Emojis are now supported as item and section icons 🥳
This commit is contained in:
Alicia Sykes 2021-07-03 19:56:00 +01:00 committed by GitHub
commit 702b69db2a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1992 additions and 4 deletions

View File

@ -168,6 +168,7 @@ Both sections and items can have an icon associated with them, and defined under
- **Favicon**: Set `icon: favicon` to fetch a services icon automatically from the URL of the corresponding application
- **Font-Awesome**: To use any font-awesome icon, specify the category, followed by the icon name, e.g. `fas fa-rocket` or `fab fa-monero`. You can also use Pro icons if you have a license key, just set it under `appConfig.fontAwesomeKey`
- **Generative**: Setting `icon: generative`, will generate a unique for a given service, based on it's URL or IP
- **Emoji**: Use an emoji as a tile icon, by putting the emoji's code as the icon attribute. Emojis can be specified either as emojis (`🚀`), unicode (`'U+1F680'`) or shortcode (`':rocket:'`).
- **URL**: You can also pass in a URL to an icon asset, hosted either locally or using any CDN service. E.g. `icon: https://i.ibb.co/710B3Yc/space-invader-x256.png`.
- **Local Image**: To use a local image, store it in `./public/item-icons/` (or create a volume in Docker: `-v /local/image/directory:/app/public/item-icons/`) , 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 organized.

View File

@ -3,14 +3,15 @@
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)
- [Auto-Fetched Favicons](#favicons)
- [Generative Icons](#generative-icons)
- [Emoji Icons](#emoji-icons)
- [Icons by URL](#icons-by-url)
- [Local Icons](#local-icons)
- [No Icon](#no-icon)
<p align="center">
<img width="400" src="https://i.ibb.co/GTVmZnc/dashy-example-icons.png" />
<img width="500" src="https://i.ibb.co/GTVmZnc/dashy-example-icons.png" />
</p>
### Font Awesome
@ -18,10 +19,17 @@ You can use any [Font Awesome Icon](https://fontawesome.com/icons) simply by spe
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`.
<p align="center">
<img width="580" src="https://i.ibb.co/pdrw8J4/fontawesome-icons2.png" />
</p>
### 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.
<p align="center">
<img width="580" src="https://i.ibb.co/k6wyhnB/favicon-icons.png" />
</p>
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)
@ -35,6 +43,29 @@ You can also force Dashy to always get favicons from the root of the domain, and
### 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`.
<p align="center">
<img width="400" src="https://i.ibb.co/qrNNNcm/generative-icons.png" />
</p>
### Emoji Icons
You can use almost any emoji as an icon for items or sections. You can specify the emoji either by pasting it directly, using it's unicode ( e.g. `'U+1F680'`) or shortcode (e.g. `':rocket:'`). You can find these codes for any emoji using [Emojipedia](https://emojipedia.org/) (near the bottom of emoji each page), or for a quick reference to emoji shortcodes, check out [emojis.ninja](https://emojis.ninja/) by @nomanoff.
<p align="center">
<img width="580" src="https://i.ibb.co/YLwgTf9/emoji-icons-1.png" />
</p>
The following example shows the unicode options available, all three will render the 🚀 emoji.
```yaml
items:
- title: Shortcode
icon: ':rocket:'
- title: Unicode
icon: 'U+1F680'
- title: Emoji
icon: 🚀
```
### 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.
@ -44,4 +75,4 @@ You may also want to store your icons locally, bundled within Dashy so that ther
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.
If you don't wish for a given item or section to have an icon, just leave out the `icon` attribute.

View File

@ -1,6 +1,7 @@
<template>
<div class="item-icon">
<i v-if="iconType === 'font-awesome'" :class="`${icon} ${size}`" ></i>
<i v-else-if="iconType === 'emoji'" :class="`emoji-icon ${size}`" >{{getEmoji(iconPath)}}</i>
<img v-else-if="icon" :src="iconPath" @error="imageNotFound"
:class="`tile-icon ${size} ${broken ? 'broken' : ''}`"
/>
@ -12,6 +13,8 @@
import BrokenImage from '@/assets/interface-icons/broken-icon.svg';
import ErrorHandler from '@/utils/ErrorHandler';
import { faviconApi as defaultFaviconApi, faviconApiEndpoints } from '@/utils/defaults';
import EmojiUnicodeRegex from '@/utils/EmojiUnicodeRegex';
import emojiLookup from '@/utils/emojis.json';
export default {
name: 'Icon',
@ -52,6 +55,27 @@ export default {
if (splitPath.length >= 1) return validImgExtensions.includes(splitPath[1]);
return false;
},
/* Determins if a given string is an emoji, and if so what type it is */
isEmoji(img) {
if (EmojiUnicodeRegex.test(img) && img.match(/./gu).length) { // Is a unicode emoji
return { isEmoji: true, emojiType: 'glyph' };
} else if (new RegExp(/^:.*:$/).test(img)) { // Is a shortcode emoji
return { isEmoji: true, emojiType: 'shortcode' };
} else if (img.substring(0, 2) === 'U+' && img.length === 7) {
return { isEmoji: true, emojiType: 'unicode' };
}
return { isEmoji: false, emojiType: '' };
},
/* Formats and gets emoji from unicode or shortcode */
getEmoji(emojiCode) {
const { emojiType } = this.isEmoji(emojiCode);
if (emojiType === 'shortcode') {
if (emojiLookup[emojiCode]) return emojiLookup[emojiCode];
} else if (emojiType === 'unicode') {
return String.fromCodePoint(parseInt(emojiCode.substr(2), 16));
}
return emojiCode; // Emoji is a glyph already, just return
},
/* Get favicon URL, for items which use the favicon as their icon */
getFavicon(fullUrl) {
if (this.shouldUseDefaultFavicon(fullUrl)) { // Check if we should use local icon
@ -85,6 +109,7 @@ export default {
case 'favicon': return this.getFavicon(url);
case 'generative': return this.getGenerativeIcon(url);
case 'svg': return img;
case 'emoji': return img;
default: return '';
}
},
@ -98,6 +123,7 @@ export default {
else if (img.includes('fa-')) imgType = 'font-awesome';
else if (img === 'favicon') imgType = 'favicon';
else if (img === 'generative') imgType = 'generative';
else if (this.isEmoji(img).isEmoji) imgType = 'emoji';
else imgType = 'none';
return imgType;
},
@ -144,7 +170,17 @@ export default {
fill: currentColor;
}
}
i.emoji-icon {
font-style: normal;
font-size: 2rem;
margin: 0.2rem;
&.small {
font-size: 1.5rem;
}
&.large {
font-size: 2.5rem;
}
}
.missing-image {
width: 3.5rem;
path {

View File

@ -0,0 +1 @@
module.exports = /(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|[\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|[\ud83c[\ude32-\ude3a]|[\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])/;

1919
src/utils/emojis.json Normal file

File diff suppressed because it is too large Load Diff