Kavita/UI/Web/src/app/nav/_components/nav-header/nav-header.component.html
Christopher cc8e7e159b Converted majority PX values to REM
Everything but dark.scss and values inside calc() have been converted from px to rem
2025-05-01 21:31:30 -06:00

216 lines
11 KiB
HTML

<ng-container *transloco="let t; read: 'nav-header'">
@if (navService.navbarVisible$ | async) {
<nav class="navbar navbar-expand-md navbar-dark fixed-top">
<div class="container-fluid">
<a class="visually-hidden-focusable focus-visible" href="javascript:void(0);" (click)="moveFocus()">{{t('skip-alt')}}</a>
@if (navService.sideNavVisibility$ | async) {
<a class="side-nav-toggle" (click)="toggleSideNav($event)"><i class="fas fa-bars" aria-hidden="true"></i></a>
}
<a class="navbar-brand dark-exempt" routerLink="/home" routerLinkActive="active">
<app-image width="24px" height="24px" imageUrl="assets/images/logo-32.png" classes="logo-icon" />
<div class="d-none d-md-inline logo">
<span>Kavita</span>
</div>
</a>
<ul class="navbar-nav col me-auto">
@if (accountService.currentUser$ | async; as user) {
<div class="nav-item search">
<label for="nav-search" class="form-label visually-hidden">{{t('search-series-alt')}}</label>
<div class="ng-autocomplete">
<app-grouped-typeahead
#search
id="nav-search"
[minQueryLength]="2"
[isLoading]="isLoading"
initialValue=""
[placeholder]="t('search-alt')"
[groupedData]="searchResults"
(inputChanged)="onChangeSearch($event)"
(clearField)="clearSearch()"
(focusChanged)="focusUpdate($event)"
>
<ng-template #libraryTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="clickLibraryResult(item)">
<div class="ms-1">
<span>{{item.name}}</span>
</div>
</div>
</ng-template>
<ng-template #seriesTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="clickSeriesSearchResult(item)">
<div style="width: 1.5rem" class="me-1">
<app-image class="me-3 search-result" width="24px" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"></app-image>
</div>
<div class="ms-1">
<app-series-format [format]="item.format"></app-series-format>
@if (searchTerm.toLowerCase().trim(); as st) {
@if (item.name.toLowerCase().trim().indexOf(st) >= 0) {
<span>{{item.name}}</span>
} @else {
<span [innerHTML]="item.localizedName"></span>
}
}
<div class="text-light fst-italic" style="font-size: 0.8rem;">in {{item.libraryName}}</div>
</div>
</div>
</ng-template>
<ng-template #bookmarkTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="clickBookmarkSearchResult(item)">
<div style="width: 1.5rem" class="me-1">
<app-image class="me-3 search-result" width="24px" [imageUrl]="imageService.getSeriesCoverImage(item.seriesId)"></app-image>
</div>
<div class="ms-1">
<app-series-format [format]="item.format"></app-series-format>
@if (searchTerm.toLowerCase().trim(); as st) {
@if (item.seriesName.toLowerCase().trim().indexOf(st) >= 0) {
<span>{{item.seriesName}}</span>
} @else {
<span [innerHTML]="item.localizedSeriesName"></span>
}
}
</div>
</div>
</ng-template>
<ng-template #collectionTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="clickCollectionSearchResult(item)">
<div style="width: 1.5rem" class="me-1">
<app-image class="me-3 search-result" width="24px" [imageUrl]="imageService.getCollectionCoverImage(item.id)"></app-image>
</div>
<div class="ms-1">
<div>
<span>{{item.title}}</span>
<app-promoted-icon [promoted]="item.promoted"></app-promoted-icon>
</div>
<app-collection-owner [collection]="item"></app-collection-owner>
</div>
</div>
</ng-template>
<ng-template #readingListTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="clickReadingListSearchResult(item)">
<div class="ms-1">
<span>{{item.title}}</span>
<app-promoted-icon [promoted]="item.promoted"></app-promoted-icon>
</div>
</div>
</ng-template>
<ng-template #tagTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="goToOther(FilterField.Tags, item.id)">
<div class="ms-1">
<span>{{item.title}}</span>
</div>
</div>
</ng-template>
<ng-template #personTemplate let-item>
<div style="display: flex;padding: 0.3125rem;" class="clickable" (click)="goToPerson(item)">
<div style="width: 1.5rem" class="me-1">
<app-image class="me-3 search-result"
[styles]="{'background': 'none', 'max-height': '24px', 'height': '24px', 'width': '24px', 'border-radius': '50%'}"
width="24px" [imageUrl]="imageService.getPersonImage(item.id)" [errorImage]="imageService.noPersonImage"></app-image>
</div>
<div class="ms-1">
<div>{{item.name}}</div>
</div>
</div>
</ng-template>
<ng-template #genreTemplate let-item>
<div style="display: flex;padding: 0.3125rem;" class="clickable" (click)="goToOther(FilterField.Genres, item.id)">
<div class="ms-1">
<div [innerHTML]="item.title"></div>
</div>
</div>
</ng-template>
<ng-template #chapterTemplate let-item>
<div style="display: flex;padding: 0.3125rem;" class="clickable" (click)="clickChapterSearchResult(item)">
<div class="ms-1">
@if (item.files.length > 0) {
<app-series-format [format]="item.files?.[0].format"></app-series-format>
}
<!-- TODO: this needs the series name before the chapter issue -->
<span>{{item.titleName || item.range}}</span>
</div>
</div>
</ng-template>
<ng-template #fileTemplate let-item>
<div class="clickable" style="display: flex;padding: 0.3125rem;" (click)="clickFileSearchResult(item)">
<div class="ms-1">
<app-series-format [format]="item.format"></app-series-format>
<span>{{item.filePath}}</span>
</div>
</div>
</ng-template>
<ng-template #noResultsTemplate let-notFound>
{{t('no-data')}}
</ng-template>
</app-grouped-typeahead>
</div>
</div>
}
</ul>
@if((breakpoint$ | async)! > Breakpoint.Tablet) {
@if (backToTopNeeded) {
<div class="back-to-top">
<button class="btn btn-icon scroll-to-top" (click)="scrollToTop()">
<i class="fa fa-angle-double-up nav" aria-hidden="true"></i>
<span class="visually-hidden">{{t('scroll-to-top-alt')}}</span>
</button>
</div>
}
}
@if (accountService.currentUser$ | async; as user) {
<div class="nav-item me-2">
<app-nav-events-toggle [user]="user"></app-nav-events-toggle>
</div>
@if((breakpoint$ | async)! <= Breakpoint.Mobile) {
<button class="btn btn-outline-secondary primary-text" (click)="openLinkSelectionMenu()">
<i class="fa-solid fa-user-circle align-self-center phone-hidden d-xs-inline-block d-sm-inline-block d-md-none"></i>
<span class="d-none d-xs-none d-sm-none d-md-inline-block fw-bold">{{user.username | sentenceCase}}</span>
</button>
} @else {
<div class="nav-item not-xs-only">
<a routerLink="/settings" [fragment]="SettingsTabId.Preferences" class="dark-exempt btn btn-icon" [title]="t('settings')">
<i class="fa fa-cogs nav" aria-hidden="true"></i>
<span class="visually-hidden">{{t('settings')}}</span>
</a>
</div>
<div ngbDropdown class="nav-item dropdown d-sm-none d-md-block" display="dynamic" placement="bottom-right">
<button class="btn btn-outline-secondary primary-text" ngbDropdownToggle>
<i class="fa-solid fa-user-circle align-self-center phone-hidden d-xs-inline-block d-sm-inline-block d-md-none"></i>
<span class="d-none d-xs-none d-sm-none d-md-inline-block fw-bold">{{user.username | sentenceCase}}</span>
</button>
<div ngbDropdownMenu>
<a ngbDropdownItem routerLink="/all-filters/">{{t('all-filters')}}</a>
<a ngbDropdownItem routerLink="/announcements/">{{t('announcements')}}</a>
<a ngbDropdownItem [href]="WikiLink.Guides" rel="noopener noreferrer" target="_blank">{{t('help')}}</a>
<a ngbDropdownItem (click)="logout()">{{t('logout')}}</a>
</div>
</div>
}
}
</div>
</nav>
}
</ng-container>