]> source.dussan.org Git - nextcloud-server.git/commitdiff
Create searchable list component
authorMarco <marcoambrosini@icloud.com>
Fri, 10 Nov 2023 04:36:26 +0000 (13:36 +0900)
committerfenn-cs <fenn25.fn@gmail.com>
Fri, 10 Nov 2023 10:27:32 +0000 (11:27 +0100)
Signed-off-by: Marco <marcoambrosini@icloud.com>
core/src/components/GlobalSearch/SearchableList.vue [new file with mode: 0644]

diff --git a/core/src/components/GlobalSearch/SearchableList.vue b/core/src/components/GlobalSearch/SearchableList.vue
new file mode 100644 (file)
index 0000000..356f2f7
--- /dev/null
@@ -0,0 +1,149 @@
+<!--
+  - @copyright 2023 Marco Ambrosini <marcoambrosini@proton.me>
+  -
+  - @author Marco Ambrosini <marcoambrosini@proton.me>
+  -
+  - @license AGPL-3.0-or-later
+  -
+  - This program is free software: you can redistribute it and/or modify
+  - it under the terms of the GNU Affero General Public License as
+  - published by the Free Software Foundation, either version 3 of the
+  - License, or (at your option) any later version.
+  -
+  - This program is distributed in the hope that it will be useful,
+  - but WITHOUT ANY WARRANTY; without even the implied warranty of
+  - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+  - GNU Affero General Public License for more details.
+  -
+  - You should have received a copy of the GNU Affero General Public License
+  - along with this program. If not, see <http://www.gnu.org/licenses/>.
+  -
+-->
+
+<template>
+       <NcPopover>
+               <template #trigger>
+                       <slot name="trigger" />
+               </template>
+               <div class="searchable-list__wrapper">
+                       <NcTextField :value.sync="searchTerm"
+                               :label="labelText"
+                               trailing-button-icon="close"
+                               :show-trailing-button="searchTerm !== ''"
+                               @trailing-button-click="clearSearch">
+                               <Magnify :size="20" />
+                       </NcTextField>
+                       <ul v-if="filteredList.length > 0" class="searchable-list__list">
+                               <li v-for="element in filteredList"
+                                       :key="element"
+                                       :title="element"
+                                       role="button">
+                                       <NcButton alignment="start"
+                                               type="tertiary"
+                                               :wide="true"
+                                               @click="$emit(element)">
+                                               <template #icon>
+                                                       <NcAvatar :display-name="element" :hide-favorite="false" />
+                                               </template>
+                                               {{ element }}
+                                       </NcButton>
+                               </li>
+                       </ul>
+                       <div v-else class="searchable-list__empty-content">
+                               <NcEmptyContent :name="emptyContentText">
+                                       <template #icon>
+                                               <AlertCircleOutline />
+                                       </template>
+                               </NcEmptyContent>
+                       </div>
+               </div>
+       </NcPopover>
+</template>
+
+<script>
+import { NcPopover, NcTextField, NcAvatar, NcEmptyContent, NcButton } from '@nextcloud/vue'
+
+import AlertCircleOutline from 'vue-material-design-icons/AlertCircleOutline.vue'
+import Magnify from 'vue-material-design-icons/Magnify.vue'
+
+export default {
+       name: 'SearchableList',
+
+       components: {
+               NcPopover,
+               NcTextField,
+               Magnify,
+               AlertCircleOutline,
+               NcAvatar,
+               NcEmptyContent,
+               NcButton,
+       },
+
+       props: {
+               labelText: {
+                       type: String,
+                       default: 'this is a label',
+               },
+
+               searchList: {
+                       type: Array,
+                       required: true,
+               },
+
+               emptyContentText: {
+                       type: String,
+                       required: true,
+               },
+       },
+
+       data() {
+               return {
+                       error: false,
+                       searchTerm: '',
+               }
+       },
+
+       computed: {
+               filteredList() {
+                       return this.searchList.filter((element) => {
+                               return element.toLowerCase().includes(this.searchTerm.toLowerCase())
+                       })
+               },
+       },
+
+       methods: {
+               clearSearch() {
+                       this.searchTerm = ''
+               },
+       },
+}
+</script>
+
+<style lang="scss" scoped>
+
+.searchable-list {
+       &__wrapper {
+               padding: calc(var(--default-grid-baseline) * 3);
+               display: flex;
+               flex-direction: column;
+               align-items: center;
+               width: 250px;
+       }
+
+       &__list {
+               width: 100%;
+               max-height: 284px;
+               overflow-y: auto;
+               margin-top: var(--default-grid-baseline);
+               padding: var(--default-grid-baseline);
+
+               :deep(.button-vue) {
+                       border-radius: var(--border-radius-large) !important;
+               }
+       }
+
+       &__empty-content {
+               margin-top: calc(var(--default-grid-baseline) * 3);
+       }
+}
+</style>