mirror of
https://github.com/Lissy93/dashy.git
synced 2025-07-23 13:45:33 +02:00
⚡ Implements improved search
This commit is contained in:
parent
4dc25e6fc6
commit
11f38c9177
@ -1,3 +1,4 @@
|
|||||||
|
<!-- Main homepage for default view -->
|
||||||
<template>
|
<template>
|
||||||
<div class="home" :style="getBackgroundImage()">
|
<div class="home" :style="getBackgroundImage()">
|
||||||
<!-- Search bar, layout options and settings -->
|
<!-- Search bar, layout options and settings -->
|
||||||
@ -9,7 +10,7 @@
|
|||||||
:displayLayout="layout"
|
:displayLayout="layout"
|
||||||
:iconSize="itemSizeBound"
|
:iconSize="itemSizeBound"
|
||||||
:externalThemes="getExternalCSSLinks()"
|
:externalThemes="getExternalCSSLinks()"
|
||||||
:sections="getSections(sections)"
|
:sections="allSections"
|
||||||
:appConfig="appConfig"
|
:appConfig="appConfig"
|
||||||
:pageInfo="pageInfo"
|
:pageInfo="pageInfo"
|
||||||
:modalOpen="modalOpen"
|
:modalOpen="modalOpen"
|
||||||
@ -19,17 +20,19 @@
|
|||||||
<div v-if="checkTheresData(sections)"
|
<div v-if="checkTheresData(sections)"
|
||||||
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
:class="`item-group-container orientation-${layout} item-size-${itemSizeBound}`">
|
||||||
<Section
|
<Section
|
||||||
v-for="(section, index) in getSections(sections)"
|
v-for="(section, index) in filteredTiles"
|
||||||
:key="index"
|
:key="index"
|
||||||
:title="section.name"
|
:title="section.name"
|
||||||
:icon="section.icon || undefined"
|
:icon="section.icon || undefined"
|
||||||
:displayData="getDisplayData(section)"
|
:displayData="getDisplayData(section)"
|
||||||
:groupId="`section-${index}`"
|
:groupId="`section-${index}`"
|
||||||
:items="filterTiles(section.items)"
|
:items="filterTiles(section.items, searchValue)"
|
||||||
|
:searchTerm="searchValue"
|
||||||
:itemSize="itemSizeBound"
|
:itemSize="itemSizeBound"
|
||||||
@itemClicked="finishedSearching()"
|
@itemClicked="finishedSearching()"
|
||||||
@change-modal-visibility="updateModalVisibility"
|
@change-modal-visibility="updateModalVisibility"
|
||||||
:class="(filterTiles(section.items).length === 0 && searchValue) ? 'no-results' : ''"
|
:class="
|
||||||
|
(searchValue && filterTiles(section.items, searchValue).length === 0) ? 'no-results' : ''"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<!-- Show message when there's no data to show -->
|
<!-- Show message when there's no data to show -->
|
||||||
@ -43,6 +46,7 @@
|
|||||||
|
|
||||||
import SettingsContainer from '@/components/Settings/SettingsContainer.vue';
|
import SettingsContainer from '@/components/Settings/SettingsContainer.vue';
|
||||||
import Section from '@/components/LinkItems/Section.vue';
|
import Section from '@/components/LinkItems/Section.vue';
|
||||||
|
import SearchUtil from '@/utils/Search';
|
||||||
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
import Defaults, { localStorageKeys, iconCdns } from '@/utils/defaults';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -63,6 +67,21 @@ export default {
|
|||||||
modalOpen: false, // When true, keybindings are disabled
|
modalOpen: false, // When true, keybindings are disabled
|
||||||
}),
|
}),
|
||||||
computed: {
|
computed: {
|
||||||
|
/* Combines sections from config file, with those in local storage */
|
||||||
|
allSections() {
|
||||||
|
// If the user has stored sections in local storage, return those
|
||||||
|
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
||||||
|
if (localSections) {
|
||||||
|
const json = JSON.parse(localSections);
|
||||||
|
if (json.length >= 1) return json;
|
||||||
|
}
|
||||||
|
// Otherwise, return the usuall data from conf.yml
|
||||||
|
return this.sections;
|
||||||
|
},
|
||||||
|
filteredTiles() {
|
||||||
|
const sections = this.allSections;
|
||||||
|
return sections.filter((section) => this.filterTiles(section.items, this.searchValue));
|
||||||
|
},
|
||||||
/* Updates layout (when button clicked), and saves in local storage */
|
/* Updates layout (when button clicked), and saves in local storage */
|
||||||
layoutOrientation: {
|
layoutOrientation: {
|
||||||
get() { return this.appConfig.layout || Defaults.layout; },
|
get() { return this.appConfig.layout || Defaults.layout; },
|
||||||
@ -86,17 +105,6 @@ export default {
|
|||||||
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
||||||
return (sections && sections.length >= 1) || (localSections && localSections.length >= 1);
|
return (sections && sections.length >= 1) || (localSections && localSections.length >= 1);
|
||||||
},
|
},
|
||||||
/* Returns sections from local storage if available, otherwise uses the conf.yml */
|
|
||||||
getSections(sections) {
|
|
||||||
// If the user has stored sections in local storage, return those
|
|
||||||
const localSections = localStorage[localStorageKeys.CONF_SECTIONS];
|
|
||||||
if (localSections) {
|
|
||||||
const json = JSON.parse(localSections);
|
|
||||||
if (json.length >= 1) return json;
|
|
||||||
}
|
|
||||||
// Otherwise, return the usuall data from conf.yml
|
|
||||||
return sections;
|
|
||||||
},
|
|
||||||
/* Updates local data with search value, triggered from filter comp */
|
/* Updates local data with search value, triggered from filter comp */
|
||||||
searching(searchValue) {
|
searching(searchValue) {
|
||||||
this.searchValue = searchValue || '';
|
this.searchValue = searchValue || '';
|
||||||
@ -105,26 +113,9 @@ export default {
|
|||||||
finishedSearching() {
|
finishedSearching() {
|
||||||
this.$refs.filterComp.clearFilterInput();
|
this.$refs.filterComp.clearFilterInput();
|
||||||
},
|
},
|
||||||
/* 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 */
|
/* Returns only the tiles that match the users search query */
|
||||||
filterTiles(allTiles) {
|
filterTiles(allTiles, searchTerm) {
|
||||||
if (!allTiles) return [];
|
return SearchUtil(allTiles, searchTerm);
|
||||||
return allTiles.filter((tile) => {
|
|
||||||
const {
|
|
||||||
title, description, provider, url,
|
|
||||||
} = tile;
|
|
||||||
const searchTerm = this.searchValue.toLowerCase();
|
|
||||||
return (title && title.toLowerCase().includes(searchTerm))
|
|
||||||
|| (provider && provider.toLowerCase().includes(searchTerm))
|
|
||||||
|| (description && description.toLowerCase().includes(searchTerm))
|
|
||||||
|| this.getDomainFromUrl(url).includes(searchTerm);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
/* Returns optional section display preferences if available */
|
/* Returns optional section display preferences if available */
|
||||||
getDisplayData(section) {
|
getDisplayData(section) {
|
||||||
@ -163,8 +154,8 @@ export default {
|
|||||||
/* Checks if any sections or items use icons from a given CDN */
|
/* Checks if any sections or items use icons from a given CDN */
|
||||||
checkIfIconLibraryNeeded(prefix) {
|
checkIfIconLibraryNeeded(prefix) {
|
||||||
let isNeeded = false;
|
let isNeeded = false;
|
||||||
if (!this.sections) return false;
|
if (!this.allSections) return false;
|
||||||
this.sections.forEach((section) => {
|
this.allSections.forEach((section) => {
|
||||||
if (section.icon && section.icon.includes(prefix)) isNeeded = true;
|
if (section.icon && section.icon.includes(prefix)) isNeeded = true;
|
||||||
section.items.forEach((item) => {
|
section.items.forEach((item) => {
|
||||||
if (item.icon && item.icon.includes(prefix)) isNeeded = true;
|
if (item.icon && item.icon.includes(prefix)) isNeeded = true;
|
||||||
@ -203,11 +194,11 @@ export default {
|
|||||||
},
|
},
|
||||||
/* Returns true if there is more than 1 sub-result visible during searching */
|
/* Returns true if there is more than 1 sub-result visible during searching */
|
||||||
checkIfResults() {
|
checkIfResults() {
|
||||||
if (!this.sections) return false;
|
if (!this.allSections) return false;
|
||||||
else {
|
else {
|
||||||
let itemsFound = true;
|
let itemsFound = true;
|
||||||
this.sections.forEach((section) => {
|
this.allSections.forEach((section) => {
|
||||||
if (this.filterTiles(section.items).length > 0) itemsFound = false;
|
if (this.filterTiles(section.items, this.searchValue).length > 0) itemsFound = false;
|
||||||
});
|
});
|
||||||
return itemsFound;
|
return itemsFound;
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ import MinimalSection from '@/components/MinimalView/MinimalSection.vue';
|
|||||||
import MinimalHeading from '@/components/MinimalView/MinimalHeading.vue';
|
import MinimalHeading from '@/components/MinimalView/MinimalHeading.vue';
|
||||||
import MinimalSearch from '@/components/MinimalView/MinimalSearch.vue';
|
import MinimalSearch from '@/components/MinimalView/MinimalSearch.vue';
|
||||||
import { GetTheme, ApplyLocalTheme, ApplyCustomVariables } from '@/utils/ThemeHelper';
|
import { GetTheme, ApplyLocalTheme, ApplyCustomVariables } from '@/utils/ThemeHelper';
|
||||||
|
import SearchUtil from '@/utils/Search';
|
||||||
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
import Defaults, { localStorageKeys } from '@/utils/defaults';
|
||||||
import ConfigLauncher from '@/components/Settings/ConfigLauncher';
|
import ConfigLauncher from '@/components/Settings/ConfigLauncher';
|
||||||
|
|
||||||
@ -122,16 +123,7 @@ export default {
|
|||||||
/* Returns only the tiles that match the users search query */
|
/* Returns only the tiles that match the users search query */
|
||||||
filterTiles(allTiles) {
|
filterTiles(allTiles) {
|
||||||
if (!allTiles) return [];
|
if (!allTiles) return [];
|
||||||
return allTiles.filter((tile) => {
|
return SearchUtil(allTiles, this.searchValue);
|
||||||
const {
|
|
||||||
title, description, provider, url,
|
|
||||||
} = tile;
|
|
||||||
const searchTerm = this.searchValue.toLowerCase();
|
|
||||||
return (title && title.toLowerCase().includes(searchTerm))
|
|
||||||
|| (provider && provider.toLowerCase().includes(searchTerm))
|
|
||||||
|| (description && description.toLowerCase().includes(searchTerm))
|
|
||||||
|| this.getDomainFromUrl(url).includes(searchTerm);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
/* Update data when modal is open (so that key bindings can be disabled) */
|
/* Update data when modal is open (so that key bindings can be disabled) */
|
||||||
updateModalVisibility(modalState) {
|
updateModalVisibility(modalState) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user