Side Nav UX Changes (#3345)

Co-authored-by: Christopher <39032787+MrRobotjs@users.noreply.github.com>
Co-authored-by: Robbie Davis <robbie@therobbiedavis.com>
This commit is contained in:
Joe Milazzo 2024-11-07 17:21:14 -06:00 committed by GitHub
parent aa939edf6d
commit 3a0c796c08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
45 changed files with 1193 additions and 664 deletions

View File

@ -211,6 +211,7 @@ public class MangaParsingTests
[InlineData("หนึ่งความคิด นิจนิรันดร์ เล่ม 2", "หนึ่งความคิด นิจนิรันดร์")] [InlineData("หนึ่งความคิด นิจนิรันดร์ เล่ม 2", "หนึ่งความคิด นิจนิรันดร์")]
[InlineData("不安の種\uff0b - 01", "不安の種\uff0b")] [InlineData("不安の種\uff0b - 01", "不安の種\uff0b")]
[InlineData("Giant Ojou-sama - Ch. 33.5 - Volume 04 Bonus Chapter", "Giant Ojou-sama")] [InlineData("Giant Ojou-sama - Ch. 33.5 - Volume 04 Bonus Chapter", "Giant Ojou-sama")]
[InlineData("[218565]-(C92) [BRIO (Puyocha)] Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE", "")]
public void ParseSeriesTest(string filename, string expected) public void ParseSeriesTest(string filename, string expected)
{ {
Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename, LibraryType.Manga)); Assert.Equal(expected, API.Services.Tasks.Scanner.Parser.Parser.ParseSeries(filename, LibraryType.Manga));

View File

@ -130,6 +130,25 @@ public class ScannerServiceTests : AbstractDbTest
Assert.NotNull(postLib.Series.First().Volumes.FirstOrDefault(v => v.Chapters.FirstOrDefault(c => c.IsSpecial) != null)); Assert.NotNull(postLib.Series.First().Volumes.FirstOrDefault(v => v.Chapters.FirstOrDefault(c => c.IsSpecial) != null));
} }
[Fact]
public async Task ScanLibrary_SeriesWithUnbalancedParenthesis()
{
const string testcase = "Scan Library Parses as ( - Manga.json";
var library = await GenerateScannerData(testcase);
var scanner = CreateServices();
await scanner.ScanLibrary(library.Id);
var postLib = await _unitOfWork.LibraryRepository.GetLibraryForIdAsync(library.Id, LibraryIncludes.Series);
Assert.NotNull(postLib);
Assert.Single(postLib.Series);
var series = postLib.Series.First();
Assert.Equal("Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE", series.Name);
}
/// <summary> /// <summary>
/// This is testing that if the first file is named A and has a localized name of B if all other files are named B, it should still group and name the series A /// This is testing that if the first file is named A and has a localized name of B if all other files are named B, it should still group and name the series A
/// </summary> /// </summary>

View File

@ -0,0 +1,4 @@
[
"[218565]-(C92) [BRIO (Puyocha)] Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE/[218565]-(C92) [BRIO (Puyocha)] Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE.zip",
"[218565]-(C92) [BRIO (Puyocha)] Mika-nee no Tanryoku Shidou - Mika s Guide to Self-Confidence (THE IDOLM@STE/[218565]-(C92) [BRIO (Puyocha)] Something Else (THE IDOLM@STE.zip"
]

View File

@ -612,6 +612,7 @@ public class LibraryController : BaseApiController
library.AllowScrobbling = false; library.AllowScrobbling = false;
} }
_unitOfWork.LibraryRepository.Update(library); _unitOfWork.LibraryRepository.Update(library);
} }

View File

@ -946,9 +946,7 @@ public class OpdsController : BaseApiController
var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId);
var libraryType = await _unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId); var libraryType = await _unitOfWork.LibraryRepository.GetLibraryTypeAsync(series.LibraryId);
var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId, VolumeIncludes.Chapters); var volume = await _unitOfWork.VolumeRepository.GetVolumeAsync(volumeId, VolumeIncludes.Chapters);
// var chapters =
// (await _unitOfWork.ChapterRepository.GetChaptersAsync(volumeId))
// .OrderBy(x => x.MinNumber, _chapterSortComparerDefaultLast);
var feed = CreateFeed(series.Name + " - Volume " + volume!.Name + $" - {_seriesService.FormatChapterName(userId, libraryType)}s ", var feed = CreateFeed(series.Name + " - Volume " + volume!.Name + $" - {_seriesService.FormatChapterName(userId, libraryType)}s ",
$"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey, prefix); $"{apiKey}/series/{seriesId}/volume/{volumeId}", apiKey, prefix);
SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-{_seriesService.FormatChapterName(userId, libraryType)}s"); SetFeedId(feed, $"series-{series.Id}-volume-{volume.Id}-{_seriesService.FormatChapterName(userId, libraryType)}s");
@ -1094,15 +1092,6 @@ public class OpdsController : BaseApiController
}; };
} }
private static FeedAuthor CreateAuthor(PersonDto person)
{
return new FeedAuthor()
{
Name = person.Name,
Uri = "http://opds-spec.org/author/" + person.Id
};
}
private static FeedEntry CreateSeries(SearchResultDto searchResultDto, string apiKey, string prefix, string baseUrl) private static FeedEntry CreateSeries(SearchResultDto searchResultDto, string apiKey, string prefix, string baseUrl)
{ {
return new FeedEntry() return new FeedEntry()
@ -1122,6 +1111,15 @@ public class OpdsController : BaseApiController
}; };
} }
private static FeedAuthor CreateAuthor(PersonDto person)
{
return new FeedAuthor()
{
Name = person.Name,
Uri = "http://opds-spec.org/author/" + person.Id
};
}
private static FeedEntry CreateChapter(string apiKey, string title, string? summary, int chapterId, int volumeId, int seriesId, string prefix, string baseUrl) private static FeedEntry CreateChapter(string apiKey, string title, string? summary, int chapterId, int volumeId, int seriesId, string prefix, string baseUrl)
{ {
return new FeedEntry() return new FeedEntry()

View File

@ -0,0 +1,48 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using API.Entities;
using API.Entities.Enums;
using Kavita.Common.EnvironmentInfo;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace API.Data.ManualMigrations;
/// <summary>
/// When I removed Scrobble support for Book libraries, I forgot to turn the setting off for said libraries.
/// </summary>
public static class ManualMigrateUnscrobbleBookLibraries
{
public static async Task Migrate(DataContext context, ILogger<Program> logger)
{
if (await context.ManualMigrationHistory.AnyAsync(m => m.Name == "ManualMigrateUnscrobbleBookLibraries"))
{
return;
}
logger.LogCritical("Running ManualMigrateUnscrobbleBookLibraries migration - Please be patient, this may take some time. This is not an error");
var libs = await context.Library.Where(l => l.Type == LibraryType.Book).ToListAsync();
foreach (var lib in libs)
{
lib.AllowScrobbling = false;
context.Entry(lib).State = EntityState.Modified;
}
if (context.ChangeTracker.HasChanges())
{
await context.SaveChangesAsync();
}
await context.ManualMigrationHistory.AddAsync(new ManualMigrationHistory()
{
Name = "ManualMigrateUnscrobbleBookLibraries",
ProductVersion = BuildInfo.Version.ToString(),
RanAt = DateTime.UtcNow
});
await context.SaveChangesAsync();
logger.LogCritical("Running ManualMigrateUnscrobbleBookLibraries migration - Completed. This is not an error");
}
}

View File

@ -20,8 +20,26 @@ public class LibraryBuilder : IEntityBuilder<Library>
Series = new List<Series>(), Series = new List<Series>(),
Folders = new List<FolderPath>(), Folders = new List<FolderPath>(),
AppUsers = new List<AppUser>(), AppUsers = new List<AppUser>(),
AllowScrobbling = type is LibraryType.LightNovel or LibraryType.Manga AllowScrobbling = type is LibraryType.LightNovel or LibraryType.Manga,
LibraryFileTypes = new List<LibraryFileTypeGroup>()
}; };
_library.LibraryFileTypes.Add(new LibraryFileTypeGroup()
{
FileTypeGroup = FileTypeGroup.Archive
});
_library.LibraryFileTypes.Add(new LibraryFileTypeGroup()
{
FileTypeGroup = FileTypeGroup.Epub
});
_library.LibraryFileTypes.Add(new LibraryFileTypeGroup()
{
FileTypeGroup = FileTypeGroup.Images
});
_library.LibraryFileTypes.Add(new LibraryFileTypeGroup()
{
FileTypeGroup = FileTypeGroup.Pdf
});
} }
public LibraryBuilder(Library library) public LibraryBuilder(Library library)

View File

@ -746,7 +746,6 @@ public class DirectoryService : IDirectoryService
public IList<string> ScanFiles(string folderPath, string fileTypes, GlobMatcher? matcher = null, public IList<string> ScanFiles(string folderPath, string fileTypes, GlobMatcher? matcher = null,
SearchOption searchOption = SearchOption.AllDirectories) SearchOption searchOption = SearchOption.AllDirectories)
{ {
_logger.LogTrace("[ScanFiles] called on {Path}", folderPath);
var files = new List<string>(); var files = new List<string>();
if (!Exists(folderPath)) return files; if (!Exists(folderPath)) return files;

View File

@ -126,6 +126,13 @@ public class ParseScannedFiles
IDictionary<string, IList<SeriesModified>> seriesPaths, Library library, bool forceCheck = false) IDictionary<string, IList<SeriesModified>> seriesPaths, Library library, bool forceCheck = false)
{ {
var fileExtensions = string.Join("|", library.LibraryFileTypes.Select(l => l.FileTypeGroup.GetRegex())); var fileExtensions = string.Join("|", library.LibraryFileTypes.Select(l => l.FileTypeGroup.GetRegex()));
// If there are no library file types, skip scanning entirely
if (string.IsNullOrWhiteSpace(fileExtensions))
{
return ArraySegment<ScanResult>.Empty;
}
var matcher = BuildMatcher(library); var matcher = BuildMatcher(library);
var result = new List<ScanResult>(); var result = new List<ScanResult>();
@ -459,7 +466,7 @@ public class ParseScannedFiles
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.FileScanProgressEvent("File Scan Starting", library.Name, ProgressEventType.Started)); MessageFactory.FileScanProgressEvent("File Scan Starting", library.Name, ProgressEventType.Started));
_logger.LogDebug("[ScannerService] Library {LibraryName} Step 1.A: Process {FolderCount} folders", library.Name, folders.Count()); _logger.LogDebug("[ScannerService] Library {LibraryName} Step 1.A: Process {FolderCount} folders", library.Name, folders.Count);
var processedScannedSeries = new ConcurrentBag<ScannedSeriesResult>(); var processedScannedSeries = new ConcurrentBag<ScannedSeriesResult>();
foreach (var folder in folders) foreach (var folder in folders)

