3131 <div class =" board-actions" >
3232 <SessionList v-if =" isNotifyPushEnabled && presentUsers .length "
3333 :sessions =" presentUsers " />
34- <!-- Hide but not remove for now as search might change in the future -->
35- <div v-if =" false" class =" deck-search" >
36- <input id =" deck-search-input"
37- ref =" search"
38- :tabindex =" 0"
39- type =" search"
40- class =" icon-search"
41- :value =" searchQuery"
42- @focus =" $store.dispatch('toggleShortcutLock', true)"
43- @blur =" $store.dispatch('toggleShortcutLock', false)"
44- @input =" $store.commit('setSearchQuery', $event.target.value)" >
45- </div >
4634 <div v-if =" board && canManage && !showArchived && !board.archived"
4735 id =" stack-add"
4836 v-click-outside =" hideAddStack" >
7159 value =" " >
7260 </form >
7361 </div >
62+ <template v-if =" showFilter " >
63+ <!-- type="text", not "search": NcTextField only fills the trailing button's
64+ icon slot when type !== 'search', so a search field renders the clear
65+ button with no icon at all. "Filter" is also the better semantic here. -->
66+ <NcTextField id="deck-search-input"
67+ class="board-filter"
68+ type="text"
69+ :label =" filterLabel "
70+ :value =" searchQuery "
71+ :show-trailing-button =" searchQuery !== ' ' "
72+ :trailing-button-label =" t (' deck' , ' Clear filter text' )"
73+ aria-describedby="deck-filter-hint"
74+ @update :value =" setSearchQuery "
75+ @trailing-button-click =" clearSearchQuery "
76+ @focus =" $store .dispatch (' toggleShortcutLock' , true )"
77+ @blur =" $store .dispatch (' toggleShortcutLock' , false )" />
78+ <span id =" deck-filter-hint" class =" hidden-visually" >{{ filterHint }}</span >
79+ </template >
7480 <div v-if =" board" class =" board-action-buttons" >
7581 <div class =" board-action-buttons__filter" >
7682 <NcPopover :placement =" ' bottom-end' "
279285<script >
280286import { mapState , mapGetters } from ' vuex'
281287import { subscribe , unsubscribe } from ' @nextcloud/event-bus'
282- import { NcActions , NcActionButton , NcActionSeparator , NcAvatar , NcButton , NcPopover , NcModal } from ' @nextcloud/vue'
288+ import { NcActions , NcActionButton , NcActionSeparator , NcAvatar , NcButton , NcPopover , NcModal , NcTextField } from ' @nextcloud/vue'
283289import labelStyle from ' ../mixins/labelStyle.js'
284290import ArchiveIcon from ' vue-material-design-icons/ArchiveOutline.vue'
285291import ImageIcon from ' vue-material-design-icons/ImageMultipleOutline.vue'
@@ -304,6 +310,7 @@ export default {
304310 NcActionButton,
305311 NcButton,
306312 NcPopover,
313+ NcTextField,
307314 NcAvatar,
308315 ArchiveIcon,
309316 ImageIcon,
@@ -361,6 +368,23 @@ export default {
361368 name: ' board.details' ,
362369 }
363370 },
371+ // Controls is shared by the board, the board list and the overviews.
372+ // Only the first two have something that consumes the query.
373+ isBoardList () {
374+ return ! this .board && ! this .overviewName
375+ },
376+ showFilter () {
377+ return !! this .board || this .isBoardList
378+ },
379+ filterLabel () {
380+ return this .isBoardList ? t (' deck' , ' Filter boards' ) : t (' deck' , ' Filter cards' )
381+ },
382+ filterHint () {
383+ // The prefixes are passed as a parameter so translators never see them as translatable text
384+ return t (' deck' , ' Type to filter the current view. Supported prefixes: {prefixes}. Wrap phrases in double quotes.' , {
385+ prefixes: ' title:, description:, tag:, assigned:, list:, date:' ,
386+ })
387+ },
364388 isFilterActive () {
365389 return this .filter .tags .length !== 0 || this .filter .users .length !== 0 || this .filter .due !== ' ' || this .filter .completed !== ' both'
366390 },
@@ -418,6 +442,12 @@ export default {
418442 }
419443 this .$nextTick (() => this .$store .dispatch (' setFilter' , { ... this .filter }))
420444 },
445+ setSearchQuery (value ) {
446+ this .$store .commit (' setSearchQuery' , value)
447+ },
448+ clearSearchQuery () {
449+ this .$store .commit (' setSearchQuery' , ' ' )
450+ },
421451 toggleNav () {
422452 this .$store .dispatch (' toggleNav' )
423453 },
@@ -486,9 +516,6 @@ export default {
486516 triggerOpenFilters () {
487517 this .$refs .filterPopover .$el .click ()
488518 },
489- triggerOpenSearch () {
490- this .$refs .search .focus ()
491- },
492519 triggerClearFilter () {
493520 this .clearFilter ()
494521 },
@@ -505,20 +532,31 @@ export default {
505532< / script>
506533
507534< style lang= " scss" scoped>
535+ @import ' ../css/variables.scss' ;
536+
508537 .controls {
509538 display: flex;
539+ // Wrap so the filter can drop to its own row on narrow screens.
540+ // This is why the height below is a min-height and not a height.
541+ flex- wrap: wrap;
542+ row- gap: var (-- default- grid- baseline);
510543 margin: calc (var (-- default- grid- baseline) * 2 );
511- height: var (-- default- clickable- area);
544+ min - height: var (-- default- clickable- area);
512545 padding- inline- start: var (-- default- clickable- area);
513546
514547 .board - title {
515548 display: flex;
516549 align- items: center;
550+ // A flex item holding text will not shrink below its content width without this
551+ min- width: 0 ;
517552
518553 h2 {
519554 margin: 0 ;
520555 margin- inline- end: 10px ;
521556 font- size: 18px ;
557+ overflow: hidden;
558+ text- overflow: ellipsis;
559+ white- space: nowrap;
522560 }
523561
524562 .board - bullet {
@@ -564,20 +602,29 @@ export default {
564602 flex- grow: 1 ;
565603 order: 100 ;
566604 display: flex;
605+ flex- wrap: wrap;
606+ align- items: center;
607+ row- gap: var (-- default- grid- baseline);
567608 justify- content: flex- end;
568609 }
569610
570611 .board - action- buttons {
571612 display: flex;
572613 }
573614
574- .deck - search {
575- display: flex;
576- align- items: center;
577- justify- content: center;
578- input[type= search] {
579- background- position: 5px ;
580- padding- inline- start: 24px ! important;
615+ .board - filter {
616+ flex: 0 1 15rem ;
617+ min- width: 0 ;
618+ margin- inline- end: var (-- default- grid- baseline);
619+ }
620+
621+ @media (max - width : $breakpoint - small - mobile ) {
622+ // order sorts the filter after the buttons, which all default to 0,
623+ // so it wraps onto its own row instead of pushing them down
624+ .board - filter {
625+ flex- basis: 100 % ;
626+ order: 1 ;
627+ margin- inline- end: 0 ;
581628 }
582629 }
583630
0 commit comments