diff --git a/README.md b/README.md
index c845d0a7..a6cfb0c0 100644
--- a/README.md
+++ b/README.md
@@ -21,6 +21,12 @@
- Many options for icons, including full Font-Awesome support and the ability to auto-fetch icon from URLs favicon
- Plus lots more...
+## Live Demo
+
+- [Demo 1](https://dashy-demo-1.as93.net)
+- [Demo 2](https://dashy-demo-2.as93.net)
+- [Demo 3](https://dashy-demo-3.as93.net)
+
---
## Running the App 🏃♂️
@@ -140,6 +146,10 @@ appConfig:
- [ ] Add support for custom widgets
- [ ] Convert JavaScript to TypeScript
+### Alternatives 🙌
+
+There are a few self-hosted web apps, that serve a similar purpose to Dashy. Including, but not limited to: [HomeDash2](https://lamarios.github.io/Homedash2), [Homer](https://github.com/bastienwirtz/homer), [Organizr](https://organizr.app/) and [Heimdall](https://github.com/linuxserver/Heimdall).
+
### Credits 🏆
The app makes use of the following components, kudos to their respective authors
diff --git a/src/assets/interface-icons/broken-icon.svg b/src/assets/interface-icons/broken-icon.svg
new file mode 100644
index 00000000..d2b5d391
--- /dev/null
+++ b/src/assets/interface-icons/broken-icon.svg
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/components/LinkItems/IframeModal.vue b/src/components/LinkItems/IframeModal.vue
index ccd5e9d3..2637b868 100644
--- a/src/components/LinkItems/IframeModal.vue
+++ b/src/components/LinkItems/IframeModal.vue
@@ -2,7 +2,8 @@
Close
x
-
+
+ No URL Specified
@@ -35,6 +36,16 @@ export default {
border: none;
}
+.no-url {
+ margin: 4rem auto;
+ width: fit-content;
+ font-size: 2rem;
+ padding: 0.5rem;
+ border: 1px dashed #ff0000;
+ border-radius: 3px;
+ background: #f4f2f2;
+}
+
.close-button {
position: absolute;
right: 0;
@@ -46,7 +57,6 @@ export default {
border-left: 1px solid var(--primary);
border-bottom: 1px solid var(--primary);
cursor: pointer;
-
&:hover {
background: var(--background);
color: var(--primary);
diff --git a/src/components/LinkItems/Item.vue b/src/components/LinkItems/Item.vue
index 1b822b87..b0b8ff34 100644
--- a/src/components/LinkItems/Item.vue
+++ b/src/components/LinkItems/Item.vue
@@ -96,7 +96,7 @@ export default {
};
-
diff --git a/src/components/Settings/KeyboardShortcutInfo.vue b/src/components/Settings/KeyboardShortcutInfo.vue
index 1c4f2294..87338106 100644
--- a/src/components/Settings/KeyboardShortcutInfo.vue
+++ b/src/components/Settings/KeyboardShortcutInfo.vue
@@ -76,12 +76,12 @@ export default {
padding: 0.1em 0.3em;
z-index: 10;
border-radius: 12px;
- border: 1px solid var(--background-darker);
+ border: 1px solid var(--welcome-popup-background);
-webkit-box-shadow: 2px 1px 5px #130f23;
box-shadow: 2px 1px 5px #130f23;
- border: 1px solid var(--primary);
- color: var(--primary);
- background: var(--background-darker);
+ border: 1px solid var(--welcome-popup-text-color);
+ color: var(--welcome-popup-text-color);
+ background: var(--welcome-popup-background);
cursor: default;
opacity: 0.94;
@include phone {
@@ -91,9 +91,9 @@ export default {
position: absolute;
top: -35px;
left: 20px;
- border: 1px solid var(--primary);
- color: var(--primary);
- background: var(--background-darker);
+ border: 1px solid var(--welcome-popup-text-color);
+ color: var(--welcome-popup-text-color);
+ background: var(--welcome-popup-background);
padding: 4px;
border-radius: var(--curve-factor);
}
@@ -108,7 +108,7 @@ export default {
border: 1px solid transparent;
cursor: pointer;
&:hover {
- border: 1px solid var(--primary);
+ border: 1px solid var(--welcome-popup-text-color);
opacity: var(--dimming-factor);
}
}
diff --git a/src/components/Settings/SettingsContainer.vue b/src/components/Settings/SettingsContainer.vue
index 2b846a01..32e1b6cc 100644
--- a/src/components/Settings/SettingsContainer.vue
+++ b/src/components/Settings/SettingsContainer.vue
@@ -75,6 +75,7 @@ export default {
align-items: center;
align-items: stretch;
background: linear-gradient(0deg, var(--background) 0%, var(--background-darker) 100%);
+ box-shadow: var(--settings-container-shadow);
}
.options-container {
display: flex;
diff --git a/src/styles/color-palette.scss b/src/styles/color-palette.scss
index 3107583d..4f6f5424 100644
--- a/src/styles/color-palette.scss
+++ b/src/styles/color-palette.scss
@@ -29,6 +29,7 @@
--item-icon-transform: drop-shadow(2px 4px 6px var(--transparent-50)) saturate(0.65);
--item-icon-transform-hover: drop-shadow(4px 8px 3px var(--transparent-50)) saturate(2);
--item-group-shadow: var(--item-shadow);
+ --settings-container-shadow: none;
/* Specific components, using variables allows them to be overridden individually */
--heading-text-color: var(--primary);
@@ -48,4 +49,6 @@
--search-field-background: var(--background);
--footer-text-color: var(--medium-grey);
--footer-text-color-link: var(--primary);
+ --welcome-popup-background: var(--background-darker);
+ --welcome-popup-text-color: var(--primary);
}
diff --git a/src/styles/color-themes.scss b/src/styles/color-themes.scss
index 5db8fa4f..46f3fe6a 100644
--- a/src/styles/color-themes.scss
+++ b/src/styles/color-themes.scss
@@ -144,6 +144,9 @@ html[data-theme='material'] {
--item-hover-shadow: 0 1px 4px #00000029, 0 2px 4px #0000002a;
--item-icon-transform: drop-shadow(1px 2px 1px var(--transparent-30)) saturate(0.65);
--item-icon-transform-hover: drop-shadow(1px 3px 2px var(--transparent-30)) saturate(2);
+ --settings-container-shadow: 0 1px 3px #0000005e, 0 1px 2px #00000085;
+ --welcome-popup-background: #01579b;
+ --welcome-popup-text-color: #ffffff;
}
html[data-theme='material-dark'] {
@@ -171,6 +174,8 @@ html[data-theme='material-dark'] {
--item-hover-shadow: 4px 4px 3px #00000082, 0 1px 10px #00000040;
--item-icon-transform: drop-shadow(1px 2px 1px var(--transparent-30)) saturate(0.65);
--item-icon-transform-hover: drop-shadow(1px 3px 2px var(--transparent-30)) saturate(2);
+ --welcome-popup-background: #131a1f;
+ --welcome-popup-text-color: var(--primary);
}
html[data-theme='colorful'] {
diff --git a/src/styles/media-queries.scss b/src/styles/media-queries.scss
index 91461af7..00ffc47e 100644
--- a/src/styles/media-queries.scss
+++ b/src/styles/media-queries.scss
@@ -53,3 +53,8 @@ $extra-large: 2800px;
@content;
}
}
+@mixin big-screen-up {
+ @media (min-width: #{$extra-large}) {
+ @content;
+ }
+}
diff --git a/src/utils/ErrorHandler.js b/src/utils/ErrorHandler.js
new file mode 100644
index 00000000..15e27769
--- /dev/null
+++ b/src/utils/ErrorHandler.js
@@ -0,0 +1,11 @@
+/* eslint no-console: ["error", { allow: ["warn", "error"] }] */
+
+/**
+ * Function called when an error happens
+ * If you wish to use an error logging service, put code for it here
+ */
+const ErrorHandler = function handler(msg) {
+ console.warn(msg);
+};
+
+export default ErrorHandler;
diff --git a/src/views/Home.vue b/src/views/Home.vue
index ce8647a1..98cc05d2 100644
--- a/src/views/Home.vue
+++ b/src/views/Home.vue
@@ -23,6 +23,7 @@
:items="filterTiles(section.items)"
@itemClicked="finishedSearching()"
:itemSize="itemSizeBound"
+ :class="(filterTiles(section.items).length === 0 && searchValue) ? 'no-results' : ''"
/>
No Data Found Yet
@@ -81,12 +82,14 @@ export default {
},
/* Extracts the site name from domain, used for the searching functionality */
getDomainFromUrl(url) {
+ if (!url) return '';
const urlPattern = /^(?:https?:\/\/)?(?:w{3}\.)?([a-z\d.-]+)\.(?:[a-z.]{2,10})(?:[/\w.-]*)*/;
const domainPattern = url.match(urlPattern);
return domainPattern ? domainPattern[1] : '';
},
/* Returns only the tiles that match the users search query */
filterTiles(allTiles) {
+ if (!allTiles) return [];
return allTiles.filter((tile) => {
const {
title, description, provider, url,
@@ -181,6 +184,7 @@ export default {
flex-direction: column;
}
&.orientation-vertical {
+ max-width: 100%;
@include tablet-up {
display: flex;
flex-direction: row;
@@ -203,6 +207,12 @@ export default {
@include big-screen {
grid-template-columns: repeat(4, 1fr);
}
+ @include big-screen-up {
+ grid-template-columns: repeat(5, 1fr);
+ }
+
+ /* Hide when search term returns nothing */
+ .no-results { display: none; }
}
.no-data {