diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index 071d1eaae..ec0088aba 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -46,7 +46,7 @@ namespace API.Data Name = "E-Ink", NormalizedName = Parser.Parser.Normalize("E-Ink"), Provider = ThemeProvider.System, - FileName = "eink.scss", + FileName = "e-ink.scss", IsDefault = false, }, }; diff --git a/UI/Web/package-lock.json b/UI/Web/package-lock.json index 85739725d..86b37394f 100644 --- a/UI/Web/package-lock.json +++ b/UI/Web/package-lock.json @@ -9173,14 +9173,6 @@ "tslib": "^2.0.0" } }, - "ng-lazyload-image": { - "version": "9.1.2", - "resolved": "https://registry.npmjs.org/ng-lazyload-image/-/ng-lazyload-image-9.1.2.tgz", - "integrity": "sha512-E5oz5HdTRtYW/TH+jceT4VMcRXKdX9Ut82eEwt2K0/bFAXKU14HluCFa8cMidPBgSa08Mlf+gmoKCTvAfUPgag==", - "requires": { - "tslib": "^2.3.0" - } - }, "ngx-file-drop": { "version": "13.0.0", "resolved": "https://registry.npmjs.org/ngx-file-drop/-/ngx-file-drop-13.0.0.tgz", diff --git a/UI/Web/package.json b/UI/Web/package.json index fd021a1c8..d43401c1a 100644 --- a/UI/Web/package.json +++ b/UI/Web/package.json @@ -38,7 +38,6 @@ "file-saver": "^2.0.5", "lazysizes": "^5.3.2", "ng-circle-progress": "^1.6.0", - "ng-lazyload-image": "^9.1.2", "ngx-file-drop": "^13.0.0", "ngx-toastr": "^14.2.1", "rxjs": "~7.5.4", diff --git a/UI/Web/src/app/_models/events/refresh-metadata-event.ts b/UI/Web/src/app/_models/events/refresh-metadata-event.ts deleted file mode 100644 index 51fda3301..000000000 --- a/UI/Web/src/app/_models/events/refresh-metadata-event.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface RefreshMetadataEvent { - libraryId: number; - seriesId: number; -} \ No newline at end of file diff --git a/UI/Web/src/app/person-role.pipe.ts b/UI/Web/src/app/_pipes/person-role.pipe.ts similarity index 94% rename from UI/Web/src/app/person-role.pipe.ts rename to UI/Web/src/app/_pipes/person-role.pipe.ts index 9559e4ad6..f71b4412b 100644 --- a/UI/Web/src/app/person-role.pipe.ts +++ b/UI/Web/src/app/_pipes/person-role.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { PersonRole } from './_models/person'; +import { PersonRole } from '../_models/person'; @Pipe({ name: 'personRole' diff --git a/UI/Web/src/app/publication-status.pipe.ts b/UI/Web/src/app/_pipes/publication-status.pipe.ts similarity index 85% rename from UI/Web/src/app/publication-status.pipe.ts rename to UI/Web/src/app/_pipes/publication-status.pipe.ts index d3beecacd..d5a9cea06 100644 --- a/UI/Web/src/app/publication-status.pipe.ts +++ b/UI/Web/src/app/_pipes/publication-status.pipe.ts @@ -1,5 +1,5 @@ import { Pipe, PipeTransform } from '@angular/core'; -import { PublicationStatus } from './_models/metadata/publication-status'; +import { PublicationStatus } from '../_models/metadata/publication-status'; @Pipe({ name: 'publicationStatus' diff --git a/UI/Web/src/app/_services/account.service.ts b/UI/Web/src/app/_services/account.service.ts index ce43a0b3f..4d3a2747d 100644 --- a/UI/Web/src/app/_services/account.service.ts +++ b/UI/Web/src/app/_services/account.service.ts @@ -84,6 +84,8 @@ export class AccountService implements OnDestroy { } else { this.themeService.setTheme(this.themeService.defaultTheme); } + } else { + this.themeService.setTheme(this.themeService.defaultTheme); } this.currentUserSource.next(user); diff --git a/UI/Web/src/app/_services/series.service.ts b/UI/Web/src/app/_services/series.service.ts index c73b9f2c0..1b78beb5e 100644 --- a/UI/Web/src/app/_services/series.service.ts +++ b/UI/Web/src/app/_services/series.service.ts @@ -149,6 +149,7 @@ export class SeriesService { } scan(libraryId: number, seriesId: number) { + // TODO: Pipe and put a toaster up: this.toastr.info('Scan queued for ' + series.name); return this.httpClient.post(this.baseUrl + 'series/scan', {libraryId: libraryId, seriesId: seriesId}); } diff --git a/UI/Web/src/app/admin/changelog/changelog.component.html b/UI/Web/src/app/admin/changelog/changelog.component.html index 481544f9e..55ab39cfd 100644 --- a/UI/Web/src/app/admin/changelog/changelog.component.html +++ b/UI/Web/src/app/admin/changelog/changelog.component.html @@ -8,8 +8,12 @@
Published: {{update.publishDate | date: 'short'}}
-

-          Download
+
+          
+            
+          
+ Installed + Download diff --git a/UI/Web/src/app/admin/manage-users/manage-users.component.html b/UI/Web/src/app/admin/manage-users/manage-users.component.html index ac8538f63..c4bbfe553 100644 --- a/UI/Web/src/app/admin/manage-users/manage-users.component.html +++ b/UI/Web/src/app/admin/manage-users/manage-users.component.html @@ -45,9 +45,9 @@ (You)
- - - + + +
Last Active: diff --git a/UI/Web/src/app/app.module.ts b/UI/Web/src/app/app.module.ts index 5b79f3a42..8ced2e262 100644 --- a/UI/Web/src/app/app.module.ts +++ b/UI/Web/src/app/app.module.ts @@ -31,12 +31,12 @@ import { ReadingListModule } from './reading-list/reading-list.module'; import { SAVER, getSaver } from './shared/_providers/saver.provider'; import { ConfigData } from './_models/config-data'; import { NavEventsToggleComponent } from './nav-events-toggle/nav-events-toggle.component'; -import { PersonRolePipe } from './person-role.pipe'; +import { PersonRolePipe } from './_pipes/person-role.pipe'; import { SeriesMetadataDetailComponent } from './series-metadata-detail/series-metadata-detail.component'; import { AllSeriesComponent } from './all-series/all-series.component'; -import { PublicationStatusPipe } from './publication-status.pipe'; import { RegistrationModule } from './registration/registration.module'; import { GroupedTypeaheadComponent } from './grouped-typeahead/grouped-typeahead.component'; +import { PublicationStatusPipe } from './_pipes/publication-status.pipe'; import { ThemeTestComponent } from './theme-test/theme-test.component'; @@ -71,7 +71,7 @@ import { ThemeTestComponent } from './theme-test/theme-test.component'; NgbDropdownModule, // Nav NgbPopoverModule, // Nav Events toggle - NgbRatingModule, // Series Detail + NgbRatingModule, // Series Detail & Filter NgbNavModule, NgbPaginationModule, @@ -85,6 +85,7 @@ import { ThemeTestComponent } from './theme-test/theme-test.component'; ReadingListModule, RegistrationModule, + ToastrModule.forRoot({ positionClass: 'toast-bottom-right', preventDuplicates: true, diff --git a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html index fb73c2d87..b525f2bc9 100644 --- a/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html +++ b/UI/Web/src/app/cards/card-detail-layout/card-detail-layout.component.html @@ -335,7 +335,7 @@ - diff --git a/UI/Web/src/app/cards/card-item/card-item.component.html b/UI/Web/src/app/cards/card-item/card-item.component.html index 5f2aecde5..c197783bb 100644 --- a/UI/Web/src/app/cards/card-item/card-item.component.html +++ b/UI/Web/src/app/cards/card-item/card-item.component.html @@ -23,7 +23,7 @@
- +
@@ -34,7 +34,7 @@
- + (promoted) diff --git a/UI/Web/src/app/cards/card-item/card-item.component.scss b/UI/Web/src/app/cards/card-item/card-item.component.scss index 171697a1e..44ee88c77 100644 --- a/UI/Web/src/app/cards/card-item/card-item.component.scss +++ b/UI/Web/src/app/cards/card-item/card-item.component.scss @@ -97,6 +97,7 @@ $image-width: 160px; input[type="checkbox"] { width: 20px; height: 20px; + color: var(--checkbox-bg-color); } } @@ -157,9 +158,5 @@ $image-width: 160px; width: 100%; height: 230px; z-index: 10; - transition: opacity 0.2s; -} - -.card-overlay:hover { - opacity: 0; + transition: all 0.2s; } diff --git a/UI/Web/src/app/cards/cards.module.ts b/UI/Web/src/app/cards/cards.module.ts index 8b21fe1ac..a64f3a056 100644 --- a/UI/Web/src/app/cards/cards.module.ts +++ b/UI/Web/src/app/cards/cards.module.ts @@ -7,7 +7,6 @@ import { EditSeriesModalComponent } from './_modals/edit-series-modal/edit-serie import { EditCollectionTagsComponent } from './_modals/edit-collection-tags/edit-collection-tags.component'; import { ChangeCoverImageModalComponent } from './_modals/change-cover-image/change-cover-image-modal.component'; import { BookmarksModalComponent } from './_modals/bookmarks-modal/bookmarks-modal.component'; -import { LazyLoadImageModule } from 'ng-lazyload-image'; import { NgbTooltipModule, NgbCollapseModule, NgbPaginationModule, NgbDropdownModule, NgbProgressbarModule, NgbNavModule, NgbRatingModule } from '@ng-bootstrap/ng-bootstrap'; import { CardActionablesComponent } from './card-item/card-actionables/card-actionables.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -61,7 +60,6 @@ import { BookmarkComponent } from './bookmark/bookmark.component'; NgbRatingModule, NgbNavModule, //Series Detail - LazyLoadImageModule, NgbPaginationModule, // CardDetailLayoutComponent NgbDropdownModule, NgbProgressbarModule, diff --git a/UI/Web/src/app/cards/series-card/series-card.component.html b/UI/Web/src/app/cards/series-card/series-card.component.html index 8653e3f9d..846e0af3f 100644 --- a/UI/Web/src/app/cards/series-card/series-card.component.html +++ b/UI/Web/src/app/cards/series-card/series-card.component.html @@ -1,6 +1,6 @@ \ No newline at end of file diff --git a/UI/Web/src/app/cards/series-card/series-card.component.ts b/UI/Web/src/app/cards/series-card/series-card.component.ts index c9acf96d3..a460a16f5 100644 --- a/UI/Web/src/app/cards/series-card/series-card.component.ts +++ b/UI/Web/src/app/cards/series-card/series-card.component.ts @@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output } import { Router } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { ToastrService } from 'ngx-toastr'; -import { take, takeUntil, takeWhile } from 'rxjs/operators'; +import { take } from 'rxjs/operators'; import { Series } from 'src/app/_models/series'; import { AccountService } from 'src/app/_services/account.service'; import { ImageService } from 'src/app/_services/image.service'; @@ -11,7 +11,6 @@ import { SeriesService } from 'src/app/_services/series.service'; import { ConfirmService } from 'src/app/shared/confirm.service'; import { ActionService } from 'src/app/_services/action.service'; import { EditSeriesModalComponent } from '../_modals/edit-series-modal/edit-series-modal.component'; -import { RefreshMetadataEvent } from 'src/app/_models/events/refresh-metadata-event'; import { MessageHubService } from 'src/app/_services/message-hub.service'; import { Subject } from 'rxjs'; diff --git a/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.html b/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.html index 8faa38656..98d466c35 100644 --- a/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.html +++ b/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.html @@ -8,8 +8,8 @@
diff --git a/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.ts b/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.ts index 6500570f1..995ea6c0c 100644 --- a/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.ts +++ b/UI/Web/src/app/carousel/carousel-reel/carousel-reel.component.ts @@ -16,7 +16,6 @@ export class CarouselReelComponent implements OnInit { swiper: Swiper | undefined; - trackByIdentity: (index: number, item: any) => string; get isEnd() { diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.html b/UI/Web/src/app/collections/collection-detail/collection-detail.component.html index 08c97266b..040ae7e4d 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.html +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.html @@ -1,7 +1,7 @@
-
- +
+
diff --git a/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss b/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss index b392abee1..a3f113c59 100644 --- a/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss +++ b/UI/Web/src/app/collections/collection-detail/collection-detail.component.scss @@ -1,20 +1,16 @@ -@import '~bootstrap/scss/mixins/breakpoints'; - .poster { - width: 100%; - max-height: 481px; + width: 100%; + max-width: 300px; +} + +@media(max-width: var(--grid-breakpoints-sm)) { + .poster { + display: none; } - - - // Including breakpoint has issue with resovling variable, so copying gridpoints here - @include media-breakpoint-down(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) { - .poster { - display: none; - } +} + +@media(max-width: var(--grid-breakpoints-sm)) { + .read-btn--text { + display: none; } - - @include media-breakpoint-down(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)) { - .read-btn--text { - display: none; - } - } \ No newline at end of file +} diff --git a/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.html b/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.html index 1d9445841..38fab78d6 100644 --- a/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.html +++ b/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.html @@ -85,7 +85,8 @@ - +
  • diff --git a/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.scss b/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.scss index 6dcd08e5f..86c48a42d 100644 --- a/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.scss +++ b/UI/Web/src/app/grouped-typeahead/grouped-typeahead.component.scss @@ -42,20 +42,6 @@ form { display: flex; } - // .close { - // cursor: pointer; - // position: absolute; - // top: 7px; - // right: 10px; - // } - - // @media only screen and (max-width:650px) { - // .close { - // top: 50%; - // transform: translate(0, -60%); - // } - // } - input { outline: 0 !important; @@ -67,7 +53,7 @@ form { text-indent: 0 !important; line-height: inherit !important; box-shadow: none !important; - width: 200px; + width: 300px; transition-property: all; transition-duration: 0.3s; display: block; diff --git a/UI/Web/src/app/library/library.component.html b/UI/Web/src/app/library/library.component.html index 144907d68..0eb8f7aa9 100644 --- a/UI/Web/src/app/library/library.component.html +++ b/UI/Web/src/app/library/library.component.html @@ -25,7 +25,7 @@ - + diff --git a/UI/Web/src/app/library/library.component.ts b/UI/Web/src/app/library/library.component.ts index d89a22f96..19462c71b 100644 --- a/UI/Web/src/app/library/library.component.ts +++ b/UI/Web/src/app/library/library.component.ts @@ -3,7 +3,6 @@ import { Title } from '@angular/platform-browser'; import { Router } from '@angular/router'; import { ReplaySubject, Subject } from 'rxjs'; import { debounceTime, take, takeUntil } from 'rxjs/operators'; -import { RefreshMetadataEvent } from '../_models/events/refresh-metadata-event'; import { SeriesAddedEvent } from '../_models/events/series-added-event'; import { SeriesRemovedEvent } from '../_models/events/series-removed-event'; import { Library } from '../_models/library'; diff --git a/UI/Web/src/app/nav-header/nav-header.component.scss b/UI/Web/src/app/nav-header/nav-header.component.scss index 0b77525fa..33f04bd4b 100644 --- a/UI/Web/src/app/nav-header/nav-header.component.scss +++ b/UI/Web/src/app/nav-header/nav-header.component.scss @@ -39,6 +39,10 @@ font-family: var(--brand-font-family); font-weight: bold; + &:hover { + text-decoration: none; + } + .logo { max-height: 28px; vertical-align: top; diff --git a/UI/Web/src/app/series-detail/series-detail.component.ts b/UI/Web/src/app/series-detail/series-detail.component.ts index d28acde9e..281a8efe1 100644 --- a/UI/Web/src/app/series-detail/series-detail.component.ts +++ b/UI/Web/src/app/series-detail/series-detail.component.ts @@ -15,7 +15,6 @@ import { DownloadService } from '../shared/_services/download.service'; import { KEY_CODES, UtilityService } from '../shared/_services/utility.service'; import { ReviewSeriesModalComponent } from '../_modals/review-series-modal/review-series-modal.component'; import { Chapter } from '../_models/chapter'; -import { RefreshMetadataEvent } from '../_models/events/refresh-metadata-event'; import { ScanSeriesEvent } from '../_models/events/scan-series-event'; import { SeriesRemovedEvent } from '../_models/events/series-removed-event'; import { LibraryType } from '../_models/library'; diff --git a/UI/Web/src/app/shared/image/image.component.html b/UI/Web/src/app/shared/image/image.component.html index 42cc9fa9b..10248a9fc 100644 --- a/UI/Web/src/app/shared/image/image.component.html +++ b/UI/Web/src/app/shared/image/image.component.html @@ -1,3 +1,7 @@ + + diff --git a/UI/Web/src/app/shared/shared.module.ts b/UI/Web/src/app/shared/shared.module.ts index 99965c696..1a6c17a6c 100644 --- a/UI/Web/src/app/shared/shared.module.ts +++ b/UI/Web/src/app/shared/shared.module.ts @@ -45,20 +45,18 @@ import { ImageComponent } from './image/image.component'; NgCircleProgressModule.forRoot(), ], exports: [ - SafeHtmlPipe, - SentenceCasePipe, - ReadMoreComponent, - DrawerComponent, - TagBadgeComponent, - ShowIfScrollbarDirective, - A11yClickDirective, - SeriesFormatComponent, - SeriesFormatComponent, - TagBadgeComponent, - CircularLoaderComponent, - PersonBadgeComponent, - BadgeExpanderComponent, - ImageComponent + SafeHtmlPipe, // Used globally + SentenceCasePipe, // Used globablly + ReadMoreComponent, // Used globably + DrawerComponent, // Can be replaced with boostrap offscreen canvas (v5) + ShowIfScrollbarDirective, // Used book reader only? + A11yClickDirective, // Used globally + SeriesFormatComponent, // Used globally + TagBadgeComponent, // Used globally + CircularLoaderComponent, // Used in Cards only + PersonBadgeComponent, // Used Series Detail + BadgeExpanderComponent, // Used globally + ImageComponent // Used globally ], }) export class SharedModule { } diff --git a/UI/Web/src/app/typeahead/typeahead.component.scss b/UI/Web/src/app/typeahead/typeahead.component.scss index 58dbebc3a..9ee84055d 100644 --- a/UI/Web/src/app/typeahead/typeahead.component.scss +++ b/UI/Web/src/app/typeahead/typeahead.component.scss @@ -1,3 +1,7 @@ +form { + position: relative; +} + input { width: 15px; opacity: 1px; @@ -42,6 +46,7 @@ input { .dropdown { width: 100%; + min-width: 10rem; background: var(--input-bg-color); z-index:1000; margin: 2px 0 0; @@ -56,6 +61,7 @@ input { .list-group-item { padding: 5px 10px; + width: 100%; } @@ -64,9 +70,6 @@ input { } } -.list-group-item { - cursor: pointer; -} .spinner-border { position: absolute; diff --git a/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.spec.ts b/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.spec.ts new file mode 100644 index 000000000..e6197fdb9 --- /dev/null +++ b/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.spec.ts @@ -0,0 +1,26 @@ +import { ThemeProvider } from '../../_models/preferences/site-theme'; +import { SiteThemeProviderPipe } from './site-theme-provider.pipe'; + +describe('SiteThemeProviderPipe', () => { + let siteThemeProviderPipe: SiteThemeProviderPipe; + + beforeEach(() => { + siteThemeProviderPipe = new SiteThemeProviderPipe(); + }) + + it('translates system to System', () => { + expect(siteThemeProviderPipe.transform(ThemeProvider.System)).toBe('System'); + }); + + it('translates user to User', () => { + expect(siteThemeProviderPipe.transform(ThemeProvider.User)).toBe('User'); + }); + + it('translates null to empty string', () => { + expect(siteThemeProviderPipe.transform(null)).toBe(''); + }); + + it('translates undefined to empty string', () => { + expect(siteThemeProviderPipe.transform(undefined)).toBe(''); + }); +}); diff --git a/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.ts b/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.ts new file mode 100644 index 000000000..b9e589dd9 --- /dev/null +++ b/UI/Web/src/app/user-settings/_pipes/site-theme-provider.pipe.ts @@ -0,0 +1,22 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { ThemeProvider } from 'src/app/_models/preferences/site-theme'; + + +@Pipe({ + name: 'siteThemeProvider' +}) +export class SiteThemeProviderPipe implements PipeTransform { + + transform(provider: ThemeProvider | undefined | null): string { + if (provider === null || provider === undefined) return ''; + switch(provider) { + case ThemeProvider.System: + return 'System'; + case ThemeProvider.User: + return 'User'; + default: + return ''; + } + } + +} diff --git a/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html b/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html index c84faa80e..3f5e23059 100644 --- a/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html +++ b/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html @@ -10,13 +10,10 @@
    -
    +
    {{theme.name | sentenceCase}}
    -
    {{theme.provider === ThemeProvider.System ? 'System' : 'User'}}
    - +
    {{theme.provider | siteThemeProvider}}
    diff --git a/UI/Web/src/app/user-settings/user-settings.module.ts b/UI/Web/src/app/user-settings/user-settings.module.ts index 47680a55c..33de715b0 100644 --- a/UI/Web/src/app/user-settings/user-settings.module.ts +++ b/UI/Web/src/app/user-settings/user-settings.module.ts @@ -9,6 +9,8 @@ import { UserSettingsRoutingModule } from './user-settings-routing.module'; import { ApiKeyComponent } from './api-key/api-key.component'; import { SharedModule } from '../shared/shared.module'; import { ThemeManagerComponent } from './theme-manager/theme-manager.component'; +import { SiteThemeProviderPipe } from './_pipes/site-theme-provider.pipe'; + @@ -17,7 +19,8 @@ import { ThemeManagerComponent } from './theme-manager/theme-manager.component'; SeriesBookmarksComponent, UserPreferencesComponent, ApiKeyComponent, - ThemeManagerComponent + ThemeManagerComponent, + SiteThemeProviderPipe, ], imports: [ CommonModule, @@ -28,6 +31,9 @@ import { ThemeManagerComponent } from './theme-manager/theme-manager.component'; NgxSliderModule, UserSettingsRoutingModule, SharedModule // SentenceCase pipe + ], + exports: [ + SiteThemeProviderPipe ] }) export class UserSettingsModule { } diff --git a/UI/Web/src/styles.scss b/UI/Web/src/styles.scss index ecfad294a..d2fc43d1a 100644 --- a/UI/Web/src/styles.scss +++ b/UI/Web/src/styles.scss @@ -3,7 +3,7 @@ // Import themes which define the css variables we use to customize the app @import './theme/themes/light'; @import './theme/themes/dark'; -@import './theme/themes/eink'; +@import './theme/themes/e-ink'; // Import colors for overrides of bootstrap theme @import './theme/toastr'; diff --git a/UI/Web/src/theme/_variables.scss b/UI/Web/src/theme/_variables.scss index f75f0574e..31f5159e3 100644 --- a/UI/Web/src/theme/_variables.scss +++ b/UI/Web/src/theme/_variables.scss @@ -9,6 +9,8 @@ $theme-colors: ( ); $form-select-indicator-color:#cecece; +$accordion-icon-color: #cecece; +$accordion-icon-active-color: #cecece; $grid-breakpoints-xs: 0; $grid-breakpoints-sm: 576px; diff --git a/UI/Web/src/theme/components/_accordion.scss b/UI/Web/src/theme/components/_accordion.scss index 53038fcab..fd415d641 100644 --- a/UI/Web/src/theme/components/_accordion.scss +++ b/UI/Web/src/theme/components/_accordion.scss @@ -13,12 +13,19 @@ } } -.accordion-button:not(.collapsed) { - color: var(--accordion-header-text-color); - background-color: var(--accordion-body-bg-color); -} +.accordion-button { + &:not(.collapsed) { + color: var(--accordion-header-text-color); + background-color: var(--accordion-body-bg-color); + } -.accordion-button.collapsed { - color: var(--accordion-header-collapsed-text-color); - background-color: var(--accordion-header-collapsed-bg-color); + &.collapsed { + color: var(--accordion-header-collapsed-text-color); + background-color: var(--accordion-header-collapsed-bg-color); + } + + &:focus { + border-color: var(--accordion-button-focus-border-color); + box-shadow: var(--accordion-button-focus-box-shadow); + } } diff --git a/UI/Web/src/theme/components/_anchors.scss b/UI/Web/src/theme/components/_anchors.scss index cc353614f..67954b5e7 100644 --- a/UI/Web/src/theme/components/_anchors.scss +++ b/UI/Web/src/theme/components/_anchors.scss @@ -6,10 +6,27 @@ a:not(.dark-exempt) { } } + a.btn { + color: inherit; + text-decoration: none; + + &:hover { + text-decoration: none; + } + } + a.read-more-link { font-weight: bold; text-decoration: none; color: var(--body-text-color); cursor: pointer; color: var(--body-text-color) !important; -} \ No newline at end of file +} + +a { + text-decoration: none; + + &:hover { + text-decoration: underline; + } +} diff --git a/UI/Web/src/theme/components/_buttons.scss b/UI/Web/src/theme/components/_buttons.scss index fb0798c83..da793f7ba 100644 --- a/UI/Web/src/theme/components/_buttons.scss +++ b/UI/Web/src/theme/components/_buttons.scss @@ -69,3 +69,7 @@ button:disabled, .form-control:disabled, .form-control[readonly], .disabled, :di button i.fa { color: var(--btn-fa-icon-color); } + +.btn-check:focus + .btn, .btn:focus { + box-shadow: 0 0 0 0.25rem var(--btn-focus-boxshadow-color); +} diff --git a/UI/Web/src/theme/components/_card.scss b/UI/Web/src/theme/components/_card.scss index 16b246b3e..5f8d544ba 100644 --- a/UI/Web/src/theme/components/_card.scss +++ b/UI/Web/src/theme/components/_card.scss @@ -4,11 +4,11 @@ border-color: var(--card-border-color); position: relative; - .overlay:hover { - background-color: var(--card-overlay-hover-bg-color); - } - .card-overlay { - background-color: var(--card-overlay-hover-bg-color); + background-color: var(--card-overlay-bg-color); + + &:hover { + background-color: var(--card-overlay-hover-bg-color); + } } } diff --git a/UI/Web/src/theme/components/_checkbox.scss b/UI/Web/src/theme/components/_checkbox.scss index cb4300763..48068c0d2 100644 --- a/UI/Web/src/theme/components/_checkbox.scss +++ b/UI/Web/src/theme/components/_checkbox.scss @@ -8,8 +8,13 @@ border-color: var(--checkbox-checked-bg-color); } - &:focus, &:hover { + &:hover { border-color: var(--checkbox-focus-border-color); } + + &:focus { + border-color: var(--checkbox-focus-border-color); + box-shadow: 0 0 0 0.25rem var(--checkbox-focus-boxshadow-color); + } } diff --git a/UI/Web/src/theme/components/_dropdown.scss b/UI/Web/src/theme/components/_dropdown.scss index 0cebe377b..0826259f0 100644 --- a/UI/Web/src/theme/components/_dropdown.scss +++ b/UI/Web/src/theme/components/_dropdown.scss @@ -10,6 +10,7 @@ &:hover, &:focus { color: var(--dropdown-item-hover-text-color); background-color: var(--dropdown-item-hover-bg-color); + text-decoration: none; } } } \ No newline at end of file diff --git a/UI/Web/src/theme/components/_input.scss b/UI/Web/src/theme/components/_input.scss index 72a27c8c0..7c6f07e58 100644 --- a/UI/Web/src/theme/components/_input.scss +++ b/UI/Web/src/theme/components/_input.scss @@ -7,6 +7,7 @@ input, .form-control { border-color: var(--input-focused-border-color); background-color: var(--input-bg-color); color: var(--input-text-color); + box-shadow: 0 0 0 0.25rem var(--input-focus-boxshadow-color); } &:read-only { diff --git a/UI/Web/src/theme/components/_list.scss b/UI/Web/src/theme/components/_list.scss index 81875258c..09ebdd08b 100644 --- a/UI/Web/src/theme/components/_list.scss +++ b/UI/Web/src/theme/components/_list.scss @@ -3,7 +3,6 @@ background-color: var(--list-group-item-bg-color); border-color: var(--list-group-item-border-color); - // TODO: We need a css class where we can exclude hover effects, like when list is just used for layout purposes &:hover { color: var(--list-group-hover-text-color); background-color: var(--list-group-hover-bg-color); @@ -12,6 +11,7 @@ &.active { color: var(--list-group-hover-text-color); background-color: var(--list-group-hover-bg-color); + border-color: var(--list-group-active-border-color); } &.no-hover:hover { diff --git a/UI/Web/src/theme/components/_nav.scss b/UI/Web/src/theme/components/_nav.scss index 40e5f72c4..f2e93c814 100644 --- a/UI/Web/src/theme/components/_nav.scss +++ b/UI/Web/src/theme/components/_nav.scss @@ -3,6 +3,7 @@ &:hover, &:focus { color: var(--nav-link-hover-text-color); + text-decoration: none; } &.active { @@ -21,6 +22,7 @@ .nav-link { color: var(--nav-link-text-color); + position: relative; &.active, &:focus { color: var(--nav-tab-active-text-color); @@ -29,6 +31,11 @@ border-left-color: var(--nav-tab-border-left); border-bottom-color: var(--nav-tab-border-bottom); border-right-color: var(--nav-tab-border-right); + transform: scaleY(1); + } + + &.active::before { + transform: scaleY(1); } &:hover { @@ -36,9 +43,26 @@ background-color: var(--nav-tab-hover-bg-color); border-top-color: var(--nav-tab-hover-border-top); border-left-color: var(--nav-tab-hover-border-left); - border-bottom-color: var(--nav-tab-border-hover-bottom); - border-right-color: var(--nav-tab-border-hover-right); - border-color: var(--nav-tab-border-hover-color); + border-bottom-color: var(--nav-tab-hover-border-bottom); + border-right-color: var(--nav-tab-hover-border-right); + } + + &.active:hover { + background-color: var(--nav-tab-active-hover-bg-color); + } + + &::before { + content: ""; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 100%; + transform: scaleY(0); + transform-origin: bottom center; + background: var(--nav-tab-active-hover-bg-color); + z-index: -1; + transition: transform 0.2s; } } diff --git a/UI/Web/src/theme/components/_radios.scss b/UI/Web/src/theme/components/_radios.scss index 70ce5681a..f47e353b7 100644 --- a/UI/Web/src/theme/components/_radios.scss +++ b/UI/Web/src/theme/components/_radios.scss @@ -4,4 +4,8 @@ input[type='radio'] { &:hover { accent-color: var(--radio-hover-accent-color); } + + &:focus { + box-shadow: 0 0 0 0.25rem var(--radio-focus-boxshadow-color); + } } diff --git a/UI/Web/src/theme/components/_selects.scss b/UI/Web/src/theme/components/_selects.scss index 74ad02e33..3e1693ad2 100644 --- a/UI/Web/src/theme/components/_selects.scss +++ b/UI/Web/src/theme/components/_selects.scss @@ -7,6 +7,7 @@ border-color: var(--input-focused-border-color); background-color: var(--input-bg-color); color: var(--input-text-color); + box-shadow: 0 0 0 0.25rem var(--input-focus-boxshadow-color); } &:read-only { diff --git a/UI/Web/src/theme/themes/dark.scss b/UI/Web/src/theme/themes/dark.scss index 0ac0bb5c5..3576dbe8a 100644 --- a/UI/Web/src/theme/themes/dark.scss +++ b/UI/Web/src/theme/themes/dark.scss @@ -5,16 +5,16 @@ --primary-color-darker-shade: #338A67; --primary-color-darkest-shade: #25624A; --error-color: #BD362F; - --bs-body-bg: #343a40; + --bs-body-bg: #343a40; --body-text-color: #efefef; --btn-icon-filter: invert(1) grayscale(100%) brightness(200%); - + /* Navbar */ --navbar-bg-color: black; --navbar-text-color: white; --navbar-fa-icon-color: white; --navbar-btn-hover-outline-color: rgba(255, 255, 255, 1); - + /* Inputs */ --input-bg-color: #343a40; --input-bg-readonly-color: #434648; @@ -22,78 +22,81 @@ --input-text-color: #fff; --input-placeholder-color: #aeaeae; --input-border-color: #ccc; - + --input-focus-boxshadow-color: rgb(255 255 255 / 50%); + /* Buttons */ + --btn-focus-boxshadow-color: rgb(255 255 255 / 50%); --btn-primary-text-color: white; - --btn-primary-bg-color: var(--primary-color-darker-shade); - --btn-primary-border-color: var(--primary-color-darker-shade); + --btn-primary-bg-color: var(--primary-color); + --btn-primary-border-color: var(--primary-color); --btn-primary-hover-text-color: white; - --btn-primary-hover-bg-color: var(--primary-color-darkest-shade); - --btn-primary-hover-border-color: var(--primary-color-darkest-shade); + --btn-primary-hover-bg-color: var(--primary-color-darker-shade); + --btn-primary-hover-border-color: var(--primary-color-darker-shade); --btn-alt-bg-color: #424c72; --btn-alt-border-color: #444f75; --btn-alt-hover-bg-color: #3b4466; --btn-alt-focus-bg-color: #343c59; - --btn-alt-focus-boxshadow-color: rgb(68 79 117 / 50%); + --btn-alt-focus-boxshadow-color: rgb(255 255 255 / 50%); --btn-fa-icon-color: white; --btn-disabled-bg-color: #343a40; --btn-disabled-text-color: white; --btn-disabled-border-color: #6c757d; - + /* Nav (Tabs) */ --nav-tab-border-color: rgba(44, 118, 88, 0.7); --nav-tab-text-color: var(--body-text-color); - --nav-tab-bg-color: var(--bs-body-bg); - --nav-tab-hover-border-color: var(--primary-color-dark-shade); + --nav-tab-bg-color: var(--primary-color); + --nav-tab-hover-border-color: var(--primary-color); --nav-tab-active-text-color: white; --nav-tab-border-hover-color: transparent; --nav-tab-hover-text-color: var(--body-text-color); - --nav-tab-hover-bg-color: var(--primary-color-dark-shade); + --nav-tab-hover-bg-color: transparent; --nav-tab-border-top: rgba(44, 118, 88, 0.7); --nav-tab-border-left: rgba(44, 118, 88, 0.7); - --nav-tab-border-bottom: var(--bs-body-bg); + --nav-tab-border-bottom: rgba(44, 118, 88, 0.7); --nav-tab-border-right: rgba(44, 118, 88, 0.7); - --nav-tab-border-hover-top: var(--primary-color-dark-shade); - --nav-tab-border-hover-left: var(--primary-color-dark-shade); - --nav-tab-border-hover-bottom: rgba(44, 118, 88, 0.7); - --nav-tab-border-hover-right: var(--primary-color-dark-shade); - - --nav-link-bg-color: var(--primary-color-dark-shade); + --nav-tab-hover-border-top: rgba(44, 118, 88, 0.7); + --nav-tab-hover-border-left: rgba(44, 118, 88, 0.7); + --nav-tab-hover-border-bottom: var(--bs-body-bg); + --nav-tab-hover-border-right: rgba(44, 118, 88, 0.7); + --nav-tab-active-hover-bg-color: var(--primary-color); + --nav-link-bg-color: var(--primary-color); --nav-link-active-text-color: white; --nav-link-text-color: white; - - /* Header */ + /* Header */ --nav-header-text-color: white; --nav-header-bg-color: rgb(22, 27, 34); - + /* Toasts */ --toast-success-bg-color: rgba(59, 158, 118, 0.9); --toast-error-bg-color: #BD362F; --toast-info-bg-color: #2F96B4; --toast-warning-bg-color: #F89406; - + /* Checkboxes */ --checkbox-checked-bg-color: var(--primary-color); --checkbox-border-color: var(--input-focused-border-color); --checkbox-focus-border-color: var(--primary-color); - + --checkbox-focus-boxshadow-color: rgb(255 255 255 / 50%); + /* Tag Badge */ --tagbadge-border-color: rgba(239, 239, 239, 0.125); --tagbadge-text-color: var(--body-text-color); --tagbadge-bg-color: var(--nav-tab-hover-bg-color); - + /* List items */ --list-group-item-text-color: var(--body-text-color); /*rgba(74, 198, 148, 0.9)*/ --list-group-item-bg-color: #343a40; --list-group-item-border-color: rgba(239, 239, 239, 0.125); --list-group-hover-text-color: white; --list-group-hover-bg-color: var(--accordion-body-bg-color); - + --list-group-active-border-color: none; + /* Popover */ --popover-body-bg-color: var(--navbar-bg-color); --popover-body-text-color: var(--navbar-text-color); - + /* Pagination */ --pagination-active-link-border-color: var(--primary-color); --pagination-active-link-bg-color: var(--primary-color); @@ -102,14 +105,14 @@ --pagination-link-text-color: var(--primary-color); --pagination-link-bg-color: rgba(1, 4, 9, 0.5); --pagination-focus-border-color: var(--primary-color); - + /* Dropdown */ --dropdown-item-hover-text-color: white; - --dropdown-item-hover-bg-color: var(--primary-color-dark-shade); + --dropdown-item-hover-bg-color: var(--primary-color); --dropdown-item-text-color: var(--navbar-text-color); --dropdown-item-bg-color: var(--navbar-bg-color); --dropdown-overlay-color: rgba(0,0,0,0.5); - + /* Accordion */ --accordion-header-text-color: rgba(74, 198, 148, 0.9); --accordion-header-bg-color: rgba(52, 60, 70, 0.5); /* This is a good accent color */ @@ -118,16 +121,18 @@ --accordion-body-text-color: var(--body-text-color); --accordion-header-collapsed-text-color: rgba(74, 198, 148, 0.9); --accordion-header-collapsed-bg-color: rgba(22,27,34,0.5); - + --accordion-button-focus-border-color: unset; + --accordion-button-focus-box-shadow: unset; + /* Breadcrumb */ --breadcrumb-bg-color: #292d32; --breadcrumb-item-text-color: var(--body-text-color); - + /* Rating star */ --ratingstar-color: white; --ratingstar-star-empty: #b0c4de; --ratingstar-star-filled: var(--primary-color); - + /* Global */ --hr-color: rgba(239, 239, 239, 0.125); --accent-bg-color: rgba(1, 4, 9, 0.5); @@ -139,17 +144,18 @@ --grid-breakpoints-xl: $grid-breakpoint-xl; --body-font-family: "EBGaramond", "Helvetica Neue", sans-serif; --brand-font-family: "Spartan", sans-serif; - + /* Card */ --card-bg-color: rgba(22,27,34,0.5); --card-text-color: var(--body-text-color); --card-border-color: rgba(239, 239, 239, 0.125); --card-progress-bar-color: var(--primary-color); + --card-overlay-bg-color: rgba(0, 0, 0, 0); --card-overlay-hover-bg-color: rgba(0, 0, 0, 0.2); - + /* Slider */ --slider-text-color: white; - + /* Manga Reader */ --manga-reader-overlay-filter: blur(10px); --manga-reader-overlay-bg-color: rgba(0,0,0,0.5); @@ -157,10 +163,11 @@ --manga-reader-bg-color: black; --manga-reader-next-highlight-bg-color: rgba(65, 225, 100, 0.5); --manga-reader-prev-highlight-bg-color: rgba(65, 105, 225, 0.5); - + /* Radios */ --radio-accent-color: var(--primary-color); - --radio-hover-accent-color: var(--primary-color-dark-shade); + --radio-hover-accent-color: var(--primary-color); + --radio-focus-boxshadow-color: rgb(255 255 255 / 50%); /* Carousel */ --carousel-header-text-color: var(--body-text-color); diff --git a/UI/Web/src/theme/themes/eink.scss b/UI/Web/src/theme/themes/e-ink.scss similarity index 88% rename from UI/Web/src/theme/themes/eink.scss rename to UI/Web/src/theme/themes/e-ink.scss index 63ab2ddf7..63ee946a1 100644 --- a/UI/Web/src/theme/themes/eink.scss +++ b/UI/Web/src/theme/themes/e-ink.scss @@ -1,4 +1,4 @@ -:root .bg-eink { +:root .bg-e-ink { --color-scheme: light; --primary-color: black; --primary-color-dark-shade: #3B9E76; @@ -22,12 +22,22 @@ --input-border-color: #ccc; /* Buttons */ - --btn-primary-text-color: white; + --btn-primary-text-color: black; + --btn-primary-bg-color: white; + --btn-primary-border-color: black; + --btn-primary-hover-text-color: white; + --btn-primary-hover-bg-color: black; + --btn-primary-hover-border-color: black; --btn-alt-bg-color: #424c72; --btn-alt-border-color: #444f75; --btn-alt-hover-bg-color: #3b4466; --btn-alt-focus-bg-color: #343c59; --btn-alt-focus-boxshadow-color: rgb(68 79 117 / 50%); + --btn-fa-icon-color: black; + --btn-disabled-bg-color: #020202; + --btn-disabled-text-color: white; + --btn-disabled-border-color: #6c757d; + /* Nav */ --nav-link-active-text-color: white; @@ -87,6 +97,7 @@ --list-group-hover-text-color: black; --list-group-hover-bg-color: #eaeaea; --list-group-item-border-color: rgba(239, 239, 239, 0.125); + --list-group-active-border-color: none; /* Dropdown */ --dropdown-item-hover-text-color: white; diff --git a/UI/Web/src/theme/themes/light.scss b/UI/Web/src/theme/themes/light.scss index 3177a57f9..51c089828 100644 --- a/UI/Web/src/theme/themes/light.scss +++ b/UI/Web/src/theme/themes/light.scss @@ -22,7 +22,7 @@ --input-border-color: #ccc; /* Buttons */ - --btn-primary-text-color: white; + --btn-primary-text-color: black; --btn-alt-bg-color: #424c72; --btn-alt-border-color: #444f75; --btn-alt-hover-bg-color: #3b4466; @@ -41,7 +41,7 @@ --nav-tab-border-hover-color: transparent; /* Checkboxes */ - --checkbox-checked-bg-color: var(--primary-color); + --checkbox-checked-bg-color: black; --checkbox-bg-color: white; --checkbox-border-color: var(--primary-color); --checkbox-focus-border-color: var(--input-border-color); @@ -70,6 +70,7 @@ --grid-breakpoints-xl: $grid-breakpoint-xl; --body-font-family: "EBGaramond", "Helvetica Neue", sans-serif; --brand-font-family: "Spartan", sans-serif; + --text-muted-color: #aaa; /* Breadcrumb */ --breadcrumb-bg-color: #eaeaea; @@ -79,6 +80,7 @@ --card-text-color: #000; --card-border-color: #ccc; --card-progress-bar-color: var(--primary-color); + --card-overlay-bg-color: rgba(0, 0, 0, 0); --card-overlay-hover-bg-color: rgba(0, 0, 0, 0.2); /* List items */ @@ -87,6 +89,7 @@ --list-group-hover-text-color: inherit; --list-group-hover-bg-color: #eaeaea; --list-group-item-border-color: rgba(239, 239, 239, 0.125); + --list-group-active-border-color: none; /* Dropdown */ --dropdown-item-hover-text-color: white; diff --git a/UI/Web/src/theme/utilities/_global.scss b/UI/Web/src/theme/utilities/_global.scss index f26908e05..2b377acc3 100644 --- a/UI/Web/src/theme/utilities/_global.scss +++ b/UI/Web/src/theme/utilities/_global.scss @@ -11,5 +11,5 @@ hr { } .text-muted { - color: #d7d7d7 !important; + color: var(--text-muted-color) !important; }