aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/accessibility/css/dark.scss3
-rw-r--r--apps/accessibility/css/highcontrast.scss3
-rw-r--r--core/css/css-variables.scss3
-rw-r--r--core/css/icons.scss1
-rw-r--r--core/css/variables.scss3
-rw-r--r--core/img/actions/filter.svg1
-rw-r--r--core/src/components/HeaderMenu.vue11
-rw-r--r--core/src/components/UnifiedSearch/SearchFilter.vue77
-rw-r--r--core/src/components/UnifiedSearch/SearchResultPlaceholder.vue68
-rw-r--r--core/src/components/UnifiedSearch/SearchResultPlaceholders.vue100
-rw-r--r--core/src/views/UnifiedSearch.vue49
11 files changed, 152 insertions, 167 deletions
diff --git a/apps/accessibility/css/dark.scss b/apps/accessibility/css/dark.scss
index c779f64ffd8..78203eae9f3 100644
--- a/apps/accessibility/css/dark.scss
+++ b/apps/accessibility/css/dark.scss
@@ -5,6 +5,9 @@ $color-main-background: #181818;
$color-background-dark: lighten($color-main-background, 4%);
$color-background-darker: lighten($color-main-background, 8%);
+$color-placeholder-light: lighten($color-main-background, 10%);
+$color-placeholder-dark: lighten($color-main-background, 20%);
+
$color-text-maxcontrast: darken($color-main-text, 30%);
$color-text-light: darken($color-main-text, 10%);
$color-text-lighter: darken($color-main-text, 20%);
diff --git a/apps/accessibility/css/highcontrast.scss b/apps/accessibility/css/highcontrast.scss
index 10ccdb47da6..707e34a2b42 100644
--- a/apps/accessibility/css/highcontrast.scss
+++ b/apps/accessibility/css/highcontrast.scss
@@ -5,6 +5,9 @@ $color-main-background: #fff;
$color-background-dark: darken($color-main-background, 30%);
$color-background-darker: darken($color-main-background, 30%);
+$color-placeholder-light: darken($color-main-background, 30%);
+$color-placeholder-dark: darken($color-main-background, 45%);
+
$color-text-maxcontrast: $color-main-text;
$color-text-light: $color-main-text;
$color-text-lighter: $color-main-text;
diff --git a/core/css/css-variables.scss b/core/css/css-variables.scss
index cf69a281237..8b09b006939 100644
--- a/core/css/css-variables.scss
+++ b/core/css/css-variables.scss
@@ -11,6 +11,9 @@
--color-background-dark: $color-background-dark;
--color-background-darker: $color-background-darker;
+ --color-placeholder-light: $color-placeholder-light;
+ --color-placeholder-dark: $color-placeholder-dark;
+
--color-primary: $color-primary;
--color-primary-light: $color-primary-light;
--color-primary-text: $color-primary-text;
diff --git a/core/css/icons.scss b/core/css/icons.scss
index 16ffc4a5874..71aa8214df0 100644
--- a/core/css/icons.scss
+++ b/core/css/icons.scss
@@ -307,6 +307,7 @@ audio, canvas, embed, iframe, img, input, object, video {
@include icon-black-white('upload', 'actions', 1, true);
@include icon-black-white('user', 'actions', 1, true);
@include icon-black-white('group', 'actions', 1, true);
+@include icon-black-white('filter', 'actions', 1, true);
@include icon-black-white('video', 'actions', 2, true);
.icon-video-white {
diff --git a/core/css/variables.scss b/core/css/variables.scss
index 796b5ffe3e2..6f2d19e8723 100644
--- a/core/css/variables.scss
+++ b/core/css/variables.scss
@@ -40,6 +40,9 @@ $color-background-hover: nc-darken($color-main-background, 4%) !default;
$color-background-dark: nc-darken($color-main-background, 7%) !default;
$color-background-darker: nc-darken($color-main-background, 14%) !default;
+$color-placeholder-light: nc-darken($color-main-background, 10%) !default;
+$color-placeholder-dark: nc-darken($color-main-background, 20%) !default;
+
$color-primary: #0082c9 !default;
$color-primary-light: mix($color-primary, $color-main-background, 10%) !default;
$color-primary-text: #ffffff !default;
diff --git a/core/img/actions/filter.svg b/core/img/actions/filter.svg
new file mode 100644
index 00000000000..34c1dd2181c
--- /dev/null
+++ b/core/img/actions/filter.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16"><path d="M1.19 2.4l5.05 6.48v5.24c0 .49.4.88.88.88h1.76c.49 0 .88-.4.88-.88V8.88l5.05-6.47a.87.87 0 00-.7-1.41H1.89a.87.87 0 00-.7 1.4z"/></svg> \ No newline at end of file
diff --git a/core/src/components/HeaderMenu.vue b/core/src/components/HeaderMenu.vue
index 2cc5b79d6dd..9848dc45e38 100644
--- a/core/src/components/HeaderMenu.vue
+++ b/core/src/components/HeaderMenu.vue
@@ -20,7 +20,7 @@
-
-->
<template>
- <div v-click-outside="closeMenu" :class="{ 'header-menu--opened': opened }" class="header-menu">
+ <div v-click-outside="clickOutsideConfig" :class="{ 'header-menu--opened': opened }" class="header-menu">
<a class="header-menu__trigger"
href="#"
:aria-controls="`header-menu-${id}`"
@@ -44,6 +44,7 @@
<script>
import { directive as ClickOutside } from 'v-click-outside'
import { emit, subscribe, unsubscribe } from '@nextcloud/event-bus'
+import excludeClickOutsideClasses from '@nextcloud/vue/dist/Mixins/excludeClickOutsideClasses'
export default {
name: 'HeaderMenu',
@@ -52,6 +53,10 @@ export default {
ClickOutside,
},
+ mixins: [
+ excludeClickOutsideClasses,
+ ],
+
props: {
id: {
type: String,
@@ -66,6 +71,10 @@ export default {
data() {
return {
opened: this.open,
+ clickOutsideConfig: {
+ handler: this.closeMenu,
+ middleware: this.clickOutsideMiddleware,
+ },
}
},
diff --git a/core/src/components/UnifiedSearch/SearchFilter.vue b/core/src/components/UnifiedSearch/SearchFilter.vue
deleted file mode 100644
index f3c06a24528..00000000000
--- a/core/src/components/UnifiedSearch/SearchFilter.vue
+++ /dev/null
@@ -1,77 +0,0 @@
- <!--
- - @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com>
- -
- - @author John Molakvoæ <skjnldsv@protonmail.com>
- -
- - @license GNU AGPL version 3 or any later version
- -
- - 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>
- <li>
- <a :title="t('core', 'Search for {name} only', { name })"
- class="unified-search__filter"
- href="#"
- @click.prevent="onClick">
- {{ filter }}
- </a>
- </li>
-</template>
-
-<script>
-export default {
- name: 'SearchFilter',
-
- props: {
- type: {
- type: String,
- required: true,
- },
- name: {
- type: String,
- required: true,
- },
- },
- computed: {
- filter() {
- return `in:${this.type}`
- },
- },
-
- methods: {
- onClick() {
- this.$emit('click', this.filter)
- },
- },
-
-}
-</script>
-
-<style lang="scss" scoped>
-.unified-search__filter {
- height: 1em;
- margin-right: 5px;
- padding: 3px 8px;
- border-radius: 1em;
- background-color: var(--color-background-darker);
-
- &:active,
- &:focus,
- &:hover {
- background-color: var(--color-background-hover);
- }
-}
-
-</style>
diff --git a/core/src/components/UnifiedSearch/SearchResultPlaceholder.vue b/core/src/components/UnifiedSearch/SearchResultPlaceholder.vue
deleted file mode 100644
index 7eb0915b359..00000000000
--- a/core/src/components/UnifiedSearch/SearchResultPlaceholder.vue
+++ /dev/null
@@ -1,68 +0,0 @@
-<template>
- <svg
- class="unified-search__result-placeholder"
- xmlns="http://www.w3.org/2000/svg"
- fill="url(#unified-search__result-placeholder-gradient)">
- <defs>
- <linearGradient id="unified-search__result-placeholder-gradient">
- <stop offset="0%" stop-color="#ededed"><animate attributeName="stop-color"
- values="#ededed; #ededed; #cccccc; #cccccc; #ededed"
- dur="2s"
- repeatCount="indefinite" /></stop>
- <stop offset="100%" stop-color="#cccccc"><animate attributeName="stop-color"
- values="#cccccc; #ededed; #ededed; #cccccc; #cccccc"
- dur="2s"
- repeatCount="indefinite" /></stop>
- </linearGradient>
- </defs>
- <rect class="unified-search__result-placeholder-icon" />
- <rect class="unified-search__result-placeholder-line-one" />
- <rect class="unified-search__result-placeholder-line-two" :style="{width: `calc(${randWidth}%)`}" />
- </svg>
-</template>
-
-<script>
-export default {
- name: 'SearchResultPlaceholder',
-
- data() {
- return {
- randWidth: Math.floor(Math.random() * 20) + 30,
- }
- },
-}
-</script>
-
-<style lang="scss" scoped>
-$clickable-area: 44px;
-$margin: 10px;
-
-.unified-search__result-placeholder {
- width: calc(100% - 2 * #{$margin});
- height: $clickable-area;
- margin: $margin;
-
- &-icon {
- width: $clickable-area;
- height: $clickable-area;
- rx: var(--border-radius);
- ry: var(--border-radius);
- }
-
- &-line-one,
- &-line-two {
- width: calc(100% - #{$margin + $clickable-area});
- height: 1em;
- x: $margin + $clickable-area;
- }
-
- &-line-one {
- y: 5px;
- }
-
- &-line-two {
- y: 25px;
- }
-}
-
-</style>
diff --git a/core/src/components/UnifiedSearch/SearchResultPlaceholders.vue b/core/src/components/UnifiedSearch/SearchResultPlaceholders.vue
new file mode 100644
index 00000000000..31f85f413d3
--- /dev/null
+++ b/core/src/components/UnifiedSearch/SearchResultPlaceholders.vue
@@ -0,0 +1,100 @@
+<template>
+ <ul>
+ <!-- Placeholder animation -->
+ <svg class="unified-search__result-placeholder-gradient">
+ <defs>
+ <linearGradient id="unified-search__result-placeholder-gradient">
+ <stop offset="0%" :stop-color="light">
+ <animate attributeName="stop-color"
+ :values="`${light}; ${light}; ${dark}; ${dark}; ${light}`"
+ dur="2s"
+ repeatCount="indefinite" />
+ </stop>
+ <stop offset="100%" :stop-color="dark">
+ <animate attributeName="stop-color"
+ :values="`${dark}; ${light}; ${light}; ${dark}; ${dark}`"
+ dur="2s"
+ repeatCount="indefinite" />
+ </stop>
+ </linearGradient>
+ </defs>
+ </svg>
+
+ <!-- Placeholders -->
+ <li v-for="placeholder in [1, 2, 3]" :key="placeholder">
+ <svg
+ class="unified-search__result-placeholder"
+ xmlns="http://www.w3.org/2000/svg"
+ fill="url(#unified-search__result-placeholder-gradient)">
+ <rect class="unified-search__result-placeholder-icon" />
+ <rect class="unified-search__result-placeholder-line-one" />
+ <rect class="unified-search__result-placeholder-line-two" :style="{width: `calc(${randWidth()}%)`}" />
+ </svg>
+ </li>
+ </ul>
+</template>
+
+<script>
+export default {
+ name: 'SearchResultPlaceholders',
+
+ data() {
+ return {
+ light: null,
+ dark: null,
+ }
+ },
+ mounted() {
+ const styles = getComputedStyle(document.documentElement)
+ this.dark = styles.getPropertyValue('--color-placeholder-dark')
+ this.light = styles.getPropertyValue('--color-placeholder-light')
+ },
+
+ methods: {
+ randWidth() {
+ return Math.floor(Math.random() * 20) + 30
+ },
+ },
+}
+</script>
+
+<style lang="scss" scoped>
+$clickable-area: 44px;
+$margin: 10px;
+
+.unified-search__result-placeholder-gradient {
+ position: fixed;
+ height: 0;
+ width: 0;
+ z-index: -1;
+}
+
+.unified-search__result-placeholder {
+ width: calc(100% - 2 * #{$margin});
+ height: $clickable-area;
+ margin: $margin;
+
+ &-icon {
+ width: $clickable-area;
+ height: $clickable-area;
+ rx: var(--border-radius);
+ ry: var(--border-radius);
+ }
+
+ &-line-one,
+ &-line-two {
+ width: calc(100% - #{$margin + $clickable-area});
+ height: 1em;
+ x: $margin + $clickable-area;
+ }
+
+ &-line-one {
+ y: 5px;
+ }
+
+ &-line-two {
+ y: 25px;
+ }
+}
+
+</style>
diff --git a/core/src/views/UnifiedSearch.vue b/core/src/views/UnifiedSearch.vue
index 2d0b59db5dc..2251ac2dd39 100644
--- a/core/src/views/UnifiedSearch.vue
+++ b/core/src/views/UnifiedSearch.vue
@@ -22,6 +22,7 @@
<template>
<HeaderMenu id="unified-search"
class="unified-search"
+ exclude-click-outside-classes="popover"
:open.sync="open"
@open="onOpen"
@close="onClose">
@@ -39,26 +40,21 @@
:placeholder="t('core', 'Search {types} …', { types: typesNames.join(', ').toLowerCase() })"
@input="onInputDebounced"
@keypress.enter.prevent.stop="onInputEnter">
- </div>
-
- <!-- Search filters -->
- <div v-if="availableFilters.length > 1" class="unified-search__filters">
- <ul>
- <SearchFilter v-for="type in availableFilters"
+ <!-- Search filters -->
+ <Actions v-if="availableFilters.length > 1" class="unified-search__filters" placement="bottom">
+ <ActionButton v-for="type in availableFilters"
:key="type"
- :type="type"
- :name="typesMap[type]"
- @click="onClickFilter" />
- </ul>
+ icon="icon-filter"
+ :title="t('core', 'Search for {name} only', { name: typesMap[type] })"
+ @click="onClickFilter(`in:${type}`)">
+ {{ `in:${type}` }}
+ </ActionButton>
+ </Actions>
</div>
<template v-if="!hasResults">
<!-- Loading placeholders -->
- <ul v-if="isLoading">
- <li v-for="placeholder in [1, 2, 3]" :key="placeholder">
- <SearchResultPlaceholder />
- </li>
- </ul>
+ <SearchResultPlaceholders v-if="isLoading" />
<EmptyContent v-else-if="isValidQuery && isDoneSearching" icon="icon-search">
{{ t('core', 'No results for {query}', {query}) }}
@@ -109,6 +105,9 @@
<script>
import { minSearchLength, getTypes, search, defaultLimit, regexFilterIn, regexFilterNot } from '../services/UnifiedSearchService'
+import ActionButton from '@nextcloud/vue/dist/Components/ActionButton'
+import Actions from '@nextcloud/vue/dist/Components/Actions'
+import debounce from 'debounce'
import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent'
import Magnify from 'vue-material-design-icons/Magnify'
import debounce from 'debounce'
@@ -117,18 +116,20 @@ import { emit } from '@nextcloud/event-bus'
import HeaderMenu from '../components/HeaderMenu'
import SearchFilter from '../components/UnifiedSearch/SearchFilter'
import SearchResult from '../components/UnifiedSearch/SearchResult'
-import SearchResultPlaceholder from '../components/UnifiedSearch/SearchResultPlaceholder'
+import SearchResultPlaceholders from '../components/UnifiedSearch/SearchResultPlaceholders'
export default {
name: 'UnifiedSearch',
components: {
+ ActionButton,
+ Actions,
EmptyContent,
HeaderMenu,
Magnify,
SearchFilter,
SearchResult,
- SearchResultPlaceholder,
+ SearchResultPlaceholders,
},
data() {
@@ -352,12 +353,12 @@ export default {
types = this.typesIDs.filter(type => this.usedFiltersIn.indexOf(type) > -1)
}
- // remove any filters from the query
+ // Remove any filters from the query
query = query.replace(regexFilterIn, '').replace(regexFilterNot, '')
console.debug('Searching', query, 'in', types)
- // reset search if the query changed
+ // Reset search if the query changed
this.resetState()
types.forEach(async type => {
@@ -566,10 +567,13 @@ $input-padding: 6px;
}
&__input-wrapper {
+ width: 100%;
position: sticky;
// above search results
z-index: 2;
top: 0;
+ display: inline-flex;
+ align-items: center;
background-color: var(--color-main-background);
}
@@ -582,8 +586,7 @@ $input-padding: 6px;
}
&__input {
- // Minus margins
- width: calc(100% - 2 * #{$margin});
+ width: 100%;
height: 34px;
margin: $margin;
padding: $input-padding;
@@ -596,6 +599,10 @@ $input-padding: 6px;
}
}
+ &__filters {
+ margin-right: $margin / 2;
+ }
+
&__results {
&::before {
display: block;