diff --git a/docs/icons.md b/docs/icons.md index e0ab48b1..01f071c3 100644 --- a/docs/icons.md +++ b/docs/icons.md @@ -80,7 +80,7 @@ sections: --- ## Generative Icons -To uses a unique and programmatically generated icon for a given service just set `icon: generative`. 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 [DiceBear](https://avatars.dicebear.com/), and use a hash of the services domain/ ip for entropy, so each domain will always have the same icon. +To uses a unique and programmatically generated icon for a given service just set `icon: generative`. 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 [DiceBear](https://avatars.dicebear.com/) (or [Evatar](https://evatar.io/) for fallback), and use a hash of the services domain/ ip for entropy, so each domain will have a unique icon.
diff --git a/src/components/LinkItems/ItemIcon.vue b/src/components/LinkItems/ItemIcon.vue
index f3c296e0..5e3a9667 100644
--- a/src/components/LinkItems/ItemIcon.vue
+++ b/src/components/LinkItems/ItemIcon.vue
@@ -49,12 +49,14 @@ export default {
},
/* Gets the icon path, dependent on icon type */
iconPath: function iconPath() {
+ if (this.broken) return this.getFallbackIcon();
return this.getIconPath(this.icon, this.url);
},
},
data() {
return {
broken: false, // If true, was unable to resolve icon
+ attemptedFallback: false,
};
},
methods: {
@@ -94,12 +96,12 @@ export default {
},
/* Get favicon URL, for items which use the favicon as their icon */
getFavicon(fullUrl, specificApi) {
- if (this.shouldUseDefaultFavicon(fullUrl)) { // Check if we should use local icon
+ const faviconApi = specificApi || this.appConfig.faviconApi || defaultFaviconApi;
+ if (this.shouldUseDefaultFavicon(fullUrl) || faviconApi === 'local') { // Check if we should use local icon
const urlParts = fullUrl.split('/');
if (urlParts.length >= 2) return `${urlParts[0]}/${urlParts[1]}/${urlParts[2]}/${iconCdns.faviconName}`;
} else if (fullUrl.includes('http')) { // Service is running publicly
const host = this.getHostName(fullUrl);
- const faviconApi = specificApi || this.appConfig.faviconApi || defaultFaviconApi;
const endpoint = faviconApiEndpoints[faviconApi];
return endpoint.replace('$URL', host);
}
@@ -130,9 +132,9 @@ export default {
return `${iconCdns.localPath}/${img}`;
},
/* Formats the URL for fetching the generative icons */
- getGenerativeIcon(url) {
+ getGenerativeIcon(url, cdn) {
const host = encodeURI(url) || Math.random().toString();
- return iconCdns.generative.replace('{icon}', asciiHash(host));
+ return (cdn || iconCdns.generative).replace('{icon}', asciiHash(host));
},
/* Returns the SVG path content */
getSimpleIcon(img) {
@@ -187,6 +189,23 @@ export default {
this.broken = true;
ErrorHandler(`The path to '${this.icon}' could not be resolved`);
},
+ /* Called when initial icon has resulted in 404. Attempts to find new icon */
+ getFallbackIcon() {
+ if (this.attemptedFallback) return undefined; // If this is second attempt, then give up
+ const { iconType } = this;
+ const markAsSttempted = () => {
+ this.broken = false;
+ this.attemptedFallback = true;
+ };
+ if (iconType.includes('favicon')) { // Specify fallback for favicon-based icons
+ markAsSttempted();
+ return this.getFavicon(this.url, 'local');
+ } else if (iconType === 'generative') {
+ markAsSttempted();
+ return this.getGenerativeIcon(this.url, iconCdns.generativeFallback);
+ }
+ return undefined;
+ },
},
};
diff --git a/src/utils/defaults.js b/src/utils/defaults.js
index f81467c8..0a5a8cf3 100644
--- a/src/utils/defaults.js
+++ b/src/utils/defaults.js
@@ -184,6 +184,7 @@ module.exports = {
mdi: 'https://cdn.jsdelivr.net/npm/@mdi/font@5.9.55/css/materialdesignicons.min.css',
si: 'https://unpkg.com/simple-icons@v5/icons',
generative: 'https://avatars.dicebear.com/api/identicon/{icon}.svg',
+ generativeFallback: 'https://evatar.io/{icon}',
localPath: './item-icons',
faviconName: 'favicon.ico',
homeLabIcons: 'https://raw.githubusercontent.com/WalkxCode/dashboard-icons/master/png/{icon}.png',