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 =" showSearch " >
63+ <!-- Not type="search": NcTextField only fills the trailing button's icon
64+ slot when type !== 'search', which leaves the clear button iconless. -->
65+ <NcTextField id="deck-search-input"
66+ class="board-search"
67+ type="text"
68+ :label =" searchLabel "
69+ :value =" searchQuery "
70+ :title =" searchHint || null "
71+ :show-trailing-button =" searchQuery !== ' ' "
72+ :trailing-button-label =" t (' deck' , ' Clear search' )"
73+ :aria-describedby =" searchHint ? ' deck-search-hint' : null "
74+ @update :value =" setSearchQuery "
75+ @trailing-button-click =" clearSearchQuery "
76+ @focus =" $store .dispatch (' toggleShortcutLock' , true )"
77+ @blur =" $store .dispatch (' toggleShortcutLock' , false )" />
78+ <!-- title is for pointer users, aria-describedby for assistive tech. No double
79+ announcement: title is only the fallback description per HTML-AAM. -->
80+ <span v-if =" searchHint" id =" deck-search-hint" class =" hidden-visually" >{{ searchHint }}</span >
81+ </template >
7482 <div v-if =" board" class =" board-action-buttons" >
7583 <div class =" board-action-buttons__filter" >
7684 <NcPopover :placement =" ' bottom-end' "
279287<script >
280288import { mapState , mapGetters } from ' vuex'
281289import { subscribe , unsubscribe } from ' @nextcloud/event-bus'
282- import { NcActions , NcActionButton , NcActionSeparator , NcAvatar , NcButton , NcPopover , NcModal } from ' @nextcloud/vue'
290+ import { NcActions , NcActionButton , NcActionSeparator , NcAvatar , NcButton , NcPopover , NcModal , NcTextField } from ' @nextcloud/vue'
283291import labelStyle from ' ../mixins/labelStyle.js'
284292import ArchiveIcon from ' vue-material-design-icons/ArchiveOutline.vue'
285293import ImageIcon from ' vue-material-design-icons/ImageMultipleOutline.vue'
@@ -304,6 +312,7 @@ export default {
304312 NcActionButton,
305313 NcButton,
306314 NcPopover,
315+ NcTextField,
307316 NcAvatar,
308317 ArchiveIcon,
309318 ImageIcon,
@@ -329,6 +338,19 @@ export default {
329338 required: false ,
330339 default: null ,
331340 },
341+ showSearch: {
342+ type: Boolean ,
343+ default: false ,
344+ },
345+ searchLabel: {
346+ type: String ,
347+ default: ' ' ,
348+ },
349+ // Only pass this where the card prefixes actually apply
350+ searchHint: {
351+ type: String ,
352+ default: ' ' ,
353+ },
332354 },
333355 data () {
334356 return {
@@ -418,6 +440,12 @@ export default {
418440 }
419441 this .$nextTick (() => this .$store .dispatch (' setFilter' , { ... this .filter }))
420442 },
443+ setSearchQuery (value ) {
444+ this .$store .commit (' setSearchQuery' , value)
445+ },
446+ clearSearchQuery () {
447+ this .$store .commit (' setSearchQuery' , ' ' )
448+ },
421449 toggleNav () {
422450 this .$store .dispatch (' toggleNav' )
423451 },
@@ -486,9 +514,6 @@ export default {
486514 triggerOpenFilters () {
487515 this .$refs .filterPopover .$el .click ()
488516 },
489- triggerOpenSearch () {
490- this .$refs .search .focus ()
491- },
492517 triggerClearFilter () {
493518 this .clearFilter ()
494519 },
@@ -505,20 +530,30 @@ export default {
505530< / script>
506531
507532< style lang= " scss" scoped>
533+ @import ' ../css/variables.scss' ;
534+
508535 .controls {
509536 display: flex;
537+ // min-height, not height: the search wraps to a second row on narrow screens
538+ flex- wrap: wrap;
539+ row- gap: var (-- default- grid- baseline);
510540 margin: calc (var (-- default- grid- baseline) * 2 );
511- height: var (-- default- clickable- area);
541+ min - height: var (-- default- clickable- area);
512542 padding- inline- start: var (-- default- clickable- area);
513543
514544 .board - title {
515545 display: flex;
516546 align- items: center;
547+ // lets the h2 below actually truncate
548+ min- width: 0 ;
517549
518550 h2 {
519551 margin: 0 ;
520552 margin- inline- end: 10px ;
521553 font- size: 18px ;
554+ overflow: hidden;
555+ text- overflow: ellipsis;
556+ white- space: nowrap;
522557 }
523558
524559 .board - bullet {
@@ -564,20 +599,30 @@ export default {
564599 flex- grow: 1 ;
565600 order: 100 ;
566601 display: flex;
602+ flex- wrap: wrap;
603+ align- items: center;
604+ row- gap: var (-- default- grid- baseline);
567605 justify- content: flex- end;
568606 }
569607
570608 .board - action- buttons {
571609 display: flex;
572610 }
573611
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;
612+ .board - search {
613+ flex: 0 1 15rem ;
614+ min- width: 0 ;
615+ margin- inline- end: var (-- default- grid- baseline);
616+ }
617+
618+ @media (max - width : $breakpoint - small - mobile ) {
619+ // Own row below the buttons, spanning the full header. The negative margin cancels
620+ // the padding .controls reserves for the navigation toggle, which only occupies the
621+ // first row; the oversized basis keeps the search alone on its line, so it is safe.
622+ .board - search {
623+ order: 1 ;
624+ flex- basis: calc (100 % + var (-- default- clickable- area));
625+ margin- inline: calc (- 1 * var (-- default- clickable- area)) 0 ;
581626 }
582627 }
583628
0 commit comments