1/* 2 * Copyright (C) 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {NgTemplateOutlet} from '@angular/common'; 18import {Component, Input} from '@angular/core'; 19import {Search} from './ui_data'; 20 21@Component({ 22 selector: 'search-list', 23 template: ` 24 <span class="mat-body-1" *ngIf="searches.length === 0"> 25 {{placeholderText}} 26 </span> 27 <div class="listed-search" *ngFor="let search of searches"> 28 <span 29 #searchName 30 class="mat-body-2 listed-search-name" 31 [matTooltipDisabled]="!showTooltip(search, searchName)" 32 [matTooltip]="getTooltip(search)"> {{search.name}} </span> 33 <div class="listed-search-date-options"> 34 <span> {{formatTimeMs(search.timeMs)}} </span> 35 <button 36 mat-icon-button 37 class="listed-search-options" 38 *ngIf="menuOptions.length > 0" 39 [class.force-show]="searchOptionsTarget === search" 40 (click)="searchOptionsTarget = search" 41 [cdkMenuTriggerFor]="optionsMenu"> 42 <mat-icon> more_vert </mat-icon> 43 </button> 44 45 <ng-template #optionsMenu> 46 <div class="context-menu" cdkMenu> 47 <div class="context-menu-item-container"> 48 <ng-container *ngFor="let opt of menuOptions"> 49 <span 50 *ngIf="opt.innerMenu" 51 class="context-menu-item" 52 cdkMenuItem 53 [cdkMenuTriggerFor]="innerMenu"> {{opt.name}} </span> 54 <span 55 *ngIf="!opt.innerMenu" 56 class="context-menu-item" 57 (click)="opt.onClickCallback(search)" 58 cdkMenuItem> {{opt.name}} </span> 59 60 <ng-template #innerMenu> 61 <div class="context-menu inner-menu" cdkMenu> 62 <div class="context-menu-item-container"> 63 <span class="context-menu-item" [cdkMenuItemDisabled]="true" cdkMenuItem> 64 <ng-container 65 [ngTemplateOutlet]="opt.innerMenu" 66 [ngTemplateOutletContext]="{search}"></ng-container> 67 </span> 68 </div> 69 </div> 70 </ng-template> 71 </ng-container> 72 </div> 73 </div> 74 </ng-template> 75 </div> 76 </div> 77 `, 78 styles: [ 79 ` 80 .listed-search { 81 display: flex; 82 flex-direction: row; 83 align-items: center; 84 justify-content: space-between; 85 } 86 .listed-search { 87 width: 100%; 88 column-gap: 10px; 89 } 90 .listed-search:hover { 91 background-color: var(--hover-element-color); 92 } 93 .listed-search:not(:hover) .listed-search-options:not(.force-show) { 94 visibility: hidden; 95 } 96 .listed-search-name { 97 overflow: hidden; 98 text-overflow: ellipsis; 99 white-space: nowrap; 100 } 101 .listed-search-date-options { 102 display: flex; 103 flex-direction: row; 104 align-items: center; 105 white-space: pre-line; 106 } 107 .listed-search-options { 108 width: fit-content; 109 cursor: pointer; 110 } 111 `, 112 ], 113}) 114export class SearchListComponent { 115 @Input() searches: Search[] = []; 116 @Input() placeholderText = ''; 117 @Input() menuOptions: MenuOption[] = []; 118 119 searchOptionsTarget: Search | undefined; 120 121 showTooltip(search: Search, el: HTMLElement) { 122 return search.name !== search.query || el.scrollWidth > el.offsetWidth; 123 } 124 125 getTooltip(search: Search) { 126 if (search.name === search.query) return search.query; 127 return search.name + ': ' + search.query; 128 } 129 130 formatTimeMs(timeMs: number) { 131 const time = new Date(timeMs); 132 return time.toTimeString().slice(0, 5) + '\n' + time.toLocaleDateString(); 133 } 134} 135 136export interface MenuOption { 137 name: string; 138 onClickCallback: (search: Search) => void; 139 innerMenu?: NgTemplateOutlet; 140} 141