Custom Theme Support (#1077)
* Started the migration to bootstrap 5. Introduced a breakpoint system that bootstrap reflects for our screens. * sr only migrated * mr/ml -> me/ms * pl/pr -> ps/pe * btn-block * removed input-group-append * Added form-label to all labels * Added some style overrides for inputs * Replaced form-group with mb-3 * Ignore journal files * Update media to d-flex/flex-grow-1 * Fixed reading list detail page * For develop builds, don't inline critical styles * Fixed some downstream security issues * Fixed a layout issue in series detail * Fixed issue with btn-light not having background color. Updated layout for series detail metadata * Cleaned up nav search * Laid out the organization for custom theme components. Update _inputs.scss with variable overrides and depending on theme, it will just work. * Lots of theming work * Added inputs to the theme page * Login and input placeholder changes - Fixed login screen centering issue on all devices - Changed the format of the login screen - Change the input placeholder color * Added checkbox styles * Refactored tagbadges and removed some ngdeep selectors * Added nav bar component and refactored some styles into event widget * Cleaned nav events again and made dedicated popover body * Finished pagination component * Fixed up some styles with buttons * refactored dropdown component * Update accordion component * Refactored breadcrumbs and rating star. Fixed a missing style for cards * Fixed some styling issues on person badge, added modal component, and some global styles * Finished moving everything within dark to component files * Fixed up filter buttons, move card styles into a component theme, fixed slider style * Refactored library card and grouped typeahead * Updated normal typeahead component and reduced amount of ngdeep selector * Refactored grid breakpoints to be available by css variable, but it's hardcoded into the app * Ensure breakpoints are defined per theme * Fixed up some styling overrides and customization for nav links and alt button * Removed some deep styles, moved css out of splash container and brough back labels for login page * Finished css variable refactor * Refactored all the theme variable definitions into files for each theme. * Added back bootstrap overrides * Added a note about bootstrap theme colors being not-possible to swap out at runtime * Cleaned up some dead code * Implemented the ability to set a custom theme on the site. Cleaned up misc code throughout. * Additional changes - Fixed nav where "kavita" was not hiding correctly on small viewports - Fixed search bar to make the behavior more consistent - Fixed accordion buttons - Changed accordion buttons to be more responsive - Added radio button colors - Fixed radios on theme test page - Changed login and reset password card layouts to be more consistent. - Added primary color shade for when darker shading is needed. * Built a basic site, allow the user to apply different themes, refactored nav service code out. * Implemented the ability update a user's theme * Added unit tests for Scan and Get Content in SiteThemeService. * Fixed a bug in the login code and Pref code which wasn't joining on SiteTheme table. Wrote Unit tests and the UI component to manage current theme. * Implemented scan so that it manages custom themes with unit tests * Component updates - Repositioning style ordering - Adding indicator override - Adding select styles * SignlaR integration, some fixes when creating custom entities, one single migration. Just login functionality left. * More ui updated - Added .no-hover to prevent hover on elements where not needed - Changed all selects I could find to appropriate class - Changed up nav tabs to work more like bootstrap tabs than pills - Added padding to top of some containers to make styles consistent - Added ability to change navbar fontawesome icon colors - removed some unecessary inline styling - Changed radio button to appropriate class - Toned down primate color, a bit too bright for dark theme. - Added ability to change button fontawesome icon color * nav-tab fix for series-detail * Added themes folder to gitignore * Adding card overlay * Fixing up light theme * Everything is done. Only bug is that color-scheme isn't being set properly from css variable. * Checkboxes have pointer by default. Confirm/Confirm email use default (dark) theme by default * Fixed an error where color-scheme wasn't reflecting correctly on themes on first load * Fixed user preferences not available on login * Changing dual radios to switches and color tweaks * disabled primary APCA fix * button APCA fixes * Fixed some timing issues with first load and image service * Fixed swiper issues from upgrade * Changed themes to be scss files again and adjusted Seed code * Migrated carousel to css variables. Fixed a broken animation for search. * Cleaned up some backend smells * Fixed white border outline on nav tabs, added some variables for header * Nav bar has been css variable-ified * Added some basic eink stuff to make the app useable Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
parent
c776ca3b72
commit
568ea9fd3a
168 changed files with 4710 additions and 1666 deletions
|
|
@ -1,30 +1,25 @@
|
|||
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Choose a Directory</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="filter">Filter</label>
|
||||
<div class="mb-3">
|
||||
<label for="filter" class="form-label">Filter</label>
|
||||
<div class="input-group">
|
||||
<input id="filter" autocomplete="off" class="form-control" [(ngModel)]="filterQuery" type="text" aria-describedby="reset-input">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-outline-secondary" type="button" id="reset-input" (click)="filterQuery = '';">Clear</button>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary" type="button" id="reset-input" (click)="filterQuery = '';">Clear</button>
|
||||
</div>
|
||||
</div>
|
||||
<nav aria-label="directory breadcrumb">
|
||||
<ol class="breadcrumb" *ngIf="routeStack.peek() !== undefined; else noBreadcrumb">
|
||||
<li class="breadcrumb-item {{route === routeStack.peek() ? 'active' : ''}}" *ngFor="let route of routeStack.items; let index = index">
|
||||
<li class="breadcrumb-item {{route === routeStack.peek() ? 'active' : ''}}" *ngFor="let route of routeStack.items; let index = index">
|
||||
<ng-container *ngIf="route === routeStack.peek(); else nonActive">
|
||||
{{route}}
|
||||
</ng-container>
|
||||
<ng-template #nonActive>
|
||||
<a href="javascript:void(0);" (click)="navigateTo(index)">{{route}}</a>
|
||||
</ng-template>
|
||||
</li>
|
||||
</li>
|
||||
</ol>
|
||||
<ng-template #noBreadcrumb>
|
||||
<div class="breadcrumb">Select a folder to view breadcrumb. Don't see your directory, try checking / first.</div>
|
||||
|
|
@ -33,17 +28,17 @@
|
|||
<ul class="list-group">
|
||||
<div class="list-group-item list-group-item-action">
|
||||
<button (click)="goBack()" class="btn btn-secondary" [disabled]="routeStack.peek() === undefined">
|
||||
<i class="fa fa-arrow-left mr-2" aria-hidden="true"></i>
|
||||
<i class="fa fa-arrow-left me-2" aria-hidden="true"></i>
|
||||
Back
|
||||
</button>
|
||||
|
||||
<button type="button" class="btn btn-primary float-right" [disabled]="routeStack.peek() === undefined" (click)="shareFolder('', $event)">Share</button>
|
||||
<button type="button" class="btn btn-primary float-end" [disabled]="routeStack.peek() === undefined" (click)="shareFolder('', $event)">Share</button>
|
||||
</div>
|
||||
</ul>
|
||||
<ul class="list-group scrollable">
|
||||
<button *ngFor="let folder of folders | filter: filterFolder" class="list-group-item list-group-item-action" (click)="selectNode(folder)">
|
||||
<span>{{getStem(folder)}}</span>
|
||||
<button type="button" class="btn btn-primary float-right" (click)="shareFolder(folder, $event)">Share</button>
|
||||
<button type="button" class="btn btn-primary float-end" (click)="shareFolder(folder, $event)">Share</button>
|
||||
</button>
|
||||
<div class="list-group-item text-center" *ngIf="folders.length === 0">
|
||||
There are no folders here
|
||||
|
|
@ -51,6 +46,6 @@
|
|||
</ul>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn btn-info" *ngIf="helpUrl.length > 0" href="{{helpUrl}}" target="_blank">Help</a>
|
||||
<a class="btn btn-icon" *ngIf="helpUrl.length > 0" href="{{helpUrl}}" target="_blank">Help</a>
|
||||
<button type="button" class="btn btn-secondary" (click)="close()">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Library Access</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
|
|
|||
|
|
@ -2,35 +2,35 @@
|
|||
<form [formGroup]="libraryForm">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">{{this.library !== undefined ? 'Edit' : 'New'}} Library</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info" *ngIf="errorMessage !== ''">
|
||||
<strong>Error: </strong> {{errorMessage}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="library-name">Name</label>
|
||||
<div class="mb-3">
|
||||
<label for="library-name" class="form-label">Name</label>
|
||||
<input id="library-name" class="form-control" formControlName="name" type="text">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="library-type">Type</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="typeTooltip" role="button" tabindex="0"></i>
|
||||
<div class="mb-3">
|
||||
<label for="library-type" class="form-label">Type</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="typeTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #typeTooltip>Library type determines how filenames are parsed and if the UI shows Chapters (Manga) vs Issues (Comics). Book work the same way as Manga but fall back to embedded data.</ng-template>
|
||||
<span class="sr-only" id="library-type-help">Library type determines how filenames are parsed and if the UI shows Chapters (Manga) vs Issues (Comics). Book work the same way as Manga but fall back to embedded data.</span>
|
||||
<select class="form-control" id="library-type" formControlName="type" [attr.disabled]="this.library" aria-describedby="library-type-help">
|
||||
<span class="visually-hidden" id="library-type-help">Library type determines how filenames are parsed and if the UI shows Chapters (Manga) vs Issues (Comics). Book work the same way as Manga but fall back to embedded data.</span>
|
||||
<select class="form-select" id="library-type" formControlName="type" [attr.disabled]="this.library" aria-describedby="library-type-help">
|
||||
<option [value]="i" *ngFor="let opt of libraryTypes; let i = index">{{opt}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
|
||||
<h4>Folders <button type="button" class="btn float-right btn-sm" (click)="openDirectoryPicker()"><i class="fa fa-plus" aria-hidden="true"></i></button></h4>
|
||||
<h4>Folders <button type="button" class="btn float-end btn-sm" (click)="openDirectoryPicker()"><i class="fa fa-plus" aria-hidden="true"></i></button></h4>
|
||||
|
||||
<ul class="list-group" style="width: 100%">
|
||||
<li class="list-group-item" *ngFor="let folder of selectedFolders; let i = index">
|
||||
{{folder}}
|
||||
<button class="btn float-right btn-sm" (click)="removeFolder(folder)"><i class="fa fa-times-circle" aria-hidden="true"></i></button>
|
||||
<button class="btn float-end btn-sm" (click)="removeFolder(folder)"><i class="fa fa-times-circle" aria-hidden="true"></i></button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<form [formGroup]="resetPasswordForm">
|
||||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Reset {{member.username | sentenceCase}}'s Password</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="alert alert-info" *ngIf="errorMessage !== ''">
|
||||
<strong>Error: </strong> {{errorMessage}}
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="password">New Password</label>
|
||||
<div class="mb-3">
|
||||
<label for="password" class="form-label">New Password</label>
|
||||
<input id="password" class="form-control" minlength="4" formControlName="password" type="password">
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
<div class="card w-100 mb-2" style="width: 18rem;">
|
||||
<div class="card-body">
|
||||
<h4 class="card-title">{{update.updateTitle}}
|
||||
<span class="badge badge-secondary" *ngIf="update.updateVersion === installedVersion">Installed</span>
|
||||
<span class="badge badge-secondary" *ngIf="update.updateVersion > installedVersion">Available</span>
|
||||
<span class="badge bg-secondary" *ngIf="update.updateVersion === installedVersion">Installed</span>
|
||||
<span class="badge bg-secondary" *ngIf="update.updateVersion > installedVersion">Available</span>
|
||||
</h4>
|
||||
<h6 class="card-subtitle mb-2 text-muted">Published: {{update.publishDate | date: 'short'}}</h6>
|
||||
|
||||
<pre class="card-text update-body" [innerHtml]="update.updateBody | safeHtml"></pre>
|
||||
<a *ngIf="!update.isDocker" href="{{update.updateUrl}}" class="btn btn-{{indx === 0 ? 'primary' : 'secondary'}} float-right" target="_blank">Download</a>
|
||||
<a *ngIf="!update.isDocker" href="{{update.updateUrl}}" class="btn btn-{{indx === 0 ? 'primary' : 'secondary'}} float-end" target="_blank">Download</a>
|
||||
</div>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div class="container">
|
||||
<h2>Admin Dashboard</h2>
|
||||
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav-tabs nav-pills">
|
||||
<ul ngbNav #nav="ngbNav" [(activeId)]="active" class="nav nav-tabs">
|
||||
<li *ngFor="let tab of tabs" [ngbNavItem]="tab">
|
||||
<a ngbNavLink routerLink="." [fragment]="tab.fragment">{{ tab.title | sentenceCase }}</a>
|
||||
<ng-template ngbNavContent>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
.container {
|
||||
padding-top: 10px;
|
||||
}
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Edit {{member.username | sentenceCase}}</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
||||
<form [formGroup]="userForm">
|
||||
<div class="row no-gutters">
|
||||
<div class="col-md-6 col-sm-12 pr-2">
|
||||
<div class="form-group">
|
||||
<label for="username">Username</label>
|
||||
<div class="row g-0">
|
||||
<div class="col-md-6 col-sm-12 pe-2">
|
||||
<div class="mb-3">
|
||||
<label for="username" class="form-label">Username</label>
|
||||
<input id="username" class="form-control" formControlName="username" type="text">
|
||||
<div id="inviteForm-validations" class="invalid-feedback" *ngIf="userForm.dirty || userForm.touched">
|
||||
<div *ngIf="userForm.get('username')?.errors?.required">
|
||||
|
|
@ -20,8 +20,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12">
|
||||
<div class="form-group" style="width:100%">
|
||||
<label for="email">Email</label>
|
||||
<div class="mb-3" style="width:100%">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input class="form-control" type="email" id="email" formControlName="email" [disabled]="true">
|
||||
<div id="inviteForm-validations" class="invalid-feedback" *ngIf="userForm.dirty || userForm.touched">
|
||||
<div *ngIf="userForm.get('email')?.errors?.required">
|
||||
|
|
@ -35,7 +35,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-6">
|
||||
<app-role-selector (selected)="updateRoleSelection($event)" [allowAdmin]="true" [member]="member"></app-role-selector>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<div class="modal-header">
|
||||
<h4 class="modal-title" id="modal-basic-title">Invite User</h4>
|
||||
<button type="button" class="close" aria-label="Close" (click)="close()">
|
||||
<span aria-hidden="true">×</span>
|
||||
<button type="button" class="btn-close" aria-label="Close" (click)="close()">
|
||||
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
|
|
@ -16,9 +16,9 @@
|
|||
|
||||
|
||||
<form [formGroup]="inviteForm">
|
||||
<div class="row no-gutters">
|
||||
<div class="form-group" style="width:100%">
|
||||
<label for="email">Email</label>
|
||||
<div class="row g-0">
|
||||
<div class="mb-3" style="width:100%">
|
||||
<label for="email" class="form-label">Email</label>
|
||||
<input class="form-control" type="email" id="email" formControlName="email" required>
|
||||
<div id="inviteForm-validations" class="invalid-feedback" *ngIf="inviteForm.dirty || inviteForm.touched">
|
||||
<div *ngIf="email?.errors?.required">
|
||||
|
|
@ -33,7 +33,7 @@
|
|||
<a class="email-link" href="{{emailLink}}" target="_blank">{{emailLink}}</a>
|
||||
</ng-container>
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div class="row g-0">
|
||||
<div class="col-md-6">
|
||||
<app-role-selector (selected)="updateRoleSelection($event)" [allowAdmin]="true"></app-role-selector>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<div class="container-fluid">
|
||||
<div class="row mb-2">
|
||||
<div class="col-8"><h3>Libraries</h3></div>
|
||||
<div class="col-4"><button class="btn btn-primary float-right" (click)="addLibrary()"><i class="fa fa-plus" aria-hidden="true"></i><span class="phone-hidden"> Add Library</span></button></div>
|
||||
<div class="col-4"><button class="btn btn-primary float-end" (click)="addLibrary()"><i class="fa fa-plus" aria-hidden="true"></i><span class="phone-hidden"> Add Library</span></button></div>
|
||||
</div>
|
||||
<ul class="list-group" *ngIf="!createLibraryToggle; else createLibrary">
|
||||
<li *ngFor="let library of libraries; let idx = index; trackby: trackbyLibrary" class="list-group-item">
|
||||
<li *ngFor="let library of libraries; let idx = index; trackby: trackbyLibrary" class="list-group-item no-hover">
|
||||
<div>
|
||||
<h4>
|
||||
<span id="library-name--{{idx}}">{{library.name}}</span>
|
||||
<div class="spinner-border text-primary" style="width: 1.5rem; height: 1.5rem;" role="status" *ngIf="scanInProgress.hasOwnProperty(library.id) && scanInProgress[library.id].progress" title="Scan in progress. Started at {{scanInProgress[library.id].timestamp | date: 'short'}}">
|
||||
<span class="sr-only">Scan for {{library.name}} in progress</span>
|
||||
<span class="visually-hidden">Scan for {{library.name}} in progress</span>
|
||||
</div>
|
||||
<div class="float-right">
|
||||
<button class="btn btn-secondary mr-2 btn-sm" (click)="scanLibrary(library)" placement="top" ngbTooltip="Scan Library" attr.aria-label="Scan Library"><i class="fa fa-sync-alt" title="Scan"></i></button>
|
||||
<button class="btn btn-danger mr-2 btn-sm" [disabled]="deletionInProgress" (click)="deleteLibrary(library)"><i class="fa fa-trash" placement="top" ngbTooltip="Delete Library" attr.aria-label="Delete {{library.name | sentenceCase}}"></i></button>
|
||||
<div class="float-end">
|
||||
<button class="btn btn-secondary me-2 btn-sm" (click)="scanLibrary(library)" placement="top" ngbTooltip="Scan Library" attr.aria-label="Scan Library"><i class="fa fa-sync-alt" title="Scan"></i></button>
|
||||
<button class="btn btn-danger me-2 btn-sm" [disabled]="deletionInProgress" (click)="deleteLibrary(library)"><i class="fa fa-trash" placement="top" ngbTooltip="Delete Library" attr.aria-label="Delete {{library.name | sentenceCase}}"></i></button>
|
||||
<button class="btn btn-primary btn-sm" (click)="editLibrary(library)"><i class="fa fa-pen" placement="top" ngbTooltip="Edit" attr.aria-label="Edit {{library.name | sentenceCase}}"></i></button>
|
||||
</div>
|
||||
</h4>
|
||||
|
|
|
|||
|
|
@ -1,65 +1,63 @@
|
|||
<div class="container-fluid">
|
||||
<form [formGroup]="settingsForm" *ngIf="serverSettings !== undefined">
|
||||
<p class="text-warning pt-2">Port and Logging Level require a manual restart of Kavita to take effect.</p>
|
||||
<div class="form-group">
|
||||
<label for="settings-cachedir">Cache Directory</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="cacheDirectoryTooltip" role="button" tabindex="0"></i>
|
||||
<div class="mb-3">
|
||||
<label for="settings-cachedir" class="form-label">Cache Directory</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="cacheDirectoryTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #cacheDirectoryTooltip>Where the server place temporary files when reading. This will be cleaned up on a regular basis.</ng-template>
|
||||
<span class="sr-only" id="settings-cachedir-help">Where the server place temporary files when reading. This will be cleaned up on a regular basis.</span>
|
||||
<span class="visually-hidden" id="settings-cachedir-help">Where the server place temporary files when reading. This will be cleaned up on a regular basis.</span>
|
||||
<input readonly id="settings-cachedir" aria-describedby="settings-cachedir-help" class="form-control" formControlName="cacheDirectory" type="text">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-bookmarksdir">Bookmarks Directory</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="bookmarksDirectoryTooltip" role="button" tabindex="0"></i>
|
||||
<div class="mb-3">
|
||||
<label for="settings-bookmarksdir" class="form-label">Bookmarks Directory</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="bookmarksDirectoryTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #bookmarksDirectoryTooltip>Location where bookmarks will be stored. Bookmarks are source files and can be large. Choose a location with adequate storage. Directory is managed, other files within directory will be deleted.</ng-template>
|
||||
<span class="sr-only" id="settings-bookmarksdir-help"><ng-container [ngTemplateOutlet]="bookmarksDirectoryTooltip"></ng-container></span>
|
||||
<span class="visually-hidden" id="settings-bookmarksdir-help"><ng-container [ngTemplateOutlet]="bookmarksDirectoryTooltip"></ng-container></span>
|
||||
<div class="input-group">
|
||||
<input readonly id="settings-bookmarksdir" aria-describedby="settings-bookmarksdir-help" class="form-control" formControlName="bookmarksDirectory" type="text" aria-describedby="change-bookmarks-dir">
|
||||
<div class="input-group-append">
|
||||
<button id="change-bookmarks-dir" class="btn btn-primary" (click)="openDirectoryChooser(settingsForm.get('bookmarksDirectory')?.value, 'bookmarksDirectory')">
|
||||
Change
|
||||
</button>
|
||||
</div>
|
||||
<button id="change-bookmarks-dir" class="btn btn-primary" (click)="openDirectoryChooser(settingsForm.get('bookmarksDirectory')?.value, 'bookmarksDirectory')">
|
||||
Change
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="form-group">
|
||||
<!-- <div class="mb-3">
|
||||
<label for="settings-baseurl">Base Url</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="baseUrlTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #baseUrlTooltip>Use this if you want to host Kavita on a base url ie) yourdomain.com/kavita</ng-template>
|
||||
<span class="sr-only" id="settings-baseurl-help">Use this if you want to host Kavita on a base url ie) yourdomain.com/kavita</span>
|
||||
<span class="visually-hidden" id="settings-baseurl-help">Use this if you want to host Kavita on a base url ie) yourdomain.com/kavita</span>
|
||||
<input id="settings-baseurl" aria-describedby="settings-baseurl-help" class="form-control" formControlName="baseUrl" type="text">
|
||||
</div> -->
|
||||
|
||||
<div class="row no-gutters">
|
||||
<div class="form-group col-md-6 col-sm-12 pr-2">
|
||||
<label for="settings-port">Port</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="portTooltip" role="button" tabindex="0"></i>
|
||||
<div class="row g-0 mb-2">
|
||||
<div class="form-group col-md-6 col-sm-12 pe-2">
|
||||
<label for="settings-port" class="form-label">Port</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="portTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #portTooltip>Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect.</ng-template>
|
||||
<span class="sr-only" id="settings-port-help">Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect.</span>
|
||||
<span class="visually-hidden" id="settings-port-help">Port the server listens on. This is fixed if you are running on Docker. Requires restart to take effect.</span>
|
||||
<input id="settings-port" aria-describedby="settings-port-help" class="form-control" formControlName="port" type="number" step="1" min="1" onkeypress="return event.charCode >= 48 && event.charCode <= 57">
|
||||
</div>
|
||||
|
||||
<div class="form-group col-md-6 col-sm-12">
|
||||
<label for="logging-level-port">Logging Level</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="loggingLevelTooltip" role="button" tabindex="0"></i>
|
||||
<label for="logging-level-port" class="form-label">Logging Level</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="loggingLevelTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #loggingLevelTooltip>Use debug to help identify issues. Debug can eat up a lot of disk space. Requires restart to take effect.</ng-template>
|
||||
<span class="sr-only" id="logging-level-port-help">Port the server listens on. Requires restart to take effect.</span>
|
||||
<select id="logging-level-port" aria-describedby="logging-level-port-help" class="form-control" aria-describedby="settings-tasks-scan-help" formControlName="loggingLevel">
|
||||
<span class="visually-hidden" id="logging-level-port-help">Port the server listens on. Requires restart to take effect.</span>
|
||||
<select id="logging-level-port" aria-describedby="logging-level-port-help" class="form-select" aria-describedby="settings-tasks-scan-help" formControlName="loggingLevel">
|
||||
<option *ngFor="let level of logLevels" [value]="level">{{level | titlecase}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="stat-collection" aria-describedby="collection-info">Allow Anonymous Usage Collection</label>
|
||||
<div class="mb-3">
|
||||
<label for="stat-collection" class="form-label" aria-describedby="collection-info">Allow Anonymous Usage Collection</label>
|
||||
<p class="accent" id="collection-info">Send anonymous usage and error information to Kavita's servers. This includes information on your browser, error reporting as well as OS and runtime version. We will use this information to prioritize features, bug fixes, and preformance tuning. Requires restart to take effect.</p>
|
||||
<div class="form-check">
|
||||
<div class="form-check form-switch">
|
||||
<input id="stat-collection" type="checkbox" aria-label="Stat Collection" class="form-check-input" formControlName="allowStatCollection">
|
||||
<label for="stat-collection" class="form-check-label">Send Data</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="opds" aria-describedby="opds-info">OPDS</label>
|
||||
<div class="mb-3">
|
||||
<label for="opds" aria-describedby="opds-info" class="form-label">OPDS</label>
|
||||
<p class="accent" id="opds-info">OPDS support will allow all users to use OPDS to read and download content from the server. If OPDS is enabled, a user will not need download permissions to download media while using it.</p>
|
||||
<div class="form-check">
|
||||
<div class="form-check form-switch">
|
||||
<input id="opds" type="checkbox" aria-label="OPDS Support" class="form-check-input" formControlName="enableOpds">
|
||||
<label for="opds" class="form-check-label">Enable OPDS</label>
|
||||
</div>
|
||||
|
|
@ -70,47 +68,45 @@
|
|||
email service. Set the url of the email service and use the Test button to ensure it works. At any time you can reset to ours. There is no way to disable emails althought confirmation links will always
|
||||
be saved to logs.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
<label for="settings-emailservice">Email Service Url</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="emailServiceTooltip" role="button" tabindex="0"></i>
|
||||
<div class="mb-3">
|
||||
<label for="settings-emailservice" class="form-label">Email Service Url</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="emailServiceTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #emailServiceTooltip>Use fully qualified url of the email service. Do not include ending slash.</ng-template>
|
||||
<span class="sr-only" id="settings-emailservice-help"><ng-container [ngTemplateOutlet]="emailServiceTooltip"></ng-container></span>
|
||||
<span class="visually-hidden" id="settings-emailservice-help"><ng-container [ngTemplateOutlet]="emailServiceTooltip"></ng-container></span>
|
||||
<div class="input-group">
|
||||
<input id="settings-emailservice" aria-describedby="settings-emailservice-help" class="form-control" formControlName="emailServiceUrl" type="text" aria-describedby="change-bookmarks-dir">
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-secondary" (click)="resetEmailServiceUrl()">
|
||||
Reset
|
||||
</button>
|
||||
<button class="btn btn-secondary" (click)="testEmailServiceUrl()">
|
||||
Test
|
||||
</button>
|
||||
</div>
|
||||
<button class="btn btn-outline-secondary" (click)="resetEmailServiceUrl()">
|
||||
Reset
|
||||
</button>
|
||||
<button class="btn btn-outline-secondary" (click)="testEmailServiceUrl()">
|
||||
Test
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<h4>Reoccuring Tasks</h4>
|
||||
<div class="form-group">
|
||||
<label for="settings-tasks-scan">Library Scan</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="taskScanTooltip" role="button" tabindex="0"></i>
|
||||
<div class="mb-3">
|
||||
<label for="settings-tasks-scan" class="form-label">Library Scan</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="taskScanTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #taskScanTooltip>How often Kavita will scan and refresh metatdata around manga files.</ng-template>
|
||||
<span class="sr-only" id="settings-tasks-scan-help">How often Kavita will scan and refresh metatdata around manga files.</span>
|
||||
<select class="form-control" aria-describedby="settings-tasks-scan-help" formControlName="taskScan" id="settings-tasks-scan">
|
||||
<span class="visually-hidden" id="settings-tasks-scan-help">How often Kavita will scan and refresh metatdata around manga files.</span>
|
||||
<select class="form-select" aria-describedby="settings-tasks-scan-help" formControlName="taskScan" id="settings-tasks-scan">
|
||||
<option *ngFor="let freq of taskFrequencies" [value]="freq">{{freq | titlecase}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-tasks-backup">Library Database Backup</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="taskBackupTooltip" role="button" tabindex="0"></i>
|
||||
<div class="mb-3">
|
||||
<label for="settings-tasks-backup" class="form-label">Library Database Backup</label> <i class="fa fa-info-circle" placement="right" [ngbTooltip]="taskBackupTooltip" role="button" tabindex="0"></i>
|
||||
<ng-template #taskBackupTooltip>How often Kavita will backup the database.</ng-template>
|
||||
<span class="sr-only" id="settings-tasks-backup-help">How often Kavita will backup the database.</span>
|
||||
<select class="form-control" aria-describedby="settings-tasks-backup-help" formControlName="taskBackup" id="settings-tasks-backup">
|
||||
<span class="visually-hidden" id="settings-tasks-backup-help">How often Kavita will backup the database.</span>
|
||||
<select class="form-select" aria-describedby="settings-tasks-backup-help" formControlName="taskBackup" id="settings-tasks-backup">
|
||||
<option *ngFor="let freq of taskFrequencies" [value]="freq">{{freq | titlecase}}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="float-right">
|
||||
<button type="button" class="btn btn-secondary mr-2" (click)="resetToDefaults()">Reset to Default</button>
|
||||
<button type="button" class="btn btn-secondary mr-2" (click)="resetForm()">Reset</button>
|
||||
<button type="submit" class="btn btn-primary" (click)="saveSettings()" [disabled]="!settingsForm.touched && !settingsForm.dirty">Save</button>
|
||||
<div class="col-auto d-flex d-md-block justify-content-sm-center text-md-end">
|
||||
<button type="button" class="flex-fill btn btn-secondary me-2" (click)="resetToDefaults()">Reset to Default</button>
|
||||
<button type="button" class="flex-fill btn btn-secondary me-2" (click)="resetForm()">Reset</button>
|
||||
<button type="submit" class="flex-fill btn btn-primary" (click)="saveSettings()" [disabled]="!settingsForm.touched && !settingsForm.dirty">Save</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
<div class="container-fluid">
|
||||
|
||||
<div class="float-right">
|
||||
<div class="float-end">
|
||||
<div class="d-inline-block" ngbDropdown #myDrop="ngbDropdown">
|
||||
<button class="btn btn-outline-primary mr-2" id="dropdownManual" ngbDropdownToggle>
|
||||
<button class="btn btn-outline-primary me-2" id="dropdownManual" ngbDropdownToggle>
|
||||
<ng-container *ngIf="backupDBInProgress || clearCacheInProgress || isCheckingForUpdate || downloadLogsInProgress">
|
||||
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
|
||||
<span class="sr-only">Loading...</span>
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</ng-container>
|
||||
Actions
|
||||
</button>
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
<h3>About System</h3>
|
||||
<hr/>
|
||||
<div class="form-group" *ngIf="serverInfo">
|
||||
<div class="mb-3" *ngIf="serverInfo">
|
||||
<dl>
|
||||
<dt>Version</dt>
|
||||
<dd>{{serverInfo.kavitaVersion}}</dd>
|
||||
|
|
|
|||
|
|
@ -4,28 +4,28 @@
|
|||
<ng-container>
|
||||
<div class="row mb-2">
|
||||
<div class="col-8"><h3>Pending Invites</h3></div>
|
||||
<div class="col-4"><button class="btn btn-primary float-right" (click)="inviteUser()"><i class="fa fa-plus" aria-hidden="true"></i><span class="phone-hidden"> Invite</span></button></div>
|
||||
<div class="col-4"><button class="btn btn-primary float-end" (click)="inviteUser()"><i class="fa fa-plus" aria-hidden="true"></i><span class="phone-hidden"> Invite</span></button></div>
|
||||
</div>
|
||||
<ul class="list-group">
|
||||
<li class="list-group-item" *ngFor="let invite of pendingInvites; let idx = index;">
|
||||
<li class="list-group-item no-hover" *ngFor="let invite of pendingInvites; let idx = index;">
|
||||
<div>
|
||||
<h4>
|
||||
<span id="member-name--{{idx}}">{{invite.username | titlecase}} </span>
|
||||
<div class="float-right">
|
||||
<button class="btn btn-danger mr-2" (click)="deleteUser(invite)">Cancel</button>
|
||||
<button class="btn btn-secondary mr-2" (click)="resendEmail(invite)">Resend</button>
|
||||
<div class="float-end">
|
||||
<button class="btn btn-danger me-2" (click)="deleteUser(invite)">Cancel</button>
|
||||
<button class="btn btn-secondary me-2" (click)="resendEmail(invite)">Resend</button>
|
||||
</div>
|
||||
</h4>
|
||||
|
||||
<div>Invited: {{invite.created | date: 'short'}}</div>
|
||||
</div>
|
||||
</li>
|
||||
<li *ngIf="loadingMembers" class="list-group-item">
|
||||
<li *ngIf="loadingMembers" class="list-group-item no-hover">
|
||||
<div class="spinner-border text-secondary" role="status">
|
||||
<span class="invisible">Loading...</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class="list-group-item" *ngIf="pendingInvites.length === 0 && !loadingMembers">
|
||||
<li class="list-group-item no-hover" *ngIf="pendingInvites.length === 0 && !loadingMembers">
|
||||
There are no invited Users
|
||||
</li>
|
||||
</ul>
|
||||
|
|
@ -35,18 +35,18 @@
|
|||
|
||||
<h3 class="mt-3">Active Users</h3>
|
||||
<ul class="list-group">
|
||||
<li *ngFor="let member of members; let idx = index;" class="list-group-item">
|
||||
<li *ngFor="let member of members; let idx = index;" class="list-group-item no-hover">
|
||||
<div>
|
||||
<h4>
|
||||
<i class="presence fa fa-circle" title="Active" aria-hidden="true" *ngIf="false && (messageHub.onlineUsers$ | async)?.includes(member.username)"></i>
|
||||
<span id="member-name--{{idx}}">{{member.username | titlecase}} </span>
|
||||
<span *ngIf="member.username === loggedInUsername">
|
||||
<i class="fas fa-star" aria-hidden="true"></i>
|
||||
<span class="sr-only">(You)</span>
|
||||
<span class="visually-hidden">(You)</span>
|
||||
</span>
|
||||
<div class="float-right" *ngIf="canEditMember(member)">
|
||||
<button class="btn btn-danger mr-2" (click)="deleteUser(member)" placement="top" ngbTooltip="Delete User" attr.aria-label="Delete User {{member.username | titlecase}}"><i class="fa fa-trash" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-secondary mr-2" (click)="updatePassword(member)" placement="top" ngbTooltip="Change Password" attr.aria-label="Change Password for {{member.username | titlecase}}"><i class="fa fa-key" aria-hidden="true"></i></button>
|
||||
<div class="float-end" *ngIf="canEditMember(member)">
|
||||
<button class="btn btn-danger me-2" (click)="deleteUser(member)" placement="top" ngbTooltip="Delete User" attr.aria-label="Delete User {{member.username | titlecase}}"><i class="fa fa-trash" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-secondary me-2" (click)="updatePassword(member)" placement="top" ngbTooltip="Change Password" attr.aria-label="Change Password for {{member.username | titlecase}}"><i class="fa fa-key" aria-hidden="true"></i></button>
|
||||
<button class="btn btn-primary" (click)="openEditUser(member)" placement="top" ngbTooltip="Edit" attr.aria-label="Edit {{member.username | titlecase}}"><i class="fa fa-pen" aria-hidden="true"></i></button>
|
||||
</div>
|
||||
</h4>
|
||||
|
|
@ -57,10 +57,10 @@
|
|||
</ng-template>
|
||||
</div>
|
||||
<div *ngIf="!hasAdminRole(member)">Sharing: {{formatLibraries(member)}}</div>
|
||||
<div>
|
||||
<div class="row g-0">
|
||||
Roles: <span *ngIf="getRoles(member).length === 0; else showRoles">None</span>
|
||||
<ng-template #showRoles>
|
||||
<app-tag-badge *ngFor="let role of getRoles(member)">{{role}}</app-tag-badge>
|
||||
<app-tag-badge *ngFor="let role of getRoles(member)" class="col-auto">{{role}}</app-tag-badge>
|
||||
</ng-template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue