style(ui): refactor reader layout grid, fix focus mode layout collapse, fix SVG rendering dots, reorganize intelligence toolbar (#69)
Reorganized the reader toolbar and layout grid to improve visual consistency and layout robustness in Focus Mode. Fixed outline SVG rendering bugs that caused icons to show as solid dots. Closes #70 --------- Co-authored-by: Marek Jasiński <jasins.marek@gmail.com> Reviewed-on: #69 Co-authored-by: Antigravity <antigravity@google.com> Co-committed-by: Antigravity <antigravity@google.com>
This commit was merged in pull request #69.
This commit is contained in:
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="verification-state" style="@(IsVerifying ? "display:flex;" : "display:none;")">
|
||||
<div class="verification-state" style="@((IsVerifying && !IsIngesting) ? "display:flex;" : "display:none;")">
|
||||
@if (Metadata != null)
|
||||
{
|
||||
<div class="verification-layout">
|
||||
|
||||
@@ -196,52 +196,37 @@
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-family: var(--nexus-font-sans);
|
||||
font-weight: 600;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
font-size: 0.85rem;
|
||||
letter-spacing: 0.5px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-transform: uppercase;
|
||||
::deep .nexus-btn.btn-primary {
|
||||
background: var(--nexus-neon, #00ffaa) !important;
|
||||
color: #050505 !important;
|
||||
border-color: transparent !important;
|
||||
box-shadow: 0 4px 12px rgba(var(--nexus-accent-rgb, 0, 255, 170), 0.2) !important;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--nexus-neon, #00ffaa);
|
||||
color: #050505;
|
||||
box-shadow: 0 4px 12px rgba(var(--nexus-accent-rgb, 0, 255, 170), 0.2);
|
||||
::deep .nexus-btn.btn-primary:hover:not(:disabled) {
|
||||
background: #00e699 !important;
|
||||
transform: translateY(-2px) !important;
|
||||
box-shadow: 0 6px 20px rgba(var(--nexus-accent-rgb, 0, 255, 170), 0.4) !important;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
background: #00e699;
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(var(--nexus-accent-rgb, 0, 255, 170), 0.4);
|
||||
::deep .nexus-btn.btn-primary:active:not(:disabled) {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: translateY(0);
|
||||
::deep .nexus-btn.btn-secondary {
|
||||
background: rgba(255, 255, 255, 0.03) !important;
|
||||
color: var(--nexus-text) !important;
|
||||
border: 1px solid rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
color: var(--nexus-text);
|
||||
border: 1px solid rgba(255, 255, 255, 0.1);
|
||||
::deep .nexus-btn.btn-secondary:hover:not(:disabled) {
|
||||
background: rgba(255, 255, 255, 0.08) !important;
|
||||
border-color: rgba(255, 255, 255, 0.3) !important;
|
||||
transform: translateY(-2px) !important;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: rgba(255, 255, 255, 0.3);
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
.btn-secondary:active {
|
||||
transform: translateY(0);
|
||||
::deep .nexus-btn.btn-secondary:active:not(:disabled) {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
|
||||
/* Verification State */
|
||||
@@ -357,27 +342,30 @@
|
||||
to { transform: scale(1.2); opacity: 0.8; }
|
||||
}
|
||||
|
||||
.btn:disabled {
|
||||
opacity: 0.5;
|
||||
cursor: not-allowed;
|
||||
filter: grayscale(1);
|
||||
::deep .nexus-btn:disabled:not(.btn-loading) {
|
||||
opacity: 0.4 !important;
|
||||
cursor: not-allowed !important;
|
||||
filter: grayscale(1) !important;
|
||||
}
|
||||
|
||||
.btn-loading {
|
||||
position: relative;
|
||||
::deep .nexus-btn.btn-loading {
|
||||
position: relative !important;
|
||||
color: transparent !important;
|
||||
opacity: 1 !important;
|
||||
cursor: wait !important;
|
||||
filter: none !important;
|
||||
}
|
||||
|
||||
.btn-loading::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2);
|
||||
border-top-color: var(--nexus-neon, #00ffaa);
|
||||
border-radius: 50%;
|
||||
animation: spin 0.8s linear infinite;
|
||||
filter: drop-shadow(0 0 4px var(--nexus-neon, #00ffaa));
|
||||
::deep .nexus-btn.btn-loading::after {
|
||||
content: "" !important;
|
||||
position: absolute !important;
|
||||
width: 20px !important;
|
||||
height: 20px !important;
|
||||
border: 2px solid rgba(255, 255, 255, 0.2) !important;
|
||||
border-top-color: var(--nexus-neon, #00ffaa) !important;
|
||||
border-radius: 50% !important;
|
||||
animation: spin 0.8s linear infinite !important;
|
||||
filter: drop-shadow(0 0 4px var(--nexus-neon, #00ffaa)) !important;
|
||||
}
|
||||
|
||||
/* Indexing State */
|
||||
|
||||
@@ -12,21 +12,21 @@
|
||||
<div class="knowledge-graph-container @(GraphService.IsLoading ? "loading" : "")" id="@ContainerId">
|
||||
@if (GraphService.IsLoading || GraphService.CurrentGraphData == null)
|
||||
{
|
||||
<div class="loading-state">
|
||||
<div class="preloader-robot">
|
||||
<NexusIcon Name="robot" Size="64" Class="neon-pulse" />
|
||||
<div class="scan-line"></div>
|
||||
<div class="loading-state">
|
||||
<div class="preloader-robot">
|
||||
<NexusIcon Name="robot" Size="64" Class="neon-pulse" />
|
||||
<div class="scan-line"></div>
|
||||
</div>
|
||||
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">Mapowanie relacji rozdziału...</NexusTypography>
|
||||
</div>
|
||||
<NexusTypography Variant="NexusTypography.TypographyVariant.UI">Mapowanie relacji rozdziału...</NexusTypography>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="graph-controls">
|
||||
<button class="zoom-btn" @onclick="ZoomIn" title="Zoom In">+</button>
|
||||
<button class="zoom-btn" @onclick="ZoomOut" title="Zoom Out">−</button>
|
||||
<button class="zoom-btn reset" @onclick="ZoomReset" title="Reset">⟲</button>
|
||||
</div>
|
||||
<div class="graph-controls">
|
||||
<button class="zoom-btn" @onclick="ZoomIn" title="Zoom In">+</button>
|
||||
<button class="zoom-btn" @onclick="ZoomOut" title="Zoom Out">−</button>
|
||||
<button class="zoom-btn reset" @onclick="ZoomReset" title="Reset">⟲</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
private async Task HandleGraphUpdate()
|
||||
{
|
||||
if (_module == null) return;
|
||||
|
||||
|
||||
if (GraphService.CurrentGraphData == null)
|
||||
{
|
||||
await _module.InvokeVoidAsync("clear");
|
||||
@@ -58,7 +58,7 @@
|
||||
{
|
||||
await _module.InvokeVoidAsync("updateData", GraphService.CurrentGraphData);
|
||||
}
|
||||
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
if (firstRender)
|
||||
{
|
||||
await InitializeGraphAsync();
|
||||
|
||||
|
||||
if (GraphService.CurrentGraphData != null)
|
||||
{
|
||||
await HandleGraphUpdate();
|
||||
@@ -101,7 +101,7 @@
|
||||
public async Task OnNodeClicked(string nodeId)
|
||||
{
|
||||
await InteractionService.NotifyNodeSelected(nodeId);
|
||||
|
||||
|
||||
if (OnNodeSelected.HasDelegate)
|
||||
{
|
||||
await OnNodeSelected.InvokeAsync(nodeId);
|
||||
@@ -128,7 +128,7 @@
|
||||
GraphService.OnGraphUpdated -= HandleGraphUpdate;
|
||||
GraphService.OnActiveNodeChanged -= HandleActiveNodeChange;
|
||||
GraphService.OnLoadingChanged -= HandleLoadingChange;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if (_module is not null)
|
||||
@@ -138,7 +138,7 @@
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
|
||||
_dotNetHelper?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.knowledge-graph-container.loading > ::deep svg {
|
||||
.knowledge-graph-container.loading> ::deep svg {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@@ -93,9 +93,20 @@
|
||||
}
|
||||
|
||||
@keyframes robot-pulse {
|
||||
0% { transform: scale(1); filter: drop-shadow(0 0 10px var(--nexus-neon)); }
|
||||
50% { transform: scale(1.1); filter: drop-shadow(0 0 25px var(--nexus-neon)); }
|
||||
100% { transform: scale(1); filter: drop-shadow(0 0 10px var(--nexus-neon)); }
|
||||
0% {
|
||||
transform: scale(1);
|
||||
filter: drop-shadow(0 0 10px var(--nexus-neon));
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
filter: drop-shadow(0 0 25px var(--nexus-neon));
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
filter: drop-shadow(0 0 10px var(--nexus-neon));
|
||||
}
|
||||
}
|
||||
|
||||
.scan-line {
|
||||
@@ -111,9 +122,17 @@
|
||||
}
|
||||
|
||||
@keyframes scan {
|
||||
0% { top: 0; }
|
||||
50% { top: 100%; }
|
||||
100% { top: 0; }
|
||||
0% {
|
||||
top: 0;
|
||||
}
|
||||
|
||||
50% {
|
||||
top: 100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
::deep .nexus-node-active {
|
||||
@@ -124,11 +143,24 @@
|
||||
}
|
||||
|
||||
::deep @keyframes neon-flash {
|
||||
0% { filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon)); }
|
||||
50% { filter: brightness(3) drop-shadow(0 0 30px var(--nexus-neon)); }
|
||||
100% { filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon)); }
|
||||
0% {
|
||||
filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon));
|
||||
}
|
||||
|
||||
50% {
|
||||
filter: brightness(3) drop-shadow(0 0 30px var(--nexus-neon));
|
||||
}
|
||||
|
||||
100% {
|
||||
filter: brightness(1) drop-shadow(0 0 0px var(--nexus-neon));
|
||||
}
|
||||
}
|
||||
|
||||
::deep .neon-flash-node {
|
||||
animation: neon-flash 0.8s ease-out;
|
||||
}
|
||||
|
||||
.knowledge-graph-container ::deep svg {
|
||||
background: radial-gradient(circle, #1a1a1a 0%, #121212 100%);
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
@@ -99,6 +99,7 @@
|
||||
private bool _isMobile = false;
|
||||
private DotNetObjectReference<ReaderCanvas>? _selfReference;
|
||||
private IJSObjectReference? _viewportModule;
|
||||
private IJSObjectReference? _selectionModule;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
@@ -201,10 +202,13 @@
|
||||
{
|
||||
try
|
||||
{
|
||||
var module = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/NexusReader.UI.Shared/js/selectionHandler.js");
|
||||
if (_selectionModule == null)
|
||||
{
|
||||
_selectionModule = await JS.InvokeAsync<IJSObjectReference>("import", "./_content/NexusReader.UI.Shared/js/selectionHandler.js");
|
||||
}
|
||||
if (_selfReference != null)
|
||||
{
|
||||
await module.InvokeVoidAsync("initSelectionListener", _selfReference, _containerRef);
|
||||
await _selectionModule.InvokeVoidAsync("initSelectionListener", _selfReference, _containerRef);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -440,6 +444,19 @@
|
||||
InteractionService.OnTextSelected -= HandleTextSelected;
|
||||
SyncService.OnProgressReceived -= HandleSyncProgressReceived;
|
||||
|
||||
try
|
||||
{
|
||||
if (_selectionModule != null)
|
||||
{
|
||||
await _selectionModule.InvokeVoidAsync("destroySelectionListener");
|
||||
await _selectionModule.DisposeAsync();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogDebug(ex, "Failed to destroy JS selection listener.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_viewportModule != null)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
padding: 2rem 0;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
position: relative;
|
||||
|
||||
|
||||
/* Dedicated Scrollbar Styling */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 255, 153, 0.2) transparent;
|
||||
@@ -30,18 +30,40 @@
|
||||
background-color: rgba(0, 255, 153, 0.5);
|
||||
}
|
||||
|
||||
.reader-canvas.theme-dark {
|
||||
background-color: #121214;
|
||||
}
|
||||
|
||||
.reader-canvas.theme-light {
|
||||
background-color: #F9F9F9; /* Paper-white requirement */
|
||||
background-color: #f4f1ea;
|
||||
/* Warm light beige/gray background */
|
||||
}
|
||||
|
||||
.reader-flow-container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
max-width: 680px;
|
||||
margin: 2rem auto;
|
||||
min-height: calc(100vh - 180px);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 1.5rem;
|
||||
position: relative;
|
||||
padding: 0 1.5rem 15rem 1.5rem; /* Large padding-bottom for reachability */
|
||||
padding: 3rem 4rem 15rem 4rem;
|
||||
/* Large padding-bottom for reachability, plus comfortable side margins */
|
||||
border-radius: 12px;
|
||||
box-sizing: border-box;
|
||||
transition: background-color 0.3s, box-shadow 0.3s, border-color 0.3s;
|
||||
}
|
||||
|
||||
.theme-dark .reader-flow-container {
|
||||
background-color: #1a1a1e;
|
||||
border: 1px solid rgba(255, 255, 255, 0.03);
|
||||
box-shadow: 0 4px 30px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.theme-light .reader-flow-container {
|
||||
background-color: #ffffff;
|
||||
border: 1px solid rgba(0, 0, 0, 0.04);
|
||||
box-shadow: 0 4px 20px rgba(139, 130, 115, 0.12);
|
||||
}
|
||||
|
||||
.block-wrapper {
|
||||
@@ -57,24 +79,49 @@
|
||||
line-height: 1.65 !important;
|
||||
letter-spacing: -0.01em !important;
|
||||
font-size: 1.15rem;
|
||||
font-weight: 300;
|
||||
font-weight: 400;
|
||||
text-align: left !important;
|
||||
color: #e4e4e7;
|
||||
/* Off-white with light gray tint */
|
||||
}
|
||||
|
||||
.theme-light ::deep .nexus-ebook {
|
||||
color: #1a1a1a;
|
||||
color: #292524;
|
||||
/* Warm charcoal for legibility */
|
||||
}
|
||||
|
||||
/* Callout Box styling for legacy blockquote segments */
|
||||
::deep .nexus-ebook blockquote {
|
||||
background-color: rgba(255, 255, 255, 0.02);
|
||||
border-left: 4px solid var(--nexus-neon);
|
||||
padding: 1rem 1.25rem;
|
||||
margin: 1.5rem 0 1.5rem 0;
|
||||
border-radius: 0 8px 8px 0;
|
||||
font-size: 1.05rem;
|
||||
color: #e2e8f0;
|
||||
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.theme-light ::deep .nexus-ebook blockquote {
|
||||
background-color: rgba(245, 158, 11, 0.04);
|
||||
border-left: 4px solid #f59e0b;
|
||||
color: #44403c;
|
||||
}
|
||||
|
||||
|
||||
/* Technical Code Block Container */
|
||||
::deep .nexus-ebook pre {
|
||||
background-color: #2d2d2d; /* Dark theme for code for better contrast */
|
||||
background-color: #2d2d2d;
|
||||
/* Dark theme for code for better contrast */
|
||||
color: #e0e0e0;
|
||||
padding: 1.25rem;
|
||||
border-radius: 8px;
|
||||
margin: 2rem 0;
|
||||
overflow-x: auto;
|
||||
box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
|
||||
border-left: 4px solid var(--nexus-neon); /* Nexus neon accent */
|
||||
|
||||
box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.1);
|
||||
border-left: 4px solid var(--nexus-neon);
|
||||
/* Nexus neon accent */
|
||||
|
||||
/* Dedicated Scrollbar for Code */
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: rgba(0, 255, 153, 0.3) transparent;
|
||||
@@ -101,7 +148,8 @@
|
||||
/* Inline Code Highlight */
|
||||
::deep .nexus-ebook p code {
|
||||
background-color: rgba(0, 0, 0, 0.05);
|
||||
color: #d63384; /* Classic differentiator for inline code */
|
||||
color: #d63384;
|
||||
/* Classic differentiator for inline code */
|
||||
padding: 0.2rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
font-size: 0.9em;
|
||||
@@ -153,9 +201,20 @@
|
||||
}
|
||||
|
||||
@keyframes pulse-small {
|
||||
0% { transform: scale(1); opacity: 1; }
|
||||
50% { transform: scale(1.1); opacity: 0.8; }
|
||||
100% { transform: scale(1); opacity: 1; }
|
||||
0% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.1);
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Chapter Loading Overlay and Spinners */
|
||||
@@ -246,29 +305,48 @@
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% { transform: rotate(0deg); }
|
||||
100% { transform: rotate(360deg); }
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
from { transform: scale(0.9) translateY(10px); opacity: 0; }
|
||||
to { transform: scale(1) translateY(0); opacity: 1; }
|
||||
from {
|
||||
transform: scale(0.9) translateY(10px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: scale(1) translateY(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeIn {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* MOBILE READER UI OVERRIDES */
|
||||
@media (max-width: 768px) {
|
||||
.reader-canvas {
|
||||
padding-top: 54px !important;
|
||||
padding-bottom: 80px !important; /* Ensure content is clear of bottom toolbar */
|
||||
padding-bottom: 80px !important;
|
||||
/* Ensure content is clear of bottom toolbar */
|
||||
}
|
||||
|
||||
.reader-flow-container {
|
||||
padding-bottom: 4rem; /* Safe breathing room */
|
||||
padding-bottom: 4rem;
|
||||
/* Safe breathing room */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,7 +416,20 @@
|
||||
}
|
||||
|
||||
.theme-light .nexus-mobile-chapter-title {
|
||||
color: #1a1a1a;
|
||||
color: #292524;
|
||||
}
|
||||
|
||||
.theme-light .nexus-mobile-escape-btn {
|
||||
color: #78716c;
|
||||
}
|
||||
|
||||
.theme-light .nexus-mobile-escape-btn:hover {
|
||||
color: #10b981;
|
||||
background-color: rgba(16, 185, 129, 0.05);
|
||||
}
|
||||
|
||||
.theme-light .nexus-mobile-escape-btn:active {
|
||||
background-color: rgba(16, 185, 129, 0.08);
|
||||
}
|
||||
|
||||
.nexus-chapter-nav-btn {
|
||||
@@ -372,4 +463,4 @@
|
||||
|
||||
.theme-light .nexus-chapter-nav-btn:hover:not(:disabled) {
|
||||
background: rgba(0, 0, 0, 0.06);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +1,99 @@
|
||||
.reader-footer {
|
||||
position: relative;
|
||||
height: 50px;
|
||||
background: #F9F9F9;
|
||||
border-top: 1px solid rgba(0, 0, 0, 0.08);
|
||||
position: absolute;
|
||||
bottom: 24px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: min(600px, 90%);
|
||||
height: 54px;
|
||||
background: rgba(24, 24, 27, 0.6);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 9999px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 1.5rem;
|
||||
z-index: 10;
|
||||
flex-shrink: 0;
|
||||
z-index: 100;
|
||||
transition: background 0.3s, border-color 0.3s, box-shadow 0.3s;
|
||||
}
|
||||
|
||||
.theme-light .reader-footer {
|
||||
background: rgba(254, 254, 254, 0.75);
|
||||
border: 1px solid rgba(0, 0, 0, 0.08);
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.04), 0 1px 3px rgba(0, 0, 0, 0.02);
|
||||
}
|
||||
|
||||
.footer-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
gap: 1.5rem;
|
||||
gap: 1rem;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.navigation-controls {
|
||||
display: grid;
|
||||
grid-template-columns: 32px 1fr 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
width: 260px;
|
||||
flex-shrink: 0;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
background: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
border-radius: 6px;
|
||||
background: rgba(255, 255, 255, 0.03);
|
||||
border: 1px solid rgba(255, 255, 255, 0.08);
|
||||
border-radius: 50%;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
color: #333;
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
|
||||
transition: color 0.2s ease-in-out, background-color 0.2s ease-in-out, border-color 0.2s ease-in-out, transform 0.2s ease-in-out;
|
||||
color: #a1a1aa; /* Zinc-400 default contrast */
|
||||
}
|
||||
|
||||
.nav-btn:hover:not(:disabled) {
|
||||
background: #f0f0f0;
|
||||
transform: translateY(-1px);
|
||||
.nav-btn:hover:not(:disabled),
|
||||
.nav-btn:focus:not(:disabled) {
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-color: var(--nexus-neon, #00ff99);
|
||||
color: var(--nexus-neon, #00ff99); /* Brand neon green hover/focus signal */
|
||||
transform: scale(1.05);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.nav-btn:disabled {
|
||||
opacity: 0.3;
|
||||
opacity: 0.25;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.theme-light .nav-btn {
|
||||
background: rgba(0, 0, 0, 0.02);
|
||||
border-color: rgba(0, 0, 0, 0.08);
|
||||
color: #78716c; /* Warm stone-500 */
|
||||
}
|
||||
|
||||
.theme-light .nav-btn:hover:not(:disabled),
|
||||
.theme-light .nav-btn:focus:not(:disabled) {
|
||||
background: rgba(16, 185, 129, 0.05);
|
||||
border-color: #10b981;
|
||||
color: #10b981;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.chapter-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
align-items: flex-start;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: #333;
|
||||
flex: 1;
|
||||
color: #e2e8f0; /* Slate-200 for clean high readability */
|
||||
}
|
||||
|
||||
.theme-light .chapter-info {
|
||||
color: #292524; /* Warm charcoal for legibility */
|
||||
}
|
||||
|
||||
.chapter-title {
|
||||
@@ -68,42 +103,66 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.chapter-count {
|
||||
opacity: 0.5;
|
||||
font-size: 0.75rem;
|
||||
color: #a1a1aa; /* Zinc-400 for secondary info clarity */
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
.theme-light .chapter-count {
|
||||
color: #78716c; /* Warm stone-500 secondary info */
|
||||
}
|
||||
|
||||
.progress-container {
|
||||
flex: 1;
|
||||
height: 6px;
|
||||
background: rgba(0, 0, 0, 0.05);
|
||||
border-radius: 3px;
|
||||
width: 80px;
|
||||
height: 4px;
|
||||
background: rgba(255, 255, 255, 0.08);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
margin: 0 1rem;
|
||||
margin: 0 0.25rem;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.theme-light .progress-container {
|
||||
background: rgba(0, 0, 0, 0.08);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
height: 100%;
|
||||
background: #2ECC71;
|
||||
border-radius: 3px;
|
||||
background: var(--nexus-neon, #00ff99);
|
||||
border-radius: 2px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.theme-light .progress-bar {
|
||||
background: #10b981;
|
||||
}
|
||||
|
||||
.meta-info {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
font-size: 0.75rem;
|
||||
color: #888;
|
||||
gap: 0.75rem;
|
||||
font-size: 0.7rem;
|
||||
color: #a1a1aa;
|
||||
flex-shrink: 0;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.theme-light .meta-info {
|
||||
color: #78716c;
|
||||
}
|
||||
|
||||
.battery {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
/* RWD constraint: floating toolbar visible ONLY on desktop (min-width: 1024px) */
|
||||
@media (max-width: 1023px) {
|
||||
.reader-footer {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user