mirror of
https://github.com/booklore-app/booklore.git
synced 2026-02-18 00:17:53 +01:00
feat(reader): improve cbx reader mobile header and slideshow indicator
This commit is contained in:
@@ -33,9 +33,7 @@
|
||||
}
|
||||
|
||||
@if (isSlideshowActive) {
|
||||
<div class="slideshow-indicator">
|
||||
<span class="slideshow-badge">Slideshow</span>
|
||||
</div>
|
||||
<div class="slideshow-progress" [class.above-footer]="isFooterVisible" [style.animation-duration.ms]="slideshowInterval"></div>
|
||||
}
|
||||
|
||||
<div class="image-container"
|
||||
|
||||
@@ -28,33 +28,26 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Slideshow indicator
|
||||
.slideshow-indicator {
|
||||
// Slideshow progress bar
|
||||
.slideshow-progress {
|
||||
position: absolute;
|
||||
top: 60px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
z-index: 11;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
height: 3px;
|
||||
background: #4a90e2;
|
||||
z-index: 1001;
|
||||
pointer-events: none;
|
||||
animation: slideshow-fill linear infinite;
|
||||
transition: bottom 0.3s ease;
|
||||
|
||||
.slideshow-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
padding: 6px 12px;
|
||||
background: rgba(74, 144, 226, 0.9);
|
||||
border-radius: 16px;
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
color: white;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
&.above-footer {
|
||||
bottom: 52px;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0%, 100% { opacity: 1; }
|
||||
50% { opacity: 0.7; }
|
||||
@keyframes slideshow-fill {
|
||||
from { width: 0; }
|
||||
to { width: 100%; }
|
||||
}
|
||||
|
||||
.bookmark-indicator {
|
||||
@@ -550,6 +543,10 @@
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.comic-reader-container {
|
||||
.slideshow-progress.above-footer {
|
||||
bottom: 48px;
|
||||
}
|
||||
|
||||
.image-container {
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
||||
@@ -94,6 +94,9 @@ export class CbxReaderComponent implements OnInit, OnDestroy {
|
||||
noteDialogData: CbxNoteDialogData | null = null;
|
||||
private editingNote: BookNoteV2 | null = null;
|
||||
|
||||
// Footer visibility (for slideshow progress bar positioning)
|
||||
isFooterVisible = false;
|
||||
|
||||
// Fullscreen state
|
||||
isFullscreen = false;
|
||||
|
||||
@@ -149,6 +152,10 @@ export class CbxReaderComponent implements OnInit, OnDestroy {
|
||||
this.footerService.setForceVisible(state.footerVisible);
|
||||
});
|
||||
|
||||
this.footerService.forceVisible$
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(visible => this.isFooterVisible = visible);
|
||||
|
||||
this.subscribeToHeaderEvents();
|
||||
this.subscribeToSidebarEvents();
|
||||
this.subscribeToFooterEvents();
|
||||
|
||||
@@ -15,15 +15,37 @@
|
||||
</div>
|
||||
<span class="book-title">{{ bookTitle }}</span>
|
||||
<div class="header-right">
|
||||
<button class="icon-btn" (click)="onToggleSlideshow()" [title]="state.isSlideshowActive ? 'Stop Slideshow (P)' : 'Start Slideshow (P)'" [class.active]="state.isSlideshowActive">
|
||||
<button class="icon-btn desktop-only" (click)="onToggleSlideshow()" [title]="state.isSlideshowActive ? 'Stop Slideshow (P)' : 'Start Slideshow (P)'" [class.active]="state.isSlideshowActive">
|
||||
<app-reader-icon [name]="state.isSlideshowActive ? 'pause' : 'play'" [size]="20" />
|
||||
</button>
|
||||
<button class="icon-btn" (click)="onToggleFullscreen()" [title]="state.isFullscreen ? 'Exit Fullscreen (F)' : 'Fullscreen (F)'">
|
||||
<button class="icon-btn desktop-only" (click)="onToggleFullscreen()" [title]="state.isFullscreen ? 'Exit Fullscreen (F)' : 'Fullscreen (F)'">
|
||||
<app-reader-icon [name]="state.isFullscreen ? 'fullscreen-exit' : 'fullscreen'" [size]="20" />
|
||||
</button>
|
||||
<button class="icon-btn" (click)="onShowShortcutsHelp()" title="Keyboard Shortcuts (?)">
|
||||
<button class="icon-btn desktop-only" (click)="onShowShortcutsHelp()" title="Keyboard Shortcuts (?)">
|
||||
<app-reader-icon name="help" [size]="20" />
|
||||
</button>
|
||||
<div class="overflow-menu mobile-only">
|
||||
<button class="icon-btn" (click)="overflowOpen = !overflowOpen; $event.stopPropagation()" title="More">
|
||||
<app-reader-icon name="dots-vertical" [size]="20" />
|
||||
</button>
|
||||
@if (overflowOpen) {
|
||||
<div class="overflow-backdrop" (click)="overflowOpen = false"></div>
|
||||
<div class="overflow-dropdown">
|
||||
<button class="overflow-item" (click)="onToggleSlideshow(); overflowOpen = false" [class.active]="state.isSlideshowActive">
|
||||
<app-reader-icon [name]="state.isSlideshowActive ? 'pause' : 'play'" [size]="18" />
|
||||
<span>{{ state.isSlideshowActive ? 'Stop Slideshow' : 'Start Slideshow' }}</span>
|
||||
</button>
|
||||
<button class="overflow-item" (click)="onToggleFullscreen(); overflowOpen = false">
|
||||
<app-reader-icon [name]="state.isFullscreen ? 'fullscreen-exit' : 'fullscreen'" [size]="18" />
|
||||
<span>{{ state.isFullscreen ? 'Exit Fullscreen' : 'Fullscreen' }}</span>
|
||||
</button>
|
||||
<button class="overflow-item" (click)="onShowShortcutsHelp(); overflowOpen = false">
|
||||
<app-reader-icon name="help" [size]="18" />
|
||||
<span>Keyboard Shortcuts</span>
|
||||
</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<button class="icon-btn" (click)="onOpenSettings()" title="Settings">
|
||||
<app-reader-icon name="settings" [size]="20" />
|
||||
</button>
|
||||
|
||||
@@ -105,6 +105,58 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.mobile-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.overflow-menu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.overflow-backdrop {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.overflow-dropdown {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
right: 0;
|
||||
margin-top: 4px;
|
||||
background: #2d2d2d;
|
||||
border: 1px solid #404040;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.4);
|
||||
z-index: 1000;
|
||||
min-width: 180px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.overflow-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 10px;
|
||||
width: 100%;
|
||||
padding: 8px 12px;
|
||||
background: none;
|
||||
border: none;
|
||||
color: #ffffff;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
border-radius: 6px;
|
||||
white-space: nowrap;
|
||||
|
||||
&:hover {
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
}
|
||||
|
||||
&.active {
|
||||
color: #ef4444;
|
||||
background: rgba(239, 68, 68, 0.15);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
@@ -123,5 +175,13 @@
|
||||
.book-title {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.desktop-only {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.mobile-only {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ export class CbxHeaderComponent implements OnInit, OnDestroy {
|
||||
@Input() currentPageHasNotes = false;
|
||||
|
||||
isVisible = true;
|
||||
overflowOpen = false;
|
||||
state: CbxHeaderState = {
|
||||
isFullscreen: false,
|
||||
isSlideshowActive: false
|
||||
|
||||
Reference in New Issue
Block a user