Small css fixes and microinteractions [SCI-10630]

This commit is contained in:
Anton 2024-04-17 17:01:58 +02:00
parent 57c138f54f
commit 9bd64104f3
6 changed files with 97 additions and 18 deletions

View file

@ -8,7 +8,8 @@
</div>
</div>
<div class="bg-white rounded p-4 flex gap-2.5 items-center mb-4 sticky top-0">
<div class="left-icon sci-input-container-v2 w-72 input-sm" :title="i18n.t('nav.search')">
<div class="left-icon sci-input-container-v2 w-72 input-sm"
:title="i18n.t('nav.search')" :class="{'error': invalidQuery}">
<input ref="searchField" type="text" class="!pr-9" :value="localQuery" @change="changeQuery" :placeholder="i18n.t('nav.search')"/>
<i class="sn-icon sn-icon-search"></i>
<i v-if="localQuery.length > 0" class="sn-icon cursor-pointer sn-icon-close absolute right-0 -top-0.5" @click="localQuery = ''"></i>
@ -145,6 +146,9 @@ export default {
};
},
computed: {
invalidQuery() {
return this.localQuery.length < 2;
},
activeFilters() {
return Object.keys(this.filters).filter((key) => {
if (key === 'created_at' || key === 'updated_at') {

View file

@ -2,7 +2,7 @@
<div ref="modal" class="modal" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<form @submit.prevent="submit">
<div class="modal-content">
<div class="modal-content !pb-2.5">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<i class="sn-icon sn-icon-close"></i>

View file

@ -46,12 +46,14 @@ export default {
}
},
query() {
if (this.query.length > 1) {
this.results = [];
this.page = 1;
this.total = 0;
this.fullDataLoaded = false;
this.loadData();
}
}
},
mounted() {
this.loadData();
@ -104,6 +106,8 @@ export default {
this.loadData();
},
loadData() {
if (this.query.length < 2) return;
if (this.loading && this.page) return;
this.loading = true;

View file

@ -2,13 +2,15 @@
<GeneralDropdown ref="container" :canOpen="canOpen" :fieldOnlyOpen="true" @close="filtersOpened = false">
<template v-slot:field>
<div class="sci--navigation--top-menu-search left-icon sci-input-container-v2" :class="{'disabled' : !currentTeam}" :title="i18n.t('nav.search')">
<input ref="searchField" type="text" class="!pr-20" v-model="searchQuery" :placeholder="i18n.t('nav.search')" @keyup.enter="saveQuery"/>
<input ref="searchField" type="text" class="!pr-20" v-model="searchQuery" @keydown="focusHistoryItem"
@focus="openHistory" :placeholder="i18n.t('nav.search')" @keyup.enter="saveQuery"/>
<i class="sn-icon sn-icon-search"></i>
<div v-if="this.searchQuery.length > 1" class="flex items-center gap-1 absolute right-2 top-1.5">
<div class="btn btn-light icon-btn btn-xs" @click="this.searchQuery = ''">
<i class="sn-icon sn-icon-close m-0"></i>
</div>
<div class="btn btn-light icon-btn btn-xs" :class="{'active': filtersOpened}" @click="filtersOpened = !filtersOpened">
<div class="btn btn-light icon-btn btn-xs" :title="i18n.t('search.quick_search.search_options')"
:class="{'active': filtersOpened}" @click="filtersOpened = !filtersOpened">
<i class="sn-icon sn-icon-search-options m-0"></i>
</div>
</div>
@ -27,6 +29,10 @@
></SearchFilters>
<div v-else-if="showHistory" class="max-w-[600px]">
<div v-for="(query, i) in reversedPreviousQueries" @click="setQuery(query)" :key="i"
ref="historyItems"
tabindex="1"
@keydown="focusHistoryItem"
@keydown.enter="setQuery(query)"
class="flex px-3 h-11 items-center gap-2 hover:bg-sn-super-light-grey cursor-pointer">
<i class="sn-icon sn-icon-history-search"></i>
{{ query }}
@ -62,7 +68,7 @@
text-sn-black hover:no-underline active:no-underline hover:text-black block"
>
<div class="flex items-center gap-2">
<i class="sn-icon shrink-0" :class="getIcon(result.type)"></i>
<i class="sn-icon shrink-0" :class="getIcon(result.type)" :title="getTitle(result.type)"></i>
<span v-if="result.attributes.archived">(A)</span>
<StringWithEllipsis class="grow max-w-[400px]" :text="getName(result.attributes)"></StringWithEllipsis>
<div class="ml-auto pl-4 text-sn-grey text-xs shrink-0">
@ -80,9 +86,9 @@
</a>
<div v-else v-for="i in Array(5).fill(5)" class="px-3 py-2">
<div class="flex items-center gap-2 mb-2">
<div class="h-6 w-6 bg-sn-light-grey rounded shrink-0"></div>
<div class="h-6 grow max-w-[200px] bg-sn-light-grey rounded shrink-0"></div>
<div class="h-6 w-12 bg-sn-light-grey rounded shrink-0 ml-auto"></div>
<div class="h-5 w-5 bg-sn-light-grey rounded shrink-0"></div>
<div class="h-5 grow max-w-[200px] bg-sn-light-grey rounded shrink-0"></div>
<div class="h-5 w-12 bg-sn-light-grey rounded shrink-0 ml-auto"></div>
</div>
<div class="flex items-center gap-2 pl-8">
<div class="h-3 grow max-w-[200px] bg-sn-light-grey rounded shrink-0"></div>
@ -153,7 +159,7 @@ export default {
},
watch: {
searchQuery() {
this.$refs.container.isOpen = this.canOpen;
this.openHistory();
if (this.searchQuery.length > 1) {
this.fetchQuickSearchResults();
@ -167,13 +173,17 @@ export default {
quickFilter: null,
results: [],
loading: false,
filtersOpened: false
filtersOpened: false,
focusedHistoryItem: null
};
},
mounted() {
this.previousQueries = JSON.parse(localStorage.getItem('quickSearchHistory') || '[]');
},
methods: {
openHistory() {
this.$refs.container.isOpen = this.canOpen;
},
getIcon(type) {
switch (type) {
case 'projects':
@ -194,8 +204,38 @@ export default {
return 'sn-icon-reports';
case 'steps':
return 'sn-icon-steps';
case 'label-templates':
case 'zebra_label_templates':
return 'sn-icon-label-templates';
case 'fluics_label_templates':
return 'sn-icon-label-templates';
default:
return null;
}
},
getTitle(type) {
switch (type) {
case 'projects':
return this.i18n.t('search.quick_search.project');
case 'experiments':
return this.i18n.t('search.quick_search.experiment');
case 'my_modules':
return this.i18n.t('search.quick_search.task');
case 'project_folders':
return this.i18n.t('search.quick_search.folder');
case 'protocols':
return this.i18n.t('search.quick_search.protocol');
case 'results':
return this.i18n.t('search.quick_search.result');
case 'repository_rows':
return this.i18n.t('search.quick_search.inventory_item');
case 'reports':
return this.i18n.t('search.quick_search.report');
case 'steps':
return this.i18n.t('search.quick_search.step');
case 'zebra_label_templates':
return this.i18n.t('search.quick_search.label_template');
case 'fluics_label_templates':
return this.i18n.t('search.quick_search.label_template');
default:
return null;
}
@ -263,6 +303,26 @@ export default {
},
searchValue() {
window.open(`${this.searchUrl}?q=${this.searchQuery}`, '_self');
},
focusHistoryItem(event) {
if (this.focusedHistoryItem === null && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) {
this.focusedHistoryItem = 0;
this.$refs.historyItems[this.focusedHistoryItem].focus();
} else if (event.key === 'ArrowDown') {
event.preventDefault();
this.focusedHistoryItem += 1;
if (this.focusedHistoryItem >= this.$refs.historyItems.length) {
this.focusedHistoryItem = 0;
}
this.$refs.historyItems[this.focusedHistoryItem].focus();
} else if (event.key === 'ArrowUp') {
event.preventDefault();
this.focusedHistoryItem -= 1;
if (this.focusedHistoryItem < 0) {
this.focusedHistoryItem = this.$refs.historyItems.length - 1;
}
this.$refs.historyItems[this.focusedHistoryItem].focus();
}
}
}
};

View file

@ -13,7 +13,7 @@ class QuickSearchSerializer < ActiveModel::Serializer
end
def code
@object.code unless @object.is_a?(ProjectFolder) || object.is_a?(Result) || object.is_a?(LabelTemplate)
@object.respond_to?(:code) ? @object.code : @object.id
end
def updated_at

View file

@ -434,13 +434,24 @@ en:
all_results: "All search results for \"%{query}\""
empty_title: "No quick search results found."
empty_description: "Quick search only checks titles. Press enter or click \"All search results for '%{query}'\" to find all available matches."
search_options: "Search options"
project: "Project"
experiment: "Experiment"
task: "Task"
result: "Result"
inventory_item: "Inventory item"
protocol: "Protocol"
label_template: "Label template"
report: "Report"
step: "Step"
result: "Result"
whole_word: "Match any whole word"
whole_phrase: "Match whole phrase"
match_case: "Match case sensitive"
object_id: "ID:"
filters:
title: "More search options"
sub_filters: "Refine your search by applying the filters below."
sub_title: "Refine your search by applying the filters below."
by_type: "Filter by type"
by_created_date: "Filter by created date"
by_updated_date: "Filter by updated date"