View File

@ -29,24 +29,12 @@ public class BasicParser(IDirectoryService directoryService, IDefaultParser imag
Format = Parser.ParseFormat(filePath), Format = Parser.ParseFormat(filePath),
Title = Parser.RemoveExtensionIfSupported(fileName)!, Title = Parser.RemoveExtensionIfSupported(fileName)!,
FullFilePath = Parser.NormalizePath(filePath), FullFilePath = Parser.NormalizePath(filePath),
Series = string.Empty, Series = Parser.ParseSeries(fileName, type),
ComicInfo = comicInfo ComicInfo = comicInfo,
Chapters = Parser.ParseChapter(fileName, type),
Volumes = Parser.ParseVolume(fileName, type),
}; };
// This will be called if the epub is already parsed once then we call and merge the information, if the
if (Parser.IsEpub(filePath))
{
ret.Chapters = Parser.ParseChapter(fileName, type);
ret.Series = Parser.ParseSeries(fileName, type);
ret.Volumes = Parser.ParseVolume(fileName, type);
}
else
{
ret.Chapters = Parser.ParseChapter(fileName, type);
ret.Series = type == LibraryType.Comic ? Parser.ParseComicSeries(fileName) : Parser.ParseSeries(fileName, type);
ret.Volumes = type == LibraryType.Comic ? Parser.ParseComicVolume(fileName) : Parser.ParseVolume(fileName, type);
}
if (ret.Series == string.Empty || Parser.IsImage(filePath)) if (ret.Series == string.Empty || Parser.IsImage(filePath))
{ {
// Try to parse information out of each folder all the way to rootPath // Try to parse information out of each folder all the way to rootPath

View File

@ -271,7 +271,7 @@ public static class Parser
RegexTimeout), RegexTimeout),
//Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans] //Knights of Sidonia c000 (S2 LE BD Omake - BLAME!) [Habanero Scans]
new Regex( new Regex(
@"(?<Series>.*)(\bc\d+\b)", @"(?<Series>.*?)(?<!\()\bc\d+\b",
MatchOptions, RegexTimeout), MatchOptions, RegexTimeout),
//Tonikaku Cawaii [Volume 11], Darling in the FranXX - Volume 01.cbz //Tonikaku Cawaii [Volume 11], Darling in the FranXX - Volume 01.cbz
new Regex( new Regex(

View File

@ -275,6 +275,7 @@ public class Startup
await MigrateLowestSeriesFolderPath2.Migrate(dataContext, unitOfWork, logger); await MigrateLowestSeriesFolderPath2.Migrate(dataContext, unitOfWork, logger);
await ManualMigrateRemovePeople.Migrate(dataContext, logger); await ManualMigrateRemovePeople.Migrate(dataContext, logger);
await MigrateDuplicateDarkTheme.Migrate(dataContext, logger); await MigrateDuplicateDarkTheme.Migrate(dataContext, logger);
await ManualMigrateUnscrobbleBookLibraries.Migrate(dataContext, logger);
// Update the version in the DB after all migrations are run // Update the version in the DB after all migrations are run
var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion); var installVersion = await unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.InstallVersion);

View File

@ -1,4 +1,5 @@
@import '../theme/variables'; @import '../theme/variables';
.content-wrapper { .content-wrapper {
padding: 0 0 0 10px; padding: 0 0 0 10px;
height: calc(var(--vh)* 100 - var(--nav-offset)); height: calc(var(--vh)* 100 - var(--nav-offset));
@ -14,6 +15,7 @@
scrollbar-width: thin; scrollbar-width: thin;
mask-image: linear-gradient(to bottom, transparent, black 0%, black 95%, transparent 100%); mask-image: linear-gradient(to bottom, transparent, black 0%, black 95%, transparent 100%);
-webkit-mask-image: linear-gradient(to bottom, transparent, black 0%, black 95%, transparent 100%); -webkit-mask-image: linear-gradient(to bottom, transparent, black 0%, black 95%, transparent 100%);
//margin-top: 7px;
// For firefox // For firefox
@supports (-moz-appearance:none) { @supports (-moz-appearance:none) {
@ -55,7 +57,7 @@
} }
.companion-bar-content { .companion-bar-content {
margin-left: 190px; margin-left: var(--side-nav-width);
} }
@media (max-width: $grid-breakpoints-lg) { @media (max-width: $grid-breakpoints-lg) {
@ -82,7 +84,6 @@
margin-left: 0; margin-left: 0;
padding-left: 0; padding-left: 0;
width: 100%; width: 100%;
padding: 10px 0 0;
height: calc(var(--vh) * 100 - var(--nav-mobile-offset)); height: calc(var(--vh) * 100 - var(--nav-mobile-offset));
scrollbar-color: rgba(255,255,255,0.3) rgba(0, 0, 0, 0.1); scrollbar-color: rgba(255,255,255,0.3) rgba(0, 0, 0, 0.1);
scrollbar-width: thin; scrollbar-width: thin;

View File

@ -1,8 +1,8 @@
<ng-container *transloco="let t; read: 'bulk-operations'"> <ng-container *transloco="let t; read: 'bulk-operations'">
@if (bulkSelectionService.selections$ | async; as selectionCount) { @if (bulkSelectionService.selections$ | async; as selectionCount) {
@if (selectionCount > 0) { @if (selectionCount > 0) {
<div class="bulk-select-container"> <div class="bulk-select-container" [ngStyle]="{'margin-left': marginLeft + 'px', 'margin-right': marginRight + 'px'}">
<div class="bulk-select mb-3 {{modalMode ? '' : 'fixed-top'}}" [ngStyle]="{'margin-top': topOffset + 'px'}"> <div class="bulk-select">
<div class="d-flex justify-content-around align-items-center"> <div class="d-flex justify-content-around align-items-center">
<span class="highlight"> <span class="highlight">

View File

@ -1,6 +1,7 @@
.bulk-select-container { .bulk-select-container {
position: absolute; z-index: 1;
width: 100%; top: 0;
position: sticky;
.bulk-select { .bulk-select {
background-color: var(--bulk-selection-bg-color); background-color: var(--bulk-selection-bg-color);

View File

@ -37,7 +37,14 @@ export class BulkOperationsComponent implements OnInit {
* Modal mode means don't fix to the top * Modal mode means don't fix to the top
*/ */
@Input() modalMode = false; @Input() modalMode = false;
@Input() topOffset: number = 75; /**
* On Series Detail this should be 12
*/
@Input() marginLeft: number = 0;
/**
* On Series Detail this should be 12
*/
@Input() marginRight: number = 8;
hasMarkAsRead: boolean = false; hasMarkAsRead: boolean = false;
hasMarkAsUnread: boolean = false; hasMarkAsUnread: boolean = false;
actions: Array<ActionItem<any>> = []; actions: Array<ActionItem<any>> = [];

View File

@ -65,7 +65,7 @@
@if (accountService.isAdmin$ | async) { @if (accountService.isAdmin$ | async) {
<div class="col-auto ms-2"> <div class="col-auto ms-2">
<button class="btn btn-secondary-outline" id="edit-btn--komf" (click)="openEditModal()" [ngbTooltip]="t('edit-series-alt')"> <button class="btn btn-actions" id="edit-btn--komf" (click)="openEditModal()" [ngbTooltip]="t('edit-series-alt')">
<span><i class="fa fa-pen" aria-hidden="true"></i></span> <span><i class="fa fa-pen" aria-hidden="true"></i></span>
</button> </button>
</div> </div>
@ -73,7 +73,7 @@
<div class="col-auto ms-2 d-none d-md-block"> <div class="col-auto ms-2 d-none d-md-block">
<div class="card-actions" [ngbTooltip]="t('more-alt')"> <div class="card-actions" [ngbTooltip]="t('more-alt')">
<app-card-actionables (actionHandler)="performAction($event)" [actions]="chapterActions" [labelBy]="series.name + ' ' + chapter.minNumber" iconClass="fa-ellipsis-h" btnClass="btn-secondary-outline btn"></app-card-actionables> <app-card-actionables (actionHandler)="performAction($event)" [actions]="chapterActions" [labelBy]="series.name + ' ' + chapter.minNumber" iconClass="fa-ellipsis-h" btnClass="btn-actions btn"></app-card-actionables>
</div> </div>
</div> </div>

View File

@ -1 +1,5 @@
@use '../../series-detail-common'; @use '../../series-detail-common';
:host ::ng-deep .card-actions .btn.btn-actions {
padding: 0.375rem 0.75rem;
}

View File

@ -265,6 +265,14 @@ export class LibraryDetailComponent implements OnInit {
case(Action.GenerateColorScape): case(Action.GenerateColorScape):
await this.actionService.refreshLibraryMetadata(library, undefined, false); await this.actionService.refreshLibraryMetadata(library, undefined, false);
break; break;
case (Action.Delete):
await this.actionService.deleteLibrary(library, () => {
this.loadPageSource.next(true);
});
break;
case (Action.AnalyzeFiles):
await this.actionService.analyzeFiles(library);
break;
case(Action.Edit): case(Action.Edit):
this.actionService.editLibrary(library); this.actionService.editLibrary(library);
break; break;

View File

@ -20,7 +20,7 @@
.widget-button--indicator { .widget-button--indicator {
position: absolute; position: absolute;
top: 30px; top: 24px;
color: var(--event-widget-activity-bg-color); color: var(--event-widget-activity-bg-color);
&.error { &.error {
@ -79,6 +79,7 @@
.dark-menu-item { .dark-menu-item {
&.update-available { &.update-available {
cursor: pointer; cursor: pointer;
opacity: 1;
i.fa { i.fa {
color: var(--primary-color) !important; color: var(--primary-color) !important;

View File

@ -72,8 +72,6 @@ export class EventsWidgetComponent implements OnInit, OnDestroy {
*/ */
updateAvailable: boolean = false; updateAvailable: boolean = false;
debugMode: boolean = false;
protected readonly EVENTS = EVENTS; protected readonly EVENTS = EVENTS;

View File

@ -1,8 +1,3 @@
form {
max-height: 38px;
}
.search-result img { .search-result img {
width: 100% !important; width: 100% !important;
} }
@ -18,38 +13,43 @@ form {
.typeahead-input { .typeahead-input {
border: 1px solid transparent; border: 1px solid transparent;
border-radius: 4px; border-radius: 4px;
padding: 0px 6px;
display: inline-block;
overflow: hidden; overflow: hidden;
position: relative; position: relative;
z-index: 1; z-index: 1;
box-sizing: border-box; box-sizing: border-box;
box-shadow: none; box-shadow: none;
cursor: text; cursor: text;
background-color: var(--input-bg-color); background-color: var(--searchbar-bg-color);
color: var(--body-text-color); color: var(--body-text-color);
min-height: 38px; min-height: 32px;
transition-property: all; transition-property: all;
transition-duration: 0.3s; transition-duration: 0.3s;
display: block; display: block;
width: 50%;
.search { .search {
display: flex; display: flex;
position: relative; position: relative;
min-height: 32px;
.btn-close {
position: unset;
margin-top: unset;
align-self: center;
margin: 0 8px;
}
} }
input { input {
width: 100%;
padding: 0px 6px;
outline: 0 !important; outline: 0 !important;
border-radius: .28571429rem; border-radius: .28571429rem;
padding: 0px !important;
min-height: 0px !important;
max-width: 100% !important;
margin: 0px !important; margin: 0px !important;
text-indent: 0 !important; text-indent: 0 !important;
line-height: inherit !important; line-height: inherit !important;
box-shadow: none !important; box-shadow: none !important;
width: 300px;
transition-property: all; transition-property: all;
transition-duration: 0.3s; transition-duration: 0.3s;
display: block; display: block;
@ -57,33 +57,42 @@ form {
position: relative; position: relative;
left: 4px; left: 4px;
border: none; border: none;
background-color: transparent;
&:focus-visible { &:focus-visible {
width: calc(100vw - 180px); width: 100%;
}
&:empty {
padding-top: 6px !important;
} }
} }
&.focused { &.focused {
width: 98.5%; width: 100%;
border-color: var(--input-focused-border-color); border-color: var(--primary-color);
}
input {
color: #fff;
}
}
} }
@media only screen and (max-width: 980px) {
.typeahead-input {
width: 65%;
}
}
/* small devices (phones, 650px and down) */ /* small devices (phones, 650px and down) */
@media only screen and (max-width:650px) { @media only screen and (max-width:650px) {
input { .typeahead-input {
width: 100% width: 75%;
margin: 0 auto;
} }
}
input:focus-visible { @media only screen and (max-width: 500px) {
width: 100% !important; .typeahead-input {
width: 100%;
} }
} }
@ -160,10 +169,10 @@ ul ul {
} }
.overlay { .overlay {
position: absolute; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
background: rgba(0,0,0,0.4); background: rgba(0,0,0,0.4);
width: 100%; width: 100vw;
height: 100dvh; height: 100vh;
} }

View File

@ -9,12 +9,14 @@
} }
<a class="navbar-brand dark-exempt" routerLink="/home" routerLinkActive="active"> <a class="navbar-brand dark-exempt" routerLink="/home" routerLinkActive="active">
<app-image width="28px" height="28px" imageUrl="assets/images/logo-32.png" classes="logo" /> <app-image width="24px" height="24px" imageUrl="assets/images/logo-32.png" classes="logo-icon" />
<span class="d-none d-md-inline logo"> Kavita</span> <div class="d-none d-md-inline logo">
<span>Kavita</span>
</div>
</a> </a>
<ul class="navbar-nav col me-auto"> <ul class="navbar-nav col me-auto">
@if (accountService.currentUser$ | async; as user) { @if (accountService.currentUser$ | async; as user) {
<div class="nav-item"> <div class="nav-item search">
<label for="nav-search" class="form-label visually-hidden">{{t('search-series-alt')}}</label> <label for="nav-search" class="form-label visually-hidden">{{t('search-series-alt')}}</label>
<div class="ng-autocomplete"> <div class="ng-autocomplete">
<app-grouped-typeahead <app-grouped-typeahead
@ -161,8 +163,6 @@
} }
</ul> </ul>
@if (!searchFocused) {
@if((breakpoint$ | async)! > Breakpoint.Tablet) { @if((breakpoint$ | async)! > Breakpoint.Tablet) {
@if (backToTopNeeded) { @if (backToTopNeeded) {
<div class="back-to-top"> <div class="back-to-top">
@ -206,7 +206,7 @@
</div> </div>
} }
} }
}
</div> </div>
</nav> </nav>

View File

@ -1,61 +1,95 @@
.btn:focus, .btn:hover { .btn:focus {
box-shadow: 0 0 0 0.1rem var(--navbar-btn-hover-outline-color); box-shadow: 0 0 0 0.1rem var(--navbar-btn-hover-outline-color);
} }
.navbar { .navbar {
background-color: var(--navbar-bg-color); background-color: var(--navbar-bg-color);
.navbar-nav {
.nav-item {
&.search {
width: 100%;
}
}
}
.side-nav-toggle { .side-nav-toggle {
cursor: pointer; cursor: pointer;
margin-left: 13px; margin-left: 0.8125rem;
font-size: 1.2rem; font-size: 1.2rem;
i { i {
color: var(--navbar-fa-icon-color); color: var(--navbar-fa-icon-color);
opacity: 0.8;
}
&:hover {
i {
opacity: 1;
}
}
}
.nav-item:not(.search) {
display: unset;
opacity: 0.8;
&:hover {
opacity: 1;
} }
} }
} }
/* small devices (phones, 650px and down) */ // On Really small screens, hide the server settings wheel and show it in nav
@media only screen and (max-width:650px) { // TODO: Look into doing this with bootstrap 5 (and moving to _utilities.scss)
.navbar-nav { .xs-only {
width: 0;
}
}
// On Really small screens, hide the server settings wheel and show it in nav
// TODO: Look into doing this with bootstrap 5 (and moving to _utilities.scss)
.xs-only {
display: none; display: none;
} }
.not-xs-only {
.not-xs-only {
display: inherit; display: inherit;
} }
@media only screen and (max-width:300px) {
@media only screen and (max-width:300px) {
.xs-only { .xs-only {
display: inherit; display: inherit;
} }
.not-xs-only { .not-xs-only {
display: none; display: none;
} }
} }
.nav-item.dropdown { .nav-item.dropdown {
position: unset; position: unset;
} }
.navbar-brand { .navbar-brand {
font-family: var(--brand-font-family); font-family: var(--brand-font-family);
font-weight: bold; font-weight: bold;
margin: 0 1rem; margin: 0 2rem;
display: flex;
align-items: center;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
} }
.logo-icon {
align-items: center;
align-self: center;
display: flex;
flex-direction: column;
height: 1.5rem;
width: 1.5rem;
margin-right: 0.5rem;
}
.logo { .logo {
max-height: 28px;
vertical-align: text-top; vertical-align: text-top;
max-height: 1.75rem;
line-height: 2.0625rem;
margin-left: 0.3125rem;
} }
.phone-hidden { .phone-hidden {
@ -63,29 +97,44 @@
} }
} }
.focus-visible:focus { .focus-visible:focus {
visibility: visible; visibility: visible;
color: var(--nav-header-text-color); color: var(--nav-header-text-color);
} }
.ng-autocomplete { .ng-autocomplete {
margin-bottom: 0px; margin-bottom: 0px;
} }
.primary-text { .primary-text {
color: var(--nav-header-text-color); color: var(--nav-header-text-color);
border: none; border: none;
} }
.search-result { .search-result {
width: 24px; width: 1.5rem;
margin-top: 5px; margin-top: 0.3125rem;
} }
.scroll-to-top:hover { .scroll-to-top:hover {
animation: MoveUpDown 1s linear infinite; animation: MoveUpDown 1s linear infinite;
} }
.text-light { .text-light {
color: var(--search-result-text-lite-color) !important; color: var(--search-result-text-lite-color) !important;
}
/* small devices (phones, 650px and down) */
@media only screen and (max-width:650px) {
.navbar-nav {
width: 0;
}
.navbar-brand {
margin: 0 1rem 0 1rem;
.logo-icon {
margin: unset;
}
}
} }

View File

@ -1,7 +1,7 @@
<ng-container *transloco="let t; read: 'download-button'"> <ng-container *transloco="let t; read: 'download-button'">
@if (canDownload$ | async) { @if (canDownload$ | async) {
@if (download$ | async; as download) { @if (download$ | async; as download) {
<button class="btn btn-secondary-outline" (click)="downloadClicked()" [ngbTooltip]="t('download-tooltip')" [disabled]="download !== null"> <button class="btn btn-actions" (click)="downloadClicked()" [ngbTooltip]="t('download-tooltip')" [disabled]="download !== null">
@if (download) { @if (download) {
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> <span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
<span class="visually-hidden">{{t('downloading-status')}}</span> <span class="visually-hidden">{{t('downloading-status')}}</span>
@ -10,7 +10,7 @@
} }
</button> </button>
} @else { } @else {
<button class="btn btn-secondary-outline" (click)="downloadClicked()" [ngbTooltip]="t('download-tooltip')"> <button class="btn btn-actions" (click)="downloadClicked()" [ngbTooltip]="t('download-tooltip')">
<i class="fa fa-arrow-alt-circle-down" aria-hidden="true"></i> <i class="fa fa-arrow-alt-circle-down" aria-hidden="true"></i>
</button> </button>
} }

View File

@ -1,5 +1,5 @@
<ng-container *transloco="let t; read: 'series-detail'"> <ng-container *transloco="let t; read: 'series-detail'">
<app-bulk-operations [actionCallback]="bulkActionCallback" [topOffset]="56"></app-bulk-operations> <app-bulk-operations [actionCallback]="bulkActionCallback" [marginLeft]="12" [marginRight]="0"></app-bulk-operations>
@if (series && seriesMetadata && libraryType !== null) { @if (series && seriesMetadata && libraryType !== null) {
<div [ngStyle]="{'height': ScrollingBlockHeight}" class="main-container container-fluid" #scrollingBlock> <div [ngStyle]="{'height': ScrollingBlockHeight}" class="main-container container-fluid" #scrollingBlock>
@ -48,7 +48,7 @@
</div> </div>
<div class="mt-3 mb-3"> <div class="mt-3 mb-3">
<div class="row g-0"> <div class="row g-0" style="align-items: center;">
<div class="col-auto"> <div class="col-auto">
<div class="btn-group"> <div class="btn-group">
<button type="button" class="btn btn-primary-outline" (click)="read()"> <button type="button" class="btn btn-primary-outline" (click)="read()">
@ -72,7 +72,7 @@
</div> </div>
<div class="col-auto ms-2"> <div class="col-auto ms-2">
<button class="btn btn-secondary-outline" (click)="toggleWantToRead()" ngbTooltip="{{isWantToRead ? t('remove-from-want-to-read') : t('add-to-want-to-read')}}"> <button class="btn btn-actions" (click)="toggleWantToRead()" ngbTooltip="{{isWantToRead ? t('remove-from-want-to-read') : t('add-to-want-to-read')}}">
<span> <span>
<i class="{{isWantToRead ? 'fa-solid' : 'fa-regular'}} fa-star" aria-hidden="true"></i> <i class="{{isWantToRead ? 'fa-solid' : 'fa-regular'}} fa-star" aria-hidden="true"></i>
</span> </span>
@ -81,7 +81,7 @@
@if (isAdmin) { @if (isAdmin) {
<div class="col-auto ms-2"> <div class="col-auto ms-2">
<button class="btn btn-secondary-outline" id="edit-btn--komf" (click)="openEditSeriesModal()" [ngbTooltip]="t('edit-series-alt')"> <button class="btn btn-actions" id="edit-btn--komf" (click)="openEditSeriesModal()" [ngbTooltip]="t('edit-series-alt')">
<span><i class="fa fa-pen" aria-hidden="true"></i></span> <span><i class="fa fa-pen" aria-hidden="true"></i></span>
</button> </button>
</div> </div>
@ -89,19 +89,19 @@
@if ((accountService.hasValidLicense$ | async) && libraryAllowsScrobbling) { @if ((accountService.hasValidLicense$ | async) && libraryAllowsScrobbling) {
<div class="col-auto ms-2"> <div class="col-auto ms-2">
<button class="btn btn-secondary-outline" (click)="toggleScrobbling($event)" [ngbTooltip]="t('scrobbling-tooltip')"> <button class="btn btn-actions" (click)="toggleScrobbling($event)" [ngbTooltip]="t('scrobbling-tooltip')">
<i class="fa-solid fa-tower-{{(isScrobbling) ? 'broadcast' : 'observation'}}" aria-hidden="true"></i> <i class="fa-solid fa-tower-{{(isScrobbling) ? 'broadcast' : 'observation'}}" aria-hidden="true"></i>
</button> </button>
</div> </div>
} }
<div class="col-auto ms-2 d-none d-md-block"> <div class="col-auto ms-2 d-none d-md-block">
<div class="card-actions mt-2" [ngbTooltip]="t('more-alt')"> <div class="card-actions btn-actions" [ngbTooltip]="t('more-alt')">
<app-card-actionables (actionHandler)="performAction($event)" [actions]="seriesActions" [labelBy]="series.name" iconClass="fa-ellipsis-h" btnClass="btn-secondary-outline btn"></app-card-actionables> <app-card-actionables (actionHandler)="performAction($event)" [actions]="seriesActions" [labelBy]="series.name" iconClass="fa-ellipsis-h" btnClass="btn"></app-card-actionables>
</div> </div>
</div> </div>
<div class="col-auto ms-2 d-none d-md-block"> <div class="col-auto ms-2 d-none d-md-block btn-actions">
<app-download-button [download$]="download$" [entity]="series" entityType="series"></app-download-button> <app-download-button [download$]="download$" [entity]="series" entityType="series"></app-download-button>
</div> </div>

View File

@ -27,4 +27,6 @@
} }
} }
:host ::ng-deep .card-actions.btn-actions .btn {
padding: 0.375rem 0.75rem;
}

View File

@ -1,7 +1,7 @@
<ng-container *transloco="let t;"> <ng-container *transloco="let t;">
<div class="container-fluid"> <div class="container-fluid">
<div class="row g-0"> <div class="settings-row g-0 row">
<div class="col-10"> <div class="col-10 setting-title">
<h6 class="section-title"> <h6 class="section-title">
@if (labelId) { @if (labelId) {
<label class="reset-label" [for]="labelId">{{title}}</label> <label class="reset-label" [for]="labelId">{{title}}</label>
@ -25,7 +25,6 @@
</div> </div>
</div> </div>
@if (isEditMode) { @if (isEditMode) {
<ng-container [ngTemplateOutlet]="valueEditRef"></ng-container> <ng-container [ngTemplateOutlet]="valueEditRef"></ng-container>
} @else { } @else {
@ -34,7 +33,6 @@
</span> </span>
} }
@if (subtitle) { @if (subtitle) {
<div class="text-muted mt-2" [innerHTML]="subtitle | safeHtml"></div> <div class="text-muted mt-2" [innerHTML]="subtitle | safeHtml"></div>
} }

View File

@ -1,21 +1,19 @@
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject} from '@angular/core'; import {ChangeDetectionStrategy, ChangeDetectorRef, Component, DestroyRef, inject} from '@angular/core';
import {CommonModule, NgOptimizedImage} from '@angular/common'; import {NgOptimizedImage} from '@angular/common';
import {FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators} from "@angular/forms"; import {FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators} from "@angular/forms";
import {NgbCollapse, NgbTooltip} from "@ng-bootstrap/ng-bootstrap"; import {NgbCollapse, NgbTooltip} from "@ng-bootstrap/ng-bootstrap";
import {translate, TranslocoDirective} from "@jsverse/transloco"; import {translate, TranslocoDirective} from "@jsverse/transloco";
import {AccountService} from "../../../_services/account.service"; import {AccountService} from "../../../_services/account.service";
import {ToastrService} from "ngx-toastr";
import {EditExternalSourceItemComponent} from "../edit-external-source-item/edit-external-source-item.component"; import {EditExternalSourceItemComponent} from "../edit-external-source-item/edit-external-source-item.component";
import {ExternalSource} from "../../../_models/sidenav/external-source"; import {ExternalSource} from "../../../_models/sidenav/external-source";
import {ExternalSourceService} from "../../../_services/external-source.service"; import {ExternalSourceService} from "../../../_services/external-source.service";
import {FilterPipe} from "../../../_pipes/filter.pipe"; import {FilterPipe} from "../../../_pipes/filter.pipe";
import {SmartFilter} from "../../../_models/metadata/v2/smart-filter";
import {WikiLink} from "../../../_models/wiki"; import {WikiLink} from "../../../_models/wiki";
@Component({ @Component({
selector: 'app-manage-external-sources', selector: 'app-manage-external-sources',
standalone: true, standalone: true,
imports: [CommonModule, FormsModule, NgOptimizedImage, NgbTooltip, ReactiveFormsModule, TranslocoDirective, NgbCollapse, EditExternalSourceItemComponent, FilterPipe], imports: [FormsModule, NgOptimizedImage, NgbTooltip, ReactiveFormsModule, TranslocoDirective, NgbCollapse, EditExternalSourceItemComponent, FilterPipe],
templateUrl: './manage-external-sources.component.html', templateUrl: './manage-external-sources.component.html',
styleUrls: ['./manage-external-sources.component.scss'], styleUrls: ['./manage-external-sources.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush changeDetection: ChangeDetectionStrategy.OnPush

View File

@ -1,5 +1,5 @@
<ng-container *transloco="let t; read: 'side-nav-companion-bar'"> <ng-container *transloco="let t; read: 'side-nav-companion-bar'">
<div class="mt-0 ms-1 d-flex justify-content-between align-items-center"> <div class="mt-0 d-flex justify-content-between align-items-center">
<div> <div>
<ng-content select="[title]"></ng-content> <ng-content select="[title]"></ng-content>
<ng-content select="[subtitle]"></ng-content> <ng-content select="[subtitle]"></ng-content>

View File

@ -1,152 +1,33 @@
@import '../../../../theme/variables'; @import '../../../../theme/variables';
::ng-deep .side-nav.closed { ::ng-deep .side-nav app-side-nav-item:first-child {
.side-nav-item {
.side-nav-text {
opacity: 0 !important;
}
.card-actions {
opacity: 0 !important;
}
&.active {
color: var(--side-nav-item-active-color);
background-color: unset !important;
}
}
}
.side-nav-item {
position: relative;
align-items: center;
display: flex;
justify-content: space-between;
padding: 0 0 0 10px;
width: 100%;
height: auto;
min-height: 40px;
overflow: hidden;
cursor: pointer;
font-size: 0.9rem;
.side-nav-text {
opacity: 1;
min-width: 100px;
word-break: break-all;
-webkit-line-clamp: 1;
text-overflow: ellipsis;
display: -webkit-box !important;
-webkit-box-orient: vertical;
overflow: hidden;
div {
min-width: 102px;
width: 100%
}
}
span {
display:flex;
&:last-child {
flex-grow: 1;
justify-content: end;
}
div {
align-items: center;
height: 100%;
justify-content: inherit;
min-width: 30px;
width: 100%;
padding-left: 5px;
i {
font-size: 18px;
}
}
}
&.closed {
.side-nav-text {
opacity: 0;
}
.card-actions {
opacity: 0;
}
&.active {
color: var(--side-nav-item-active-color);
background-color: unset;
}
i {
color: var(--side-nav-item-closed-color);
}
&:hover {
color: var(--side-nav-hover-text-color);
background-color: var(--side-nav-hover-bg-color);
i {
color: var(--side-nav-item-closed-hover-color);
}
}
}
&:hover {
color: var(--side-nav-hover-text-color);
background-color: var(--side-nav-hover-bg-color);
.card-actions i.fa {
// TODO: The override to white does not work, please fix for light themes
color: var(--side-nav-hover-text-color) !important;
}
}
&.active {
color: var(--side-nav-item-active-color);
background-color: var(--side-nav-active-bg-color);
.active-highlight { .active-highlight {
background-color: var(--side-nav-item-active-color); border-top-left-radius: 3px;
width: 5px;
height: 100%;
position: absolute;
left: 0;
}
.side-nav-text, i {
color: var(--side-nav-item-active-text-color) !important;
}
&:hover {
color: var(--side-nav-hover-text-color);
background-color: var(--side-nav-hover-bg-color);
.card-actions i.fa {
// TODO: The override to white does not work, please fix for light themes
color: var(--side-nav-hover-text-color) !important;
}
}
} }
} }
::ng-deep .side-nav app-side-nav-item:first-child {
.side-nav-item {
border-top-left-radius: 3px;
}
}
a { @media (max-width: $grid-breakpoints-lg) {
text-decoration: none; ::ng-deep .side-nav app-side-nav-item:first-child {
color: var(--side-nav-text-color); .side-nav-item {
border-top-left-radius: 0px;
}
}
::ng-deep .side-nav app-side-nav-item:last-child {
.side-nav-item {
border-bottom-left-radius: 0px;
}
}
} }
@media (max-width: $grid-breakpoints-lg) { @media (max-width: $grid-breakpoints-lg) {
.side-nav-item { .side-nav-item {
align-items: center;
padding: 0 10px;
height: 55px;
font-size: 1rem;
.side-nav-text { .side-nav-text {
width: 100%; width: 100%;
@ -155,12 +36,5 @@ a {
span:last-child { span:last-child {
flex-grow: 0; flex-grow: 0;
} }
&.closed {
.card-actions {
font-size: inherit;
}
}
} }
} }

View File

@ -9,7 +9,7 @@
@for(section of sections; track section.title + section.children.length; let idx = $index;) { @for(section of sections; track section.title + section.children.length; let idx = $index;) {
@if (hasAnyChildren(user, section)) { @if (hasAnyChildren(user, section)) {
<h5 class="side-nav-header mt-3 mb-2 ms-3" [ngClass]="{'mt-4': idx > 0}">{{t(section.title)}}</h5> <h5 class="side-nav-header mb-2 ms-3" [ngClass]="{'mt-4': idx > 0}">{{t(section.title)}}</h5>
@for(item of section.children; track item.fragment) { @for(item of section.children; track item.fragment) {
@if (accountService.hasAnyRole(user, item.roles)) { @if (accountService.hasAnyRole(user, item.roles)) {
<app-side-nav-item [id]="'nav-item-' + item.fragment" [noIcon]="true" link="/settings" [fragment]="item.fragment" [title]="item.fragment | settingFragment" [badgeCount]="item.badgeCount$ | async"></app-side-nav-item> <app-side-nav-item [id]="'nav-item-' + item.fragment" [noIcon]="true" link="/settings" [fragment]="item.fragment" [title]="item.fragment | settingFragment" [badgeCount]="item.badgeCount$ | async"></app-side-nav-item>

View File

@ -1,22 +1,6 @@
@import '../../../theme/variables'; @import '../../../theme/variables';
// TODO: Move this to a common file so it applies both ways // TODO: Move this to a common file so it applies both ways
.side-nav { .side-nav {
padding-bottom: 10px;
width: 190px;
background-color: var(--side-nav-bg-color);
height: calc((var(--vh)*100) - 75px);
position: fixed;
margin: 0;
left: 10px;
top: 73px;
overflow-y: hidden;
overflow-x: hidden;
border-radius: var(--side-nav-border-radius);
transition: width var(--side-nav-openclose-transition), background-color var(--side-nav-bg-color-transition), border-color var(--side-nav-border-transition);
border: var(--side-nav-border);
scrollbar-gutter: stable both-edges;
scrollbar-width: thin;
// For firefox // For firefox
@supports (-moz-appearance:none) { @supports (-moz-appearance:none) {
scrollbar-color: transparent transparent; scrollbar-color: transparent transparent;
@ -38,7 +22,6 @@
&:hover { &:hover {
scrollbar-width: thin; scrollbar-width: thin;
overflow-y: auto; overflow-y: auto;
// For firefox // For firefox
@supports (-moz-appearance:none) { @supports (-moz-appearance:none) {
scrollbar-color: rgba(255,255,255,0.3) rgba(0, 0, 0, 0); scrollbar-color: rgba(255,255,255,0.3) rgba(0, 0, 0, 0);
@ -49,37 +32,6 @@
background-color: rgba(255,255,255,0.3); /*On hover, it will turn grey*/ background-color: rgba(255,255,255,0.3); /*On hover, it will turn grey*/
} }
} }
&.no-donate {
height: calc((var(--vh)*100) - 82px);
}
&.hidden {
display: none;
opacity: 0;
}
&.closed {
width: 50px;
overflow-x: hidden;
overflow-y: auto;
background-color: var(--side-nav-closed-bg-color);
border: var(--side-nav-border-closed);
}
.side-nav-item:first {
border-top-left-radius: var(--side-nav-border-radius);
border-top-right-radius: var(--side-nav-border-radius);
}
}
::ng-deep .side-nav-text {
div {
display: flex;
}
span {
font-size: 0.6rem;
}
} }
@media (max-width: $grid-breakpoints-lg) { @media (max-width: $grid-breakpoints-lg) {
@ -112,21 +64,6 @@
height: calc((var(--vh)*100) - var(--nav-mobile-offset)); height: calc((var(--vh)*100) - var(--nav-mobile-offset));
} }
} }
.side-nav-overlay {
background-color: var(--side-nav-overlay-color);
width: 100vw;
height: calc((var(--vh)*100) - var(--nav-offset));
position: absolute;
left: 0;
z-index: 998;
&.closed {
display: none;
}
}
} }
.side-nav-header { .side-nav-header {
@ -134,12 +71,3 @@
font-weight: bold; font-weight: bold;
margin-left: 5px; margin-left: 5px;
} }
.side-nav-header:first-of-type {
margin-top: 0.5rem !important;
}
// Overrides for this component
::ng-deep .side-nav-item {
padding: 0 0 0 20px !important;
}

View File

@ -1,6 +1,6 @@
<ng-container *transloco="let t; read: 'series-detail'"> <ng-container *transloco="let t; read: 'series-detail'">
<app-bulk-operations [actionCallback]="bulkActionCallback" [topOffset]="55"></app-bulk-operations> <app-bulk-operations [actionCallback]="bulkActionCallback" [marginLeft]="12" [marginRight]="0"></app-bulk-operations>
<div [ngStyle]="{'height': ScrollingBlockHeight}" class="main-container container-fluid" #scrollingBlock> <div [ngStyle]="{'height': ScrollingBlockHeight}" class="main-container container-fluid" #scrollingBlock>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Logo" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
<path d="M274,0l43.83,7.67c90.55,22.21,163.26,94.54,186.1,184.9,3.71,14.68,5.18,29.62,8.07,44.43v39c-3.06,14.43-4.44,29.07-8.07,43.43-22.71,89.84-94.64,161.78-184.5,184.5-14.68,3.71-29.62,5.18-44.43,8.07h-39c-14.43-3.06-29.07-4.44-43.43-8.07-89.84-22.71-161.78-94.64-184.5-184.5-3.63-14.35-5.01-28.99-8.07-43.43v-40c3.06-14.43,4.44-29.08,8.07-43.43C30.79,102.73,102.71,30.79,192.57,8.07L237,0h37ZM112,136c-8.58.97-23.39-4.03-24,8.5l-.04,238.04c.67,7.25,2.27,8.83,9.5,9.5,37.4,3.46,80-2.74,117.95.05,11.79,1.61,14.73,13.06,23.25,18.75,9.94,6.62,24.73,6.63,34.67,0,9.41-6.27,10.67-17.07,24.28-18.72,36.05-4.38,80.22,3.32,116.93-.07,7.23-.67,8.83-2.25,9.5-9.5l-.04-238.04c-.61-12.53-15.42-7.53-24-8.5-.05-10.65.04-21.35,0-32h-123.5c-5.86,0-15.04,6.99-17.7,12.3l-3.29,6.71c-1.06-6.34-6.02-13.34-11.81-16.21-.98-.49-7.7-2.8-8.2-2.8h-123.5c-.04,10.65.05,21.35,0,32Z" style="fill: #4ac594;"/>
<path d="M112,136c.05-10.65-.04-21.35,0-32h123.5c.5,0,7.22,2.31,8.2,2.8,5.78,2.87,10.74,9.87,11.81,16.21l3.29-6.71c2.66-5.3,11.84-12.3,17.7-12.3h123.5c.04,10.65-.05,21.35,0,32,.36,71.95.56,144.06,0,216h-129.5c-5.19.42-9.52,3.46-12.37,7.64-.92,1.35-.83,4.1-1.64,4.37-1.95.66-1.82-3.33-3.03-4.97-2.87-3.9-7.01-6.63-11.96-7.04H112c-.56-71.94-.36-144.05,0-216ZM176,128h-32v56h32v-56ZM195.5,132l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h38c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-38ZM278.5,132l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM195.5,156l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h38c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-38ZM278.5,156l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM195.5,180l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h38c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-38ZM278.5,180l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM142.5,204l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM278.5,204l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM142.5,228l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM278.5,228l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM142.5,252l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.5,0,2.61-2.51,2.55-3.55.53-1.28-1.82-4.45-2.55-4.45h-91ZM278.5,252l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.5,0,2.61-2.51,2.55-3.55.53-1.28-1.82-4.45-2.55-4.45h-91ZM142.5,276l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM278.5,276l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM142.5,300l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM278.5,300l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM142.5,324l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91ZM278.5,324l-2.55,4.45c-.06,1.04,2.05,3.55,2.55,3.55h91c.73,0,3.08-3.17,2.55-4.45.06-1.04-2.05-3.55-2.55-3.55h-91Z" style="fill: #fefefe;"/>
<path d="M112,136c-.36,71.95-.56,144.06,0,216,.04,5.32-.03,10.68,0,16h131.5c.72,0,5.03,2.29,6.01,2.99l6.98,9.02c.32-4.4,7.9-12.01,12.01-12.01h131.5c.03-5.32-.04-10.68,0-16,.56-71.94.36-144.05,0-216,8.58.97,23.39-4.03,24,8.5l.04,238.04c-.67,7.25-2.27,8.83-9.5,9.5-36.7,3.4-80.88-4.3-116.93.07-13.61,1.65-14.87,12.45-24.28,18.72-9.94,6.63-24.73,6.62-34.67,0-8.52-5.68-11.47-17.14-23.25-18.75-37.95-2.79-80.55,3.41-117.95-.05-7.23-.67-8.83-2.25-9.5-9.5l.04-238.04c.61-12.53,15.42-7.53,24-8.5Z" style="fill: #424d72;"/>
<path d="M112,352h129.5c4.94.41,9.09,3.14,11.96,7.04,1.21,1.64,1.08,5.63,3.03,4.97.8-.27.71-3.02,1.64-4.37,2.85-4.18,7.18-7.22,12.37-7.64h129.5c-.04,5.32.03,10.68,0,16h-131.5c-4.11,0-11.69,7.6-12.01,12.01l-6.98-9.02c-.98-.7-5.29-2.99-6.01-2.99H112c-.03-5.32.04-10.68,0-16Z" style="fill: #e2e6ed;"/>
<rect x="144" y="128" width="32" height="56" style="fill: #58d1f6;"/>
<path d="M278.5,132h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e3e6ee;"/>
<path d="M278.5,156h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,180h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M142.5,204h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,204h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M142.5,228h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,228h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M142.5,252h91c.73,0,3.08,3.17,2.55,4.45.06,1.04-2.05,3.55-2.55,3.55h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,252h91c.73,0,3.08,3.17,2.55,4.45.06,1.04-2.05,3.55-2.55,3.55h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M142.5,276h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,276h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M142.5,300h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,300h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M142.5,324h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M278.5,324h91c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-91c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M195.5,132h38c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-38c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e6ee;"/>
<path d="M195.5,156h38c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-38c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
<path d="M195.5,180h38c.5,0,2.61,2.51,2.55,3.55.53,1.28-1.82,4.45-2.55,4.45h-38c-.5,0-2.61-2.51-2.55-3.55l2.55-4.45Z" style="fill: #e4e7ee;"/>
</svg>

After

Width:  |  Height:  |  Size: 6.8 KiB

View File

@ -4,7 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>Kavita</title> <title>Kavita</title>
<base href="/"> <base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon.png"> <link rel="apple-touch-icon" sizes="180x180" href="assets/icons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="assets/icons/favicon-32x32.png"> <link rel="icon" type="image/png" sizes="32x32" href="assets/icons/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="assets/icons/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="assets/icons/favicon-16x16.png">

View File

@ -37,7 +37,20 @@
box-shadow: inset 0px -2px 0px 0px var(--btn-secondary-outline-text-color); box-shadow: inset 0px -2px 0px 0px var(--btn-secondary-outline-text-color);
border-bottom-left-radius: 0; border-bottom-left-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
}
}
.btn-actions {
color: var(--btn-fa-icon-color);
border-radius: var(--btn-actions-border-radius);
&:hover {
background-color: var(--btn-actions-hover-bg);
}
&:active, &:focus {
background-color: rgb(255 255 255 / 28%) !important;
border-color: transparent !important;
} }
} }
@ -45,7 +58,7 @@
filter: var(--btn-icon-filter) !important; filter: var(--btn-icon-filter) !important;
} }
.btn-primary:disabled, .btn-primary.disabled { .btn-primary:disabled, .btn-primary.disabled, .btn-tertiary.disabled {
background-color: var(--btn-disabled-bg-color); background-color: var(--btn-disabled-bg-color);
color: var(--btn-disabled-text-color); color: var(--btn-disabled-text-color);
border-color: var(--btn-disabled-border-color); border-color: var(--btn-disabled-border-color);

View File

@ -7,7 +7,7 @@ input:not([type="range"]), .form-control {
border-color: var(--input-focused-border-color); border-color: var(--input-focused-border-color);
background-color: var(--input-bg-color); background-color: var(--input-bg-color);
color: var(--input-text-color); color: var(--input-text-color);
box-shadow: 0 0 0 0.25rem var(--input-focus-boxshadow-color); box-shadow: 0 0 0 .25rem var(--input-focus-boxshadow-color);
} }
&:read-only { &:read-only {

View File

@ -2,6 +2,11 @@
background-color: var(--navbar-bg-color); background-color: var(--navbar-bg-color);
color: var(--navbar-text-color); color: var(--navbar-text-color);
z-index: 1040; z-index: 1040;
border-radius: 4px;
left: 0px;
margin: var(--navbar-header-margin);
padding: 0;
height: 3rem;
} }
@ -12,3 +17,9 @@ i.fa.nav {
.nav-tabs .nav-link.active::before { .nav-tabs .nav-link.active::before {
transform: scaleY(0); transform: scaleY(0);
} }
@media (max-width: $grid-breakpoints-lg) {
.navbar {
margin: 8px 12px;
}
}

View File

@ -2,6 +2,10 @@
background-color: var(--progress-bg-color); background-color: var(--progress-bg-color);
} }
.progress-bar {
background-color: var(--progress-bar-color);
}
.progress-bar.text-bg-success { .progress-bar.text-bg-success {
background-color: var(--progress-bar-color) !important; background-color: var(--progress-bar-color) !important;
} }

View File

@ -1,54 +1,160 @@
@import "../variables"; @import "../variables";
//START sidebar container
.side-nav-container { .side-nav-container {
padding-bottom: 10px; width: var(--side-nav-width);
width: 190px;
background-color: var(--side-nav-bg-color); background-color: var(--side-nav-bg-color);
height: calc((var(--vh) * 100) - 115px); height: calc((var(--vh) * 100) - 7.375rem);
position: fixed; position: fixed;
margin: 0; margin: 0;
left: 10px; left: 0.625rem;
top: 73px; top: 4rem;
border-radius: var(--side-nav-border-radius); border-radius: var(--side-nav-border-radius);
transition: transition: width var(--side-nav-openclose-transition), background-color var(--side-nav-bg-color-transition), border-color var(--side-nav-border-transition);
width var(--side-nav-openclose-transition),
background-color var(--side-nav-bg-color-transition),
border-color var(--side-nav-border-transition);
border: var(--side-nav-border); border: var(--side-nav-border);
&::-webkit-scrollbar { &::-webkit-scrollbar {
visibility: hidden; visibility: hidden;
} }
&.preference {
height: calc((var(--vh) * 100));
}
&.no-donate { &.no-donate {
height: calc((var(--vh) * 100) - 82px); height: calc((var(--vh) * 100) - 5.125rem);
} }
&.hidden { &.hidden {
display: none; display: none;
opacity: 0; opacity: 0;
} }
//START closed state of the sidebar
&.closed { &.closed {
width: 55px; width: 4.0625rem;
overflow-x: hidden; overflow-x: hidden;
overflow-y: hidden; overflow-y: hidden;
background-color: var(--side-nav-closed-bg-color); background-color: var(--side-nav-closed-bg-color);
border: var(--side-nav-border-closed); border: var(--side-nav-border-closed);
height: calc((var(--vh) * 100) - 6.5rem);
border-radius: unset;
.side-nav {
.side-nav-item {
color: var(--side-nav-item-closed-color);
&:hover {
&.active {
color: var(--side-nav-item-active-text-color);
}
} }
.active-highlight {
opacity: 0;
}
.side-nav-text {
opacity: 0;
display: none;
}
.card-actions {
opacity: 0;
display: none;
}
}
}
}
//END closed state of the sidebar
//START sidebar
.side-nav { .side-nav {
overflow-y: hidden; overflow-y: hidden;
height: 100%; height: 100%;
mask-image: linear-gradient(to bottom, transparent, black 0%, black 97%, transparent 100%);
-webkit-mask-image: linear-gradient(to bottom, transparent, black 0%, black 97%, transparent 100%);
scrollbar-gutter: stable; scrollbar-gutter: stable;
scrollbar-width: thin; scrollbar-width: thin;
//START sidebar nav item
.side-nav-item {
position: relative;
align-items: center;
display: flex;
justify-content: space-between;
width: 100%;
height: auto;
min-height: 2.6rem;
overflow: hidden;
cursor: pointer;
font-size: 0.9rem;
text-decoration: none;
color: var(--side-nav-text-color);
.phone-hidden {
display: flex;
&:first-of-type {
text-align: center;
width: 2.5rem;
margin-left: 0.3rem;
}
&:last-child {
flex-grow: 1;
justify-content: end;
}
div {
align-items: center;
height: 100%;
justify-content: inherit;
width: 100%;
i {
font-size: var(--side-nav-icon-size);
}
}
}
.active-highlight {
background-color: #2f2f2f;
background-color: rgb(255 255 255 / 9%);
width: 0.25rem;
height: 100%;
position: absolute;
left: 0;
}
.side-nav-text {
opacity: 1;
min-width: 6.25rem;
word-break: break-all;
-webkit-line-clamp: 1;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-box-orient: vertical;
overflow: hidden;
div {
min-width: 6.375rem;
width: 100%
}
}
.card-actions {
flex-grow: 1;
justify-content: end;
display: flex;
}
&.active {
background-color: var(--side-nav-active-bg-color);
color: var(--side-nav-item-active-text-color);
.active-highlight {
background-color: var(--side-nav-item-active-color);
}
}
&:hover {
color: var(--side-nav-hover-text-color);
background-color: var(--side-nav-hover-bg-color);
}
}
//END sidebar nav item
// For firefox // For firefox
@supports (-moz-appearance: none) { @supports (-moz-appearance: none) {
scrollbar-color: transparent transparent; scrollbar-color: transparent transparent;
@ -70,7 +176,6 @@
&:hover { &:hover {
scrollbar-width: thin; scrollbar-width: thin;
overflow-y: auto; overflow-y: auto;
// For firefox // For firefox
@supports (-moz-appearance: none) { @supports (-moz-appearance: none) {
scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0); scrollbar-color: rgba(255, 255, 255, 0.3) rgba(0, 0, 0, 0);
@ -81,96 +186,130 @@
background-color: rgba(255, 255, 255, 0.3); /*On hover, it will turn grey*/ background-color: rgba(255, 255, 255, 0.3); /*On hover, it will turn grey*/
} }
} }
}
//END sidebar
//START preference sidebar
&.preference {
height: calc((var(--vh)*100) - 4.6875rem);
width: 14.875rem;
.side-nav-item:first { .side-nav {
border-top-left-radius: var(--side-nav-border-radius); overflow-x: hidden;
border-top-right-radius: var(--side-nav-border-radius); padding-bottom: 0.625rem;
.side-nav-header {
color: #ffffff;
font-size: 0.9375rem;
&:first-of-type {
margin-top: 0.7rem;
} }
} }
}
.sidenav-bottom {
position: absolute;
bottom: 0;
width: 190px;
font-size: 12px;
transition: width var(--side-nav-openclose-transition);
z-index: 999;
left: 10px;
.donate {
.side-nav-item { .side-nav-item {
width: 100%; font-size: 0.9rem;
padding: 0 80px; min-height: 1.875rem;
justify-content: center; justify-content: unset;
align-items: center; margin-left: 1.125rem;
&:hover { &.active {
background-color: unset !important; .side-nav-text {
color: white !important; color: var(--side-nav-item-active-text-color);
i {
color: var(--side-nav-item-closed-color) !important;
&:hover {
color: white !important;
}
}
}
span {
flex-grow: unset !important;
min-width: unset !important;
div {
min-width: unset !important;
i {
font-size: 1rem !important;
}
}
}
&.closed {
span {
&.phone-hidden {
div {
width: 100%;
} }
} }
.side-nav-text { .side-nav-text {
text-align: unset;
margin-left: 0.75rem;
font-size: 0.8125rem;
color: #999999;
}
.card-actions {
display: none;
}
}
}
}
//END preference sidebar
}
//END sidebar container
//START kavita+ subscription bottom heart button
.sidenav-bottom {
position: absolute;
bottom: 0;
width: var(--side-nav-width);
font-size: 0.75rem;
transition: width var(--side-nav-openclose-transition);
z-index: 999;
background-color: var(--side-nav-bg-color);
.donate {
.side-nav-item {
width: 100%;
padding: 0 5rem;
justify-content: center;
align-items: center;
display: flex;
min-height: 3.125rem;
color: var(--side-nav-text-color);
&:hover {
color: var(--side-nav-hover-text-color);
background-color: var(--side-nav-hover-bg-color);
}
.active-highlight {
display: none;
}
.phone-hidden {
div { div {
width: 0; i {
} font-size: var(--side-nav-icon-size);
}
}
} }
} }
} }
.side-nav-text {
display: none !important;
}
.card-actions {
display: none;
}
}
}
//START sidebar closed
&.closed { &.closed {
width: 45px; width: 3.4375rem;
overflow-x: hidden; overflow-x: hidden;
overflow-y: auto; overflow-y: auto;
background-color: unset;
.side-nav-item { .side-nav-item {
width: 100%; width: 100%;
padding: 0; padding: 0;
display: block; display: block;
line-height: 40px; line-height: 2.5rem;
text-align: center; text-align: center;
min-height: unset;
color: var(--side-nav-item-closed-color);
&:hover { &:hover {
background-color: unset; background-color: unset !important;
} }
} }
} }
//END sidebar closed
} }
//END kavita+ subscription bottom heart button
@media (max-width: $grid-breakpoints-lg) { @media (max-width: $grid-breakpoints-lg) {
.side-nav-container { .side-nav-container {
padding: 10px 0; padding: 0.625rem 0;
padding-left: 0.3125rem;
width: 55vw; width: 55vw;
background-color: var(--side-nav-mobile-bg-color); background-color: var(--side-nav-mobile-bg-color);
height: 100dvh; height: 100dvh;
@ -182,6 +321,27 @@
z-index: 1050; z-index: 1050;
overflow-y: auto; overflow-y: auto;
border: var(--side-nav-mobile-border); border: var(--side-nav-mobile-border);
border-radius: 0rem;
&.preference {
background-color: unset;
.side-nav {
.side-nav-header {
font-size: 1.25rem;
}
.side-nav-item {
.active-highlight {
}
.side-nav-text {
div {
font-size: 1rem;
}
}
}
}
}
&.no-donate { &.no-donate {
height: 100dvh; height: 100dvh;
@ -195,33 +355,34 @@
.side-nav { .side-nav {
overflow: auto; overflow: auto;
.side-nav-item {
.active-highlight {
border-top-left-radius: 0rem;
border-bottom-left-radius: 0rem;
}
}
} }
.side-nav-item { .side-nav-item {
padding: 0; padding: 0;
} }
.side-nav-item:first {
border-top-left-radius: var(--side-nav-border-radius);
border-top-right-radius: var(--side-nav-border-radius);
}
} }
.sidenav-bottom { .sidenav-bottom {
display: none; display: none;
&.closed { &.closed {
left: 10px; left: 0.625rem;
} }
} }
.side-nav-overlay { .side-nav-overlay {
background-color: var(--side-nav-overlay-color); background-color: var(--side-nav-overlay-color);
width: 100vw; width: 100vw;
height: calc((var(--vh) * 100) - var(--nav-mobile-offset)); height: 100vh;
position: absolute; position: absolute;
left: 0; left: 0;
top: var(--nav-mobile-offset); top: 0;
z-index: 998; z-index: 1041;
&.closed { &.closed {
display: none; display: none;
@ -230,8 +391,8 @@
} }
.btn-close { .btn-close {
margin-top: -28px; margin-top: -1.75rem;
font-size: 0.8rem; font-size: 0.8rem;
position: absolute; position: absolute;
right: 16px; right: 1rem;
} }

View File

@ -58,29 +58,32 @@
* match the non-default/alpha on launch. * match the non-default/alpha on launch.
*/ */
--colorscape-enabled: true; --colorscape-enabled: true;
/* These are the default background colors for the app. These will be updated on different pages with the generated colors. Must be RGB */ /* These are the default background colors for the app. These will be updated on different pages with the generated colors. Must be RGB */
--colorscape-primary-color: rgb(38, 38, 38); --colorscape-primary-color: rgb(38, 38, 38);
--colorscape-lighter-color: rgb(32, 32, 32); --colorscape-lighter-color: rgb(32, 32, 32);
--colorscape-darker-color: rgb(28, 28, 28); --colorscape-darker-color: rgb(28, 28, 28);
--colorscape-complementary-color: rgb(51, 51, 51); --colorscape-complementary-color: rgb(51, 51, 51);
/* These need to be an alpha 0 variant. */ /* These need to be an alpha 0 variant. */
--colorscape-primary-alpha-color: rgba(38, 38, 38, 0); --colorscape-primary-alpha-color: rgba(38, 38, 38, 0);
--colorscape-lighter-alpha-color: rgba(32, 32, 32, 0); --colorscape-lighter-alpha-color: rgba(32, 32, 32, 0);
--colorscape-darker-alpha-color: rgba(28, 28, 28, 0); --colorscape-darker-alpha-color: rgba(28, 28, 28, 0);
--colorscape-complementary-alpha-color: rgba(51, 51, 51, 0); --colorscape-complementary-alpha-color: rgba(51, 51, 51, 0);
/* These are the default background colors. They need to match and cannot be a var reference. They will not be updated. Must be RGB */ /* These are the default background colors. They need to match and cannot be a var reference. They will not be updated. Must be RGB */
--colorscape-primary-default-color: rgb(38, 38, 38); --colorscape-primary-default-color: rgb(38, 38, 38);
--colorscape-lighter-default-color: rgb(32, 32, 32); --colorscape-lighter-default-color: rgb(32, 32, 32);
--colorscape-darker-default-color: rgb(28, 28, 28); --colorscape-darker-default-color: rgb(28, 28, 28);
--colorscape-complementary-default-color: rgb(51, 51, 51); --colorscape-complementary-default-color: rgb(51, 51, 51);
/* Meta and Globals */ /* Meta and Globals */
--theme-color: #000000; --theme-color: #000000;
--color-scheme: dark; --color-scheme: dark;
--tile-color: var(--primary-color); --tile-color: var(--primary-color);
--nav-offset: 60px; --nav-offset: 60px;
--nav-mobile-offset: 55px; --nav-mobile-offset: 55px;
/* Should we render the series cover as background on mobile */ /* Should we render the series cover as background on mobile */
--mobile-series-img-background: true; --mobile-series-img-background: true;
@ -90,22 +93,20 @@
--setting-header-font-weight: bold; --setting-header-font-weight: bold;
--setting-break-color: rgba(255, 255, 255, 0.2); --setting-break-color: rgba(255, 255, 255, 0.2);
/* Table */ /* Table */
--table-header-bg-color: rgba(0,0,0,.15); --table-header-bg-color: rgba(0,0,0,.15);
--table-header-text-color: hsla(0,0%,100%,.9); --table-header-text-color: hsla(0,0%,100%,.9);
--table-body-bg-color: hsla(0,0%,100%,.02); --table-body-bg-color: hsla(0,0%,100%,.02);
--table-body-text-color: hsla(0,0%,100%,.85); --table-body-text-color: hsla(0,0%,100%,.85);
--table-body-striped-bg-color: hsla(0,0%,100%,.25);
--table-body-border: hidden; --table-body-border: hidden;
--table-body-striped-bg-color: var(--elevation-layer2); --table-body-striped-bg-color: var(--elevation-layer2);
/* Navbar */ /* Navbar */
--navbar-bg-color: var(--elevation-layer11-dark); --navbar-bg-color: black;
--navbar-text-color: white; --navbar-text-color: white;
--navbar-fa-icon-color: white; --navbar-fa-icon-color: white;
--navbar-btn-hover-outline-color: rgba(255, 255, 255, 1); --navbar-btn-hover-outline-color: rgba(255, 255, 255, 1);
--navbar-header-margin: 0px; // 8px allows for the Plex navbar + --nav-offset: 56px;
/* Inputs */ /* Inputs */
--input-bg-color: #343a40; --input-bg-color: #343a40;
@ -124,33 +125,27 @@
--btn-primary-hover-text-color: white; --btn-primary-hover-text-color: white;
--btn-primary-hover-bg-color: var(--primary-color-darker-shade); --btn-primary-hover-bg-color: var(--primary-color-darker-shade);
--btn-primary-hover-border-color: var(--primary-color-darker-shade); --btn-primary-hover-border-color: var(--primary-color-darker-shade);
--btn-primary-outline-text-color: white; --btn-primary-outline-text-color: white;
--btn-primary-outline-bg-color: transparent; --btn-primary-outline-bg-color: transparent;
--btn-primary-outline-border-color: var(--primary-color); --btn-primary-outline-border-color: var(--primary-color);
--btn-primary-outline-hover-text-color: white; --btn-primary-outline-hover-text-color: white;
--btn-primary-outline-hover-bg-color: var(--primary-color-darker-shade); --btn-primary-outline-hover-bg-color: var(--primary-color-darker-shade);
--btn-primary-outline-hover-border-color: var(--primary-color-darker-shade); --btn-primary-outline-hover-border-color: var(--primary-color-darker-shade);
--btn-secondary-text-color: white; --btn-secondary-text-color: white;
--btn-secondary-bg-color: #6c757d; --btn-secondary-bg-color: #6c757d;
--btn-secondary-border-color: #6c757d; --btn-secondary-border-color: #6c757d;
--btn-secondary-hover-bg-color: var(--bs-btn-hover-bg); --btn-secondary-hover-bg-color: var(--bs-btn-hover-bg);
--btn-secondary-hover-border-color: var(--bs-btn-hover-border-color); --btn-secondary-hover-border-color: var(--bs-btn-hover-border-color);
--btn-secondary-font-weight: bold; --btn-secondary-font-weight: bold;
--btn-secondary-outline-text-color: white; --btn-secondary-outline-text-color: white;
--btn-secondary-outline-bg-color: transparent; --btn-secondary-outline-bg-color: transparent;
--btn-secondary-outline-border-color: transparent; --btn-secondary-outline-border-color: transparent;
--btn-secondary-outline-hover-bg-color: transparent; --btn-secondary-outline-hover-bg-color: transparent;
--btn-secondary-outline-hover-border-color: transparent; --btn-secondary-outline-hover-border-color: transparent;
--btn-secondary-outline-font-weight: bold; --btn-secondary-outline-font-weight: bold;
--btn-primary-text-text-color: white; --btn-primary-text-text-color: white;
--btn-secondary-text-text-color: lightgrey; --btn-secondary-text-text-color: lightgrey;
--btn-danger-text-text-color: var(--error-color); --btn-danger-text-text-color: var(--error-color);
--btn-alt-bg-color: #424c72; --btn-alt-bg-color: #424c72;
--btn-alt-border-color: #444f75; --btn-alt-border-color: #444f75;
--btn-alt-hover-bg-color: #3b4466; --btn-alt-hover-bg-color: #3b4466;
@ -161,6 +156,8 @@
--btn-disabled-text-color: white; --btn-disabled-text-color: white;
--btn-disabled-border-color: #6c757d; --btn-disabled-border-color: #6c757d;
--bs-btn-disabled-border-color: transparent; --bs-btn-disabled-border-color: transparent;
--btn-actions-border-radius: 0.375rem;
--btn-actions-hover-bg: rgb(255 255 255 / 18%);
/* Nav (Tabs) */ /* Nav (Tabs) */
--nav-item-min-width: 150px; --nav-item-min-width: 150px;
@ -204,7 +201,6 @@
--alert-text-color: #fff3cd; --alert-text-color: #fff3cd;
--alert-bg-color: transparent; --alert-bg-color: transparent;
/* Checkboxes/Switch */ /* Checkboxes/Switch */
--checkbox-checked-bg-color: var(--primary-color); --checkbox-checked-bg-color: var(--primary-color);
--checkbox-border-color: var(--input-focused-border-color); --checkbox-border-color: var(--input-focused-border-color);
@ -220,6 +216,8 @@
--tagbadge-filled-bg-color: var(--primary-color); --tagbadge-filled-bg-color: var(--primary-color);
/* Side Nav */ /* Side Nav */
--side-nav-width: 230px;
--side-nav-icon-size: 0.9rem;
--side-nav-bg-color: var(--elevation-layer9-dark); --side-nav-bg-color: var(--elevation-layer9-dark);
--side-nav-mobile-bg-color: var(--elevation-layer2-dark-solid); --side-nav-mobile-bg-color: var(--elevation-layer2-dark-solid);
--side-nav-openclose-transition: 0.15s ease-in-out; --side-nav-openclose-transition: 0.15s ease-in-out;
@ -227,8 +225,8 @@
--side-nav-mobile-box-shadow: 3px 0em 5px 10em rgb(0 0 0 / 50%); --side-nav-mobile-box-shadow: 3px 0em 5px 10em rgb(0 0 0 / 50%);
--side-nav-hover-text-color: white; --side-nav-hover-text-color: white;
--side-nav-hover-bg-color: black; --side-nav-hover-bg-color: black;
--side-nav-text-color: white; --side-nav-text-color: hsla(0,0%,100%,.85);
--side-nav-border-radius: 5px; --side-nav-border-radius: 3px;
--side-nav-border: none; --side-nav-border: none;
--side-nav-border-closed: none; --side-nav-border-closed: none;
--side-nav-border-transition: 0.5s ease-in-out; --side-nav-border-transition: 0.5s ease-in-out;
@ -236,13 +234,12 @@
--side-nav-bg-color-transition: 0.5s ease-in-out; --side-nav-bg-color-transition: 0.5s ease-in-out;
--side-nav-closed-bg-color: transparent; --side-nav-closed-bg-color: transparent;
--side-nav-item-active-color: var(--primary-color); --side-nav-item-active-color: var(--primary-color);
--side-nav-item-active-text-color: white; --side-nav-item-active-text-color: #fff;
--side-nav-active-bg-color: transparent; --side-nav-active-bg-color: transparent;
--side-nav-overlay-color: var(--elevation-layer11-dark); --side-nav-overlay-color: var(--elevation-layer11-dark);
--side-nav-item-closed-color: var(--elevation-layer10); --side-nav-item-closed-color: var(--elevation-layer10);
--side-nav-item-closed-hover-color: white; --side-nav-item-closed-hover-color: white;
/* List items */ /* List items */
--list-group-item-text-color: var(--body-text-color); --list-group-item-text-color: var(--body-text-color);
--list-group-item-bg-color: transparent; --list-group-item-bg-color: transparent;
@ -324,6 +321,7 @@
--grid-breakpoints-xl: $grid-breakpoints-xl; --grid-breakpoints-xl: $grid-breakpoints-xl;
--body-font-family: "EBGaramond", "Helvetica Neue", sans-serif; --body-font-family: "EBGaramond", "Helvetica Neue", sans-serif;
--brand-font-family: "Spartan", sans-serif; --brand-font-family: "Spartan", sans-serif;
--html-font-size: 16px;
/* Card */ /* Card */
--card-bg-color: var(--elevation-layer3); --card-bg-color: var(--elevation-layer3);
@ -334,7 +332,7 @@
--card-border-radius: 5px; --card-border-radius: 5px;
--card-progress-bar-color: var(--primary-color); --card-progress-bar-color: var(--primary-color);
--card-overlay-bg-color: rgba(0, 0, 0, 0); --card-overlay-bg-color: rgba(0, 0, 0, 0);
--card-overlay-hover-bg-color: rgba(0, 0, 0, 0.4); --card-overlay-hover-bg-color: rgba(30,30,30,.6);
--card-progress-triangle-size: 28px; --card-progress-triangle-size: 28px;
/* Slider */ /* Slider */
@ -375,14 +373,14 @@
--event-widget-update-bg-color: var(--primary-color); --event-widget-update-bg-color: var(--primary-color);
--event-widget-activity-bg-color: var(--primary-color); --event-widget-activity-bg-color: var(--primary-color);
/* Search */ /* Search */
--search-result-text-lite-color: initial; --search-result-text-lite-color: initial;
--searchbar-bg-color: rgb(255 255 255 / 12%);
/* Bulk Selection */ /* Bulk Selection */
--bulk-selection-text-color: var(--navbar-text-color); --bulk-selection-text-color: var(--navbar-text-color);
--bulk-selection-highlight-text-color: var(--primary-color); --bulk-selection-highlight-text-color: var(--primary-color);
--bulk-selection-bg-color: rgba(39,39,39,1); --bulk-selection-bg-color: var(--elevation-layer11-dark);
/* List Card Item */ /* List Card Item */
--card-list-item-bg-color: linear-gradient(180deg, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.15) 1%, rgba(0,0,0,0) 100%); --card-list-item-bg-color: linear-gradient(180deg, rgba(0,0,0,0.15) 0%, rgba(0,0,0,0.15) 1%, rgba(0,0,0,0) 100%);

View File

@ -1,5 +1,9 @@
// Global styles for the site. Keep this as small as possible // Global styles for the site. Keep this as small as possible
html {
font-size: var(--html-font-size);
}
html, body { height: 100%; overflow: hidden; } html, body { height: 100%; overflow: hidden; }
body { body {
margin: 0; margin: 0;