aboutsummaryrefslogtreecommitdiffstats
path: root/core
diff options
context:
space:
mode:
authorFerdinand Thiessen <opensource@fthiessen.de>2024-06-26 11:22:27 +0200
committerFerdinand Thiessen <opensource@fthiessen.de>2024-06-27 12:13:14 +0200
commit0ff17b857b22dbd296471b5b3d6580742a437553 (patch)
tree65bec1ca99d7e4b3936edc6ad3185b0356a4ee91 /core
parent6ee965f0d92f3538ae5b44249d929fe741a371c0 (diff)
downloadnextcloud-server-0ff17b857b22dbd296471b5b3d6580742a437553.tar.gz
nextcloud-server-0ff17b857b22dbd296471b5b3d6580742a437553.zip
fix(UnifiedSearch): Implement design comments and focus input on open
Signed-off-by: Ferdinand Thiessen <opensource@fthiessen.de>
Diffstat (limited to 'core')
-rw-r--r--core/src/components/UnifiedSearch/UnifiedSearchLocalSearchBar.vue72
1 files changed, 54 insertions, 18 deletions
diff --git a/core/src/components/UnifiedSearch/UnifiedSearchLocalSearchBar.vue b/core/src/components/UnifiedSearch/UnifiedSearchLocalSearchBar.vue
index ed9a9951297..d68466ea91a 100644
--- a/core/src/components/UnifiedSearch/UnifiedSearchLocalSearchBar.vue
+++ b/core/src/components/UnifiedSearch/UnifiedSearchLocalSearchBar.vue
@@ -8,7 +8,8 @@
class="local-unified-search animated-width"
:class="{ 'local-unified-search--open': open }">
<!-- We can not use labels as it breaks the header layout so only aria-label and placeholder -->
- <NcInputField class="local-unified-search__input animated-width"
+ <NcInputField ref="searchInput"
+ class="local-unified-search__input animated-width"
:aria-label="t('core', 'Search in current app')"
:placeholder="t('core', 'Search in current app')"
show-trailing-button
@@ -21,13 +22,17 @@
</template>
</NcInputField>
- <NcButton class="local-unified-search__global-search"
+ <NcButton ref="searchGlobalButton"
+ class="local-unified-search__global-search"
:aria-label="t('core', 'Search everywhere')"
:title="t('core', 'Search everywhere')"
type="tertiary-no-background"
@click="$emit('global-search')">
+ <template v-if="!isMobile" #default>
+ {{ t('core', 'Search everywhere') }}
+ </template>
<template #icon>
- <NcIconSvgWrapper :path="mdiEarth" />
+ <NcIconSvgWrapper :path="mdiCloudSearch" />
</template>
</NcButton>
</div>
@@ -35,14 +40,18 @@
</template>
<script lang="ts" setup>
-import { mdiEarth, mdiClose } from '@mdi/js'
+import type { ComponentPublicInstance } from 'vue'
+import { mdiCloudSearch, mdiClose } from '@mdi/js'
import { translate as t } from '@nextcloud/l10n'
+import { useIsMobile } from '@nextcloud/vue/dist/Composables/useIsMobile.js'
+import { computed, ref, watchEffect } from 'vue'
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcIconSvgWrapper from '@nextcloud/vue/dist/Components/NcIconSvgWrapper.js'
import NcInputField from '@nextcloud/vue/dist/Components/NcInputField.js'
+import { useElementSize } from '@vueuse/core'
-defineProps<{
+const props = defineProps<{
query: string,
open: boolean
}>()
@@ -53,6 +62,28 @@ const emit = defineEmits<{
(e: 'global-search'): void
}>()
+// Hacky type until the library provides real Types
+type FocusableComponent = ComponentPublicInstance<object, object, object, Record<string, never>, { focus: () => void }>
+/** The input field component */
+const searchInput = ref<FocusableComponent>()
+/** When the search bar is opened we focus the input */
+watchEffect(() => {
+ if (props.open && searchInput.value) {
+ searchInput.value.focus()
+ }
+})
+
+/** Current window size is below the "mobile" breakpoint (currently 1024px) */
+const isMobile = useIsMobile()
+
+const searchGlobalButton = ref<ComponentPublicInstance>()
+/** Width of the search global button, used to resize the input field */
+const { width: searchGlobalButtonWidth } = useElementSize(searchGlobalButton)
+const searchGlobalButtonCSSWidth = computed(() => searchGlobalButtonWidth.value ? `${searchGlobalButtonWidth.value}px` : 'var(--default-clickable-area)')
+
+/**
+ * Clear the search query and close the search bar
+ */
function clearAndCloseSearch() {
emit('update:query', '')
emit('update:open', false)
@@ -61,10 +92,12 @@ function clearAndCloseSearch() {
<style scoped lang="scss">
.local-unified-search {
- --width: min(250px, 95vw);
+ --local-search-width: min(calc(250px + v-bind('searchGlobalButtonCSSWidth')), 95vw);
+
+ box-sizing: border-box;
position: relative;
height: var(--header-height);
- width: var(--width);
+ width: var(--local-search-width);
display: flex;
align-items: center;
// Ensure it overlays the other entries
@@ -78,21 +111,20 @@ function clearAndCloseSearch() {
#{&} &__global-search {
position: absolute;
- inset-inline-end: 0;
+ inset-inline-end: var(--default-clickable-area);
}
#{&} &__input {
+ box-sizing: border-box;
// override some nextcloud-vue styles
margin: 0;
- width: var(--width);
+ width: var(--local-search-width);
// Fixup the spacing so we can fit in the "search globally" button
// this can break at any time the component library changes
:deep(input) {
- padding-inline-end: calc(2 * var(--default-clickable-area) + var(--default-grid-baseline));
- }
- :deep(button) {
- inset-inline-end: var(--default-clickable-area);
+ // search global width + close button width
+ padding-inline-end: calc(v-bind('searchGlobalButtonWidth') + var(--default-clickable-area));
}
}
}
@@ -110,22 +142,26 @@ function clearAndCloseSearch() {
.v-enter,
.v-leave-to {
&.local-unified-search {
- // Start with only those two buttons + a little bit of the input element
- --width: calc(3 * var(--default-clickable-area));
+ // Start with only the overlayed button
+ --local-search-width: var(--clickable-area-large);
}
}
@media screen and (max-width: 500px) {
.local-unified-search.local-unified-search--open {
// 100% but still show the menu toggle on the very right
- --width: calc(100vw - (var(--clickable-area-large) + 5 * var(--default-grid-baseline)));
+ --local-search-width: 100vw;
+ padding-inline: var(--default-grid-baseline);
}
// when open we need to position it absolut to allow overlay the full bar
:global(.unified-search-menu:has(.local-unified-search--open)) {
position: absolute !important;
- // Keep showing the menu toggle
- inset-inline-end: calc(var(--clickable-area-large) + 4 * var(--default-grid-baseline));
+ inset-inline: 0;
+ }
+ // Hide all other entries, especially the user menu as it might leak pixels
+ :global(.header-right:has(.local-unified-search--open) > :not(.unified-search-menu)) {
+ display: none;
}
}
</style>