feat(editor): align selection popup and all editor control elements styling with Reader

This commit is contained in:
2026-06-11 19:46:32 +02:00
parent c8d9646110
commit 039973b974
6 changed files with 717 additions and 462 deletions
@@ -95,11 +95,11 @@
</div> </div>
<span class="nav-text">Koncentry</span> <span class="nav-text">Koncentry</span>
</NavLink> </NavLink>
<NavLink class="nav-item" href="/dev/creator-test" @onclick="CloseMobileMenu" title="Kreator (Dev)" aria-label="Kreator (Dev)"> <NavLink class="nav-item" href="/creator" @onclick="CloseMobileMenu" title="Kreator" aria-label="Kreator">
<div class="nav-icon"> <div class="nav-icon">
<NexusIcon Name="edit" Size="20" /> <NexusIcon Name="edit" Size="20" />
</div> </div>
<span class="nav-text">Kreator (Dev)</span> <span class="nav-text">Kreator</span>
</NavLink> </NavLink>
</nav> </nav>
+13 -11
View File
@@ -10,18 +10,20 @@
<p class="subtitle">Zen publishing workspace mapping standard Markdown into clean visual blocks.</p> <p class="subtitle">Zen publishing workspace mapping standard Markdown into clean visual blocks.</p>
</div> </div>
<div class="milkdown-premium-container" spellcheck="false"> <div class="milkdown-premium-container creator-workspace-card" spellcheck="false">
<MarkdownEditor @ref="_editorRef" InitialMarkdown="@_initialMarkdown" OnSave="HandleSave" ShowFetchButton="false" Height="450px" /> <div class="editor-growing-area">
</div> <MarkdownEditor @ref="_editorRef" InitialMarkdown="@_initialMarkdown" OnSave="HandleSave" ShowFetchButton="false" Height="100%" />
</div>
<div class="creator-actions-bar"> <div class="creator-actions-bar">
<button type="button" @onclick="TriggerFetchAsync" class="nexus-btn premium-fetch-btn"> <button type="button" @onclick="TriggerFetchAsync" class="nexus-btn premium-fetch-btn btn-nexus-premium">
<span>Fetch Markdown Content</span> <span>Fetch Markdown Content</span>
<svg class="arrow-icon" viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2.5" fill="none" stroke-linecap="round" stroke-linejoin="round"> <svg class="arrow-icon" viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2.5" fill="none" stroke-linecap="round" stroke-linejoin="round">
<line x1="5" y1="12" x2="19" y2="12"></line> <line x1="5" y1="12" x2="19" y2="12"></line>
<polyline points="12 5 19 12 12 19"></polyline> <polyline points="12 5 19 12 12 19"></polyline>
</svg> </svg>
</button> </button>
</div>
</div> </div>
@if (!string.IsNullOrEmpty(_savedMarkdown)) @if (!string.IsNullOrEmpty(_savedMarkdown))
+150 -58
View File
@@ -2,70 +2,168 @@
Creator.razor.css - Isolated Styles for Zen Mode Creator Workspace Creator.razor.css - Isolated Styles for Zen Mode Creator Workspace
========================================================================== */ ========================================================================== */
/* 1. BOUNDARY & SCROLLING RE-ENGINEERING */
/* Strict flexbox layout context eliminating global browser scrollbars */
.creator-fullscreen-wrapper { .creator-fullscreen-wrapper {
max-width: 1200px; width: 100% !important;
margin: 2rem auto; max-width: 100% !important; /* Likwidujemy sztuczne ograniczenia szerokości */
padding: 0 1.5rem; margin: 0;
padding: 1.5rem; /* Elastyczny, bezpieczny margines od krawędzi bocznych menu i ekranu */
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 1.5rem; height: calc(100vh - 4rem);
box-sizing: border-box;
overflow: hidden;
gap: 1.25rem;
}
.creator-header {
flex-shrink: 0;
padding-left: 0.5rem;
} }
.creator-header h1 { .creator-header h1 {
font-size: 2rem; font-size: 1.75rem;
font-weight: 700; font-weight: 700;
color: var(--text-main); color: var(--text-main);
margin: 0 0 0.5rem 0; margin: 0 0 0.25rem 0;
} }
.creator-header .subtitle { .creator-header .subtitle {
font-size: 1rem; font-size: 0.9rem;
color: var(--text-muted); color: var(--text-muted);
margin: 0; margin: 0;
} }
/* 1. Main Workspace Card Layer Elevation */ /* 2. Full Viewport Workspace Card stretching smoothly */
.milkdown-premium-container { .creator-workspace-card {
background-color: var(--bg-surface) !important; background-color: var(--bg-surface) !important;
border: 1px solid var(--border) !important; border: 1px solid var(--border) !important;
border-radius: var(--radius-lg); border-radius: 20px;
padding: 1.5rem; padding: 2rem;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.15); box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2);
position: relative; display: flex;
flex-direction: column;
flex-grow: 1;
width: 100% !important;
box-sizing: border-box;
overflow: hidden; overflow: hidden;
} }
/* 2. Deep Component Style Isolation */ .editor-growing-area {
flex-grow: 1;
display: flex;
flex-direction: column;
overflow: hidden;
}
/* Fix Top Text Clipping & padding context on the ProseMirror surface */ /* 3. Deep Cascading Overrides to target dynamic editor components */
::deep .markdown-editor-container {
height: 100% !important;
display: flex !important;
flex-direction: column !important;
flex-grow: 1 !important;
overflow: hidden !important;
}
::deep .milkdown-editor-wrapper {
display: flex !important;
flex-direction: column !important;
flex-grow: 1 !important;
overflow: hidden !important;
}
/* Force crepe and milkdown inner wrappers to stretch */
::deep .crepe,
::deep .milkdown {
width: 100% !important;
max-width: 100% !important;
display: flex !important;
flex-direction: column !important;
flex-grow: 1 !important;
overflow: hidden !important;
background-color: transparent !important;
background: transparent !important;
}
/* Pin the toolbar at the top */
::deep .crepe .toolbar,
::deep .milkdown-menu,
::deep .crepe-menu-wrapper {
flex-shrink: 0 !important;
background-color: var(--bg-base) !important;
border: 1px solid var(--border) !important;
border-radius: 12px !important;
padding: 0.5rem !important;
margin-bottom: 1rem !important;
}
::deep .crepe .toolbar button:hover,
::deep .milkdown-menu button:hover,
::deep .crepe-menu-wrapper button:hover,
::deep .crepe .toolbar .button:hover,
::deep .milkdown-menu .button:hover {
color: var(--accent) !important;
background-color: rgba(16, 185, 129, 0.1) !important;
border-radius: var(--radius-sm, 4px) !important;
}
/* Relocate scrolling directly to ProseMirror editor layer and fix text clipping */
::deep .ProseMirror, ::deep .ProseMirror,
::deep .crepe .editor, ::deep .crepe .editor,
::deep .milkdown .editor { ::deep .milkdown .editor {
position: relative !important; position: relative !important;
top: 0 !important; top: 0 !important;
transform: none !important; transform: none !important;
padding: 2rem !important; flex-grow: 1 !important;
overflow-y: auto !important;
padding: 1.5rem !important;
padding-right: 15px !important;
background-color: var(--bg-surface) !important; background-color: var(--bg-surface) !important;
color: var(--text-main) !important; color: var(--text-main) !important;
font-size: 1.1rem !important; font-size: 1.1rem !important;
line-height: 1.7 !important; line-height: 1.7 !important;
outline: none !important; outline: none !important;
width: 100% !important;
max-width: 100% !important;
} }
/* Base Editorial Typography flow inside the dynamic DOM */ /* Custom narrow scrollbar mapped to var(--border) */
::deep .crepe, ::deep .ProseMirror::-webkit-scrollbar,
::deep .milkdown { ::deep .crepe .editor::-webkit-scrollbar,
background-color: var(--bg-surface) !important; ::deep .milkdown .editor::-webkit-scrollbar {
background: var(--bg-surface) !important; width: 6px;
color: var(--text-main) !important; height: 6px;
} }
::deep .ProseMirror::-webkit-scrollbar-track,
::deep .crepe .editor::-webkit-scrollbar-track,
::deep .milkdown .editor::-webkit-scrollbar-track {
background: transparent;
}
::deep .ProseMirror::-webkit-scrollbar-thumb,
::deep .crepe .editor::-webkit-scrollbar-thumb,
::deep .milkdown .editor::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 3px;
}
::deep .ProseMirror::-webkit-scrollbar-thumb:hover,
::deep .crepe .editor::-webkit-scrollbar-thumb:hover,
::deep .milkdown .editor::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* Editorial Typography */
::deep .milkdown .editor h1, ::deep .milkdown .editor h1,
::deep .crepe h1, ::deep .crepe h1,
::deep .ProseMirror h1 { ::deep .ProseMirror h1 {
margin-top: 1.8rem !important; margin-top: 1.8rem !important;
margin-bottom: 1rem !important; margin-bottom: 1rem !important;
font-size: 2.2rem !important; font-size: 2.25rem !important;
font-weight: 700 !important; font-weight: 700 !important;
color: var(--text-main) !important; color: var(--text-main) !important;
line-height: 1.25 !important; line-height: 1.25 !important;
@@ -104,35 +202,15 @@
font-size: 0.85em !important; font-size: 0.85em !important;
} }
/* Toolbar Styling Overrides */
::deep .crepe .toolbar,
::deep .milkdown-menu,
::deep .crepe-menu-wrapper {
background-color: var(--bg-base) !important;
border: 1px solid var(--border) !important;
border-radius: 12px !important;
padding: 0.5rem !important;
margin-bottom: 1rem !important;
}
::deep .crepe .toolbar button:hover,
::deep .milkdown-menu button:hover,
::deep .crepe-menu-wrapper button:hover,
::deep .crepe .toolbar .button:hover,
::deep .milkdown-menu .button:hover {
color: var(--accent) !important;
background-color: rgba(16, 185, 129, 0.1) !important;
border-radius: var(--radius-sm, 4px) !important;
}
/* Premium GFM Table Layouts */ /* Premium GFM Table Layouts */
::deep .milkdown-premium-container table, ::deep .milkdown-premium-container table,
::deep .crepe table, ::deep .crepe table,
::deep .milkdown table, ::deep .milkdown table,
::deep .ProseMirror table { ::deep .ProseMirror table {
width: 100% !important; width: 100% !important;
max-width: 100% !important;
border-collapse: collapse !important; border-collapse: collapse !important;
margin: 2rem 0 !important; margin: 1.5rem 0 !important;
} }
::deep .milkdown-premium-container th, ::deep .milkdown-premium-container th,
@@ -190,31 +268,42 @@
line-height: 1.7 !important; line-height: 1.7 !important;
} }
/* 3. Bottom Actions Panel styling */ /* 4. Bottom Actions Panel locked at floor zone of the card structure */
.creator-actions-bar { .creator-actions-bar {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-top: 1.5rem;
padding: 1rem 0 0 0; padding: 1rem 0 0 0;
margin-top: 1rem;
border-top: 1px solid var(--border); border-top: 1px solid var(--border);
flex-shrink: 0;
width: 100%;
} }
.premium-fetch-btn { .btn-nexus-premium {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1); transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
background: var(--accent); background-color: var(--accent) !important;
color: #000000; background: var(--accent) !important;
color: #000000 !important;
border: none;
border-radius: var(--radius-md);
padding: 8px 16px;
font-weight: 600;
cursor: pointer;
font-family: var(--nexus-font-sans);
font-size: 0.9rem;
min-height: 36px;
} }
.premium-fetch-btn:hover { .btn-nexus-premium:hover {
transform: translateY(-2px); transform: translateY(-2px);
filter: brightness(1.1); filter: brightness(1.1);
box-shadow: 0 4px 15px var(--accent-glow); box-shadow: 0 4px 15px var(--accent-glow);
} }
.premium-fetch-btn:hover .arrow-icon { .btn-nexus-premium:hover .arrow-icon {
transform: translateX(4px); transform: translateX(4px);
} }
@@ -222,28 +311,31 @@
transition: transform 0.2s ease; transition: transform 0.2s ease;
} }
/* 4. Dedicated Preview Module */ /* 5. Dedicated Preview Card */
.creator-preview-card { .creator-preview-card {
background: #121214; background: #121214;
border: 1px solid rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: var(--radius-lg); border-radius: var(--radius-lg);
padding: 1.5rem; padding: 1.25rem;
margin-top: 2rem; flex-shrink: 0;
max-height: 180px;
display: flex;
flex-direction: column;
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25); box-shadow: 0 8px 25px rgba(0, 0, 0, 0.25);
} }
.preview-header h3 { .preview-header h3 {
margin: 0 0 1rem 0; margin: 0 0 0.75rem 0;
font-size: 1.25rem; font-size: 1.1rem;
font-weight: 600; font-weight: 600;
color: #ffffff; color: #ffffff;
font-family: var(--nexus-font-sans); font-family: var(--nexus-font-sans);
} }
.pre-wrapper { .pre-wrapper {
max-height: 400px;
overflow-y: auto; overflow-y: auto;
overflow-x: auto; overflow-x: auto;
flex-grow: 1;
} }
.code-preview-block { .code-preview-block {
@@ -1,128 +0,0 @@
@page "/dev/creator-test"
@using Microsoft.AspNetCore.Authorization
@attribute [AllowAnonymous]
@inject HttpClient Http
<PageTitle>Markdown Creator Test</PageTitle>
<div class="creator-test-container glass-panel">
<div class="test-header">
<h1>Milkdown WYSIWYG Integration (Stage 2)</h1>
<p class="subtitle">Verifying secure image upload (drag &amp; drop / paste) and backend XSS sanitization.</p>
</div>
<div class="editor-section" spellcheck="false">
<MarkdownEditor InitialMarkdown="@_initialMarkdown" OnSave="HandleSave" Height="400px" />
</div>
<div class="result-section">
<div class="result-header">
<h3>Retrieved Markdown Content</h3>
@if (!string.IsNullOrEmpty(_savedMarkdown))
{
<button type="button" @onclick="SanitizeContentAsync" class="nexus-btn secondary-btn">
Run XSS Guard Sanitization
</button>
}
</div>
<p class="description">This block shows the content received from the editor when you click "Fetch Markdown Content".</p>
<div class="pre-wrapper">
@if (string.IsNullOrEmpty(_savedMarkdown))
{
<span class="placeholder">No content fetched yet. Click "Fetch Markdown Content" above to retrieve data.</span>
}
else
{
<pre><code>@_savedMarkdown</code></pre>
}
</div>
@if (!string.IsNullOrEmpty(_sanitizedMarkdown))
{
<div class="sanitized-container">
<h3>Sanitized Content (XSS Shielded)</h3>
<p class="description">This block shows the content after passing through the backend `HtmlSanitizer` API.</p>
<div class="pre-wrapper sanitized-wrapper">
<pre><code>@_sanitizedMarkdown</code></pre>
</div>
</div>
}
</div>
</div>
@code {
private readonly string _initialMarkdown = @"# Milkdown WYSIWYG Test Page (Stage 2)
This is a demonstration of the **Milkdown** editor embedded inside a Blazor WASM component.
## Secure Image Upload (Drag & Drop / Paste)
You can drag and drop or copy-paste an image (JPEG, PNG, WEBP) directly into this editor area. The file will be intercepted, sent as a byte stream to the backend `/api/media/upload` endpoint, validated for magic numbers and file size limits (max 5MB), saved locally, and rendered inside the editor.
## XSS Security Test
Here is some malicious HTML to test the backend XSS Guard:
<script>alert('xss')</script>
<img src=x onerror=alert(1)>
## GFM Features Support
The editor supports Github Flavored Markdown out-of-the-box:
1. **Task Lists**
- [x] Create reusable Blazor component
- [x] Configure ESM dynamic wrapper
- [x] Implement stage 2 features
2. **Tables**
| Feature | Stage 1 Status | Stage 2 Plan |
| :--- | :---: | :---: |
| WYSIWYG Mode | Active | Polish UI |
| C# Interop | Done | Auto-Sync |
| GFM Support | Verified | Custom Nodes |
Feel free to edit this text and click **Fetch Markdown Content** below!";
private string _savedMarkdown = string.Empty;
private string _sanitizedMarkdown = string.Empty;
private void HandleSave(string markdown)
{
_savedMarkdown = markdown;
_sanitizedMarkdown = string.Empty; // Reset sanitization result
StateHasChanged();
}
private async Task SanitizeContentAsync()
{
if (string.IsNullOrEmpty(_savedMarkdown)) return;
try
{
var request = new NexusReader.Application.DTOs.Media.ValidateChapterRequest(_savedMarkdown);
var response = await Http.PostAsJsonAsync(
"/api/chapters/validate",
request,
NexusReader.Application.Common.AppJsonContext.Default.ValidateChapterRequest
);
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadFromJsonAsync<NexusReader.Application.DTOs.Media.ValidateChapterResponse>(
NexusReader.Application.Common.AppJsonContext.Default.ValidateChapterResponse
);
_sanitizedMarkdown = result?.SanitizedContent ?? string.Empty;
}
else
{
_sanitizedMarkdown = $"Error: {response.StatusCode}";
}
}
catch (Exception ex)
{
_sanitizedMarkdown = $"Exception: {ex.Message}";
}
StateHasChanged();
}
}
@@ -1,257 +0,0 @@
/* ==========================================================================
CreatorTest.razor.css - Isolated Styles for WYSIWYG Text Editor Test
========================================================================== */
/* 1. BOUNDARY & SCROLLING RE-ENGINEERING */
/* Stable height boundary and scrolling behavior on the editor wrapper */
::deep .milkdown-editor-wrapper {
min-height: 350px !important;
max-height: 600px !important;
overflow-y: auto !important;
background-color: var(--bg-base) !important;
border: 1px solid var(--border) !important;
border-radius: var(--radius-md) !important;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
::deep .milkdown-editor-wrapper:focus-within {
border-color: var(--accent) !important;
box-shadow: 0 0 0 1px var(--accent-glow) !important;
}
/* Fix Top Text Clipping on the ProseMirror editable surface */
::deep .ProseMirror,
::deep .crepe .editor,
::deep .milkdown .editor {
position: relative !important;
top: 0 !important;
transform: none !important;
padding: 1.5rem !important;
background-color: var(--bg-base) !important;
color: var(--text-main) !important;
outline: none !important;
}
/* Encapsulate Milkdown editor wrapper & ProseMirror container */
::deep .crepe,
::deep .milkdown {
background-color: var(--bg-base) !important;
background: var(--bg-base) !important;
color: var(--text-main) !important;
}
/* Headings and inline typography styles */
::deep .milkdown .editor h1,
::deep .crepe h1,
::deep .ProseMirror h1 {
margin-top: 1.5rem !important;
margin-bottom: 1rem !important;
font-size: 2rem !important;
font-weight: 700 !important;
color: var(--text-main) !important;
line-height: 1.25 !important;
}
::deep .milkdown .editor h2,
::deep .crepe h2,
::deep .ProseMirror h2 {
margin-top: 1.25rem !important;
margin-bottom: 0.75rem !important;
font-size: 1.5rem !important;
font-weight: 600 !important;
color: var(--text-main) !important;
line-height: 1.3 !important;
}
::deep .milkdown .editor code,
::deep .crepe code,
::deep .ProseMirror code {
background-color: rgba(16, 185, 129, 0.1) !important;
color: var(--accent) !important;
padding: 0.2rem 0.4rem !important;
border-radius: var(--radius-sm, 4px) !important;
font-family: 'Azeret Mono', monospace !important;
font-size: 0.85em !important;
}
/* 2. HIGH-FIDELITY GFM TABLE FORMATTING */
::deep .crepe table,
::deep .milkdown table,
::deep .ProseMirror table {
width: 100% !important;
border-collapse: separate !important;
border-spacing: 0 !important;
margin: 1.5rem 0 !important;
border-radius: 8px !important;
overflow: hidden !important;
border: 1px solid var(--border) !important;
background-color: rgba(255, 255, 255, 0.01) !important;
}
::deep .crepe th,
::deep .milkdown th,
::deep .ProseMirror th {
background-color: rgba(255, 255, 255, 0.02) !important;
font-weight: 600 !important;
color: var(--text-main) !important;
padding: 10px 14px !important;
border-bottom: 2px solid var(--border) !important;
text-align: left !important;
}
::deep .crepe td,
::deep .milkdown td,
::deep .ProseMirror td {
padding: 12px 14px !important;
color: var(--text-main) !important;
border-bottom: 1px solid rgba(255, 255, 255, 0.05) !important;
}
::deep .crepe tr:last-child td,
::deep .milkdown tr:last-child td,
::deep .ProseMirror tr:last-child td {
border-bottom: none !important;
}
::deep .crepe tr:hover,
::deep .milkdown tr:hover,
::deep .ProseMirror tr:hover {
background-color: rgba(16, 185, 129, 0.03) !important;
}
/* 3. ACCENT SCHEME UNIFICATION */
/* Line-height specifications for GFM lists & task lists */
::deep .crepe ul,
::deep .crepe ol,
::deep .milkdown ul,
::deep .milkdown ol,
::deep .ProseMirror ul,
::deep .ProseMirror ol {
line-height: 1.6 !important;
}
/* Bottom action toolbar extraction & styling */
::deep .editor-actions {
display: flex !important;
justify-content: flex-end !important;
padding: 1rem 0 0 0 !important;
margin-top: 1rem !important;
border-top: 1px solid var(--border) !important;
}
/* ==========================================================================
Page Layout & Output Panel Styles
========================================================================== */
.creator-test-container {
max-width: 1000px;
margin: 2rem auto;
padding: 2rem;
display: flex;
flex-direction: column;
gap: 1.5rem;
}
.test-header h1 {
font-size: 1.75rem;
color: var(--text-main);
margin: 0 0 0.5rem 0;
}
.test-header .subtitle {
font-size: 0.95rem;
color: var(--text-muted);
margin: 0;
}
.editor-section {
background: var(--bg-surface);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 1.5rem;
overflow: hidden;
}
.result-section {
display: flex;
flex-direction: column;
gap: 0.5rem;
background: rgba(255, 255, 255, 0.02);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 1.5rem;
}
.result-header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
margin-bottom: 0.5rem;
}
.result-section h3 {
margin: 0;
font-size: 1.2rem;
color: var(--text-main);
}
.sanitized-container {
margin-top: 1.5rem;
display: flex;
flex-direction: column;
gap: 0.5rem;
border-top: 1px dashed var(--border);
padding-top: 1.5rem;
}
.sanitized-wrapper {
border-color: rgba(0, 255, 153, 0.25);
box-shadow: 0 0 10px rgba(0, 255, 153, 0.05);
}
.nexus-btn.secondary-btn {
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
color: #ffffff;
}
.nexus-btn.secondary-btn:hover {
background: rgba(255, 255, 255, 0.1);
box-shadow: 0 4px 15px rgba(255, 255, 255, 0.05);
}
.result-section .description {
font-size: 0.85rem;
color: var(--text-muted);
margin: 0 0 0.5rem 0;
}
.pre-wrapper {
background: #121214;
border: 1px solid rgba(255, 255, 255, 0.08);
border-radius: var(--radius-md);
padding: 1.2rem;
max-height: 300px;
overflow-y: auto;
overflow-x: auto;
}
.pre-wrapper pre {
margin: 0;
white-space: pre-wrap;
word-break: break-all;
font-family: 'Azeret Mono', SFMono-Regular, Consolas, Menlo, monospace;
font-size: 0.85rem;
color: #e4e4e7;
line-height: 1.6;
}
.placeholder {
color: var(--text-muted);
font-size: 0.9rem;
font-style: italic;
}
+549 -3
View File
@@ -60,9 +60,12 @@
--nexus-node-concept-text: #e0e0e0; --nexus-node-concept-text: #e0e0e0;
} }
::selection { ::selection,
background-color: var(--nexus-selection); .ProseMirror ::selection,
color: inherit; .ProseMirror::selection,
.ProseMirror *::selection {
background-color: var(--nexus-selection) !important;
color: inherit !important;
} }
@@ -445,3 +448,546 @@ h1:focus {
transform: scale(0.95); transform: scale(0.95);
} }
} }
/* ==========================================================================
Selection Pop-up Menu & Crepe Toolbar Unification (SelectionAiPanel Style)
========================================================================== */
/* 1. Pop-up Containers (Glassmorphism Capsule) */
.milkdown-popover,
.popover,
.prosemirror-bubble-menu,
.milkdown .popover,
.milkdown-popover.popover,
.milkdown-toolbar {
background: rgba(24, 24, 28, 0.85) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
border-radius: 8px !important;
padding: 4px 6px !important;
margin: 0 !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4) !important;
display: inline-flex; /* Removed !important to allow Tippy.js to hide popovers via inline style */
align-items: center !important;
gap: 4px !important;
z-index: 10000 !important;
box-sizing: border-box !important;
animation: fadeInScaleGlobal 0.18s cubic-bezier(0.16, 1, 0.3, 1) !important;
}
/* Light Theme (Warm Paper) Overrides for Container */
.theme-light .milkdown-popover,
.theme-light .popover,
.theme-light .prosemirror-bubble-menu,
.theme-light .milkdown .popover,
.theme-light .milkdown-popover.popover,
.theme-light .milkdown-toolbar {
background: rgba(254, 254, 254, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.08) !important;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04) !important;
}
/* 2. Button & Item Formatting (Reader Selection Toolbar Style) */
.milkdown-popover button,
.popover button,
.prosemirror-bubble-menu button,
.milkdown .popover button,
.milkdown-toolbar button {
text-transform: none !important;
font-size: 0.8rem !important;
font-weight: 500 !important;
color: #e4e4e7 !important; /* zinc-200 */
background: transparent !important;
border: none !important;
padding: 6px 12px !important;
margin: 0 !important;
border-radius: 6px !important;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
display: inline-flex !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer !important;
gap: 6px !important;
}
/* Crepe's Specific Square Icon-Only Toolbar Items */
.milkdown-toolbar .toolbar-item {
text-transform: none !important;
color: #e4e4e7 !important; /* zinc-200 */
background: transparent !important;
border: none !important;
margin: 0 !important;
border-radius: 6px !important;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
cursor: pointer !important;
width: 28px !important;
height: 28px !important;
padding: 6px !important;
display: inline-flex !important;
justify-content: center !important;
align-items: center !important;
box-sizing: border-box !important;
}
/* Icon overrides inside buttons */
.milkdown-popover button svg,
.popover button svg,
.prosemirror-bubble-menu button svg,
.milkdown .popover button svg,
.milkdown-popover button i,
.popover button i,
.prosemirror-bubble-menu button i,
.milkdown .popover button i,
.milkdown-toolbar button svg,
.milkdown-toolbar .toolbar-item svg,
.milkdown-toolbar button i,
.milkdown-toolbar .toolbar-item i {
color: currentColor !important;
fill: currentColor !important;
width: 14px !important;
height: 14px !important;
}
/* Hover effects (zinc-200 / zinc-100 highlight) */
.milkdown-popover button:hover:not(.active),
.popover button:hover:not(.active),
.prosemirror-bubble-menu button:hover:not(.active),
.milkdown-toolbar button:hover:not(.active),
.milkdown-toolbar .toolbar-item:hover:not(.active) {
background: rgba(255, 255, 255, 0.05) !important;
color: #ffffff !important;
}
/* Active formatting state colors (var(--accent, #00ff99)) */
.milkdown-popover button.active,
.popover button.active,
.prosemirror-bubble-menu button.active,
.milkdown-popover button[aria-pressed="true"],
.popover button[aria-pressed="true"],
.prosemirror-bubble-menu button[aria-pressed="true"],
.milkdown-toolbar button.active,
.milkdown-toolbar .toolbar-item.active,
.milkdown-toolbar button[aria-pressed="true"],
.milkdown-toolbar .toolbar-item[aria-pressed="true"] {
color: var(--accent, #00ff99) !important;
}
.milkdown-popover button.active:hover,
.popover button.active:hover,
.prosemirror-bubble-menu button.active:hover,
.milkdown-popover button[aria-pressed="true"]:hover,
.popover button[aria-pressed="true"]:hover,
.prosemirror-bubble-menu button[aria-pressed="true"]:hover,
.milkdown-toolbar button.active:hover,
.milkdown-toolbar .toolbar-item.active:hover,
.milkdown-toolbar button[aria-pressed="true"]:hover,
.milkdown-toolbar .toolbar-item[aria-pressed="true"]:hover {
background: rgba(0, 255, 153, 0.08) !important;
box-shadow: 0 0 12px rgba(0, 255, 153, 0.15) !important;
color: var(--accent, #00ff99) !important;
}
/* 3. Light Theme Overrides for Buttons */
.theme-light .milkdown-popover button,
.theme-light .popover button,
.theme-light .prosemirror-bubble-menu button,
.theme-light .milkdown-toolbar button,
.theme-light .milkdown-toolbar .toolbar-item {
color: #57524e !important;
}
.theme-light .milkdown-popover button:hover:not(.active),
.theme-light .popover button:hover:not(.active),
.theme-light .prosemirror-bubble-menu button:hover:not(.active),
.theme-light .milkdown-toolbar button:hover:not(.active),
.theme-light .milkdown-toolbar .toolbar-item:hover:not(.active) {
background: rgba(0, 0, 0, 0.04) !important;
color: #1c1917 !important;
}
.theme-light .milkdown-popover button.active,
.theme-light .popover button.active,
.theme-light .prosemirror-bubble-menu button.active,
.theme-light .milkdown-popover button[aria-pressed="true"],
.theme-light .popover button[aria-pressed="true"],
.theme-light .prosemirror-bubble-menu button[aria-pressed="true"],
.theme-light .milkdown-toolbar button.active,
.theme-light .milkdown-toolbar .toolbar-item.active,
.theme-light .milkdown-toolbar button[aria-pressed="true"],
.theme-light .milkdown-toolbar .toolbar-item[aria-pressed="true"] {
color: #10b981 !important;
}
.theme-light .milkdown-popover button.active:hover,
.theme-light .popover button.active:hover,
.theme-light .prosemirror-bubble-menu button.active:hover,
.theme-light .milkdown-popover button[aria-pressed="true"]:hover,
.theme-light .popover button[aria-pressed="true"]:hover,
.theme-light .prosemirror-bubble-menu button[aria-pressed="true"]:hover,
.theme-light .milkdown-toolbar button.active:hover,
.theme-light .milkdown-toolbar .toolbar-item.active:hover,
.theme-light .milkdown-toolbar button[aria-pressed="true"]:hover,
.theme-light .milkdown-toolbar .toolbar-item[aria-pressed="true"]:hover {
background: rgba(16, 185, 129, 0.06) !important;
box-shadow: 0 0 12px rgba(16, 185, 129, 0.1) !important;
color: #10b981 !important;
}
/* 4. Dividers Alignment */
.milkdown-popover .divider,
.popover .divider,
.prosemirror-bubble-menu .divider,
.milkdown .popover .divider,
.milkdown-toolbar .divider {
width: 1px !important;
height: 16px !important;
background-color: rgba(255, 255, 255, 0.1) !important;
margin: 0 4px !important;
border: none !important;
}
.theme-light .milkdown-popover .divider,
.theme-light .popover .divider,
.theme-light .prosemirror-bubble-menu .divider,
.theme-light .milkdown-toolbar .divider {
background-color: rgba(0, 0, 0, 0.08) !important;
}
to {
opacity: 1;
transform: scale(1);
}
}
/* ==========================================================================
Editor Table & General Control Elements Theming (SelectionAiPanel Style)
========================================================================== */
/* 1. Cell Drag Handles (Column and Row Drag Handles) */
.milkdown .milkdown-table-block .cell-handle {
background-color: rgba(24, 24, 28, 0.85) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
color: #e4e4e7 !important;
transition: all 0.2s ease !important;
}
.theme-light .milkdown .milkdown-table-block .cell-handle {
background-color: rgba(254, 254, 254, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.08) !important;
color: #57524e !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
}
.milkdown .milkdown-table-block .cell-handle:hover {
background-color: rgba(255, 255, 255, 0.15) !important;
color: #ffffff !important;
border-color: var(--accent) !important;
}
.theme-light .milkdown .milkdown-table-block .cell-handle:hover {
background-color: rgba(0, 0, 0, 0.08) !important;
color: #1c1917 !important;
border-color: #10b981 !important;
}
.milkdown .milkdown-table-block .cell-handle svg {
fill: currentColor !important;
color: currentColor !important;
}
/* 2. Drag Handle Options Popup Menu (.button-group) */
.milkdown .milkdown-table-block .cell-handle .button-group {
background: rgba(24, 24, 28, 0.85) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
border-radius: 8px !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4) !important;
padding: 4px !important;
gap: 4px !important;
display: flex; /* Removed !important to allow toggling via data-show attribute */
}
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group {
background: rgba(254, 254, 254, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.08) !important;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04) !important;
}
.milkdown .milkdown-table-block .cell-handle .button-group button {
background: transparent !important;
border: none !important;
margin: 0 !important;
border-radius: 6px !important;
transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1) !important;
cursor: pointer !important;
width: 28px !important;
height: 28px !important;
padding: 6px !important;
display: inline-flex !important;
justify-content: center !important;
align-items: center !important;
box-sizing: border-box !important;
color: #e4e4e7 !important;
}
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group button {
color: #57524e !important;
}
.milkdown .milkdown-table-block .cell-handle .button-group button:hover {
background: rgba(255, 255, 255, 0.05) !important;
color: #ffffff !important;
}
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group button:hover {
background: rgba(0, 0, 0, 0.04) !important;
color: #1c1917 !important;
}
.milkdown .milkdown-table-block .cell-handle .button-group button:active {
background: rgba(0, 255, 153, 0.08) !important;
color: var(--accent, #00ff99) !important;
}
.theme-light .milkdown .milkdown-table-block .cell-handle .button-group button:active {
background: rgba(16, 185, 129, 0.06) !important;
color: #10b981 !important;
}
.milkdown .milkdown-table-block .cell-handle .button-group button svg {
color: currentColor !important;
fill: currentColor !important;
width: 14px !important;
height: 14px !important;
}
/* 3. Table Column/Row Insertion Lines & Add Buttons */
.milkdown .milkdown-table-block .line-handle {
background-color: var(--accent) !important;
}
.theme-light .milkdown .milkdown-table-block .line-handle {
background-color: #10b981 !important;
}
.milkdown .milkdown-table-block .line-handle .add-button {
background-color: rgba(24, 24, 28, 0.85) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
color: #e4e4e7 !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
}
.theme-light .milkdown .milkdown-table-block .line-handle .add-button {
background-color: rgba(254, 254, 254, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.08) !important;
color: #57524e !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
}
.milkdown .milkdown-table-block .line-handle .add-button:hover {
background-color: rgba(255, 255, 255, 0.15) !important;
color: #ffffff !important;
border-color: var(--accent) !important;
}
.theme-light .milkdown .milkdown-table-block .line-handle .add-button:hover {
background-color: rgba(0, 0, 0, 0.08) !important;
color: #1c1917 !important;
border-color: #10b981 !important;
}
.milkdown .milkdown-table-block .line-handle .add-button svg {
width: 12px !important;
height: 12px !important;
color: currentColor !important;
fill: currentColor !important;
}
/* 4. Paragraph Block Drag Handles */
.milkdown .milkdown-block-handle {
background-color: rgba(24, 24, 28, 0.85) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
border-radius: 6px !important;
padding: 2px !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
display: flex; /* Removed !important to allow toggling */
gap: 2px !important;
}
.theme-light .milkdown .milkdown-block-handle {
background-color: rgba(254, 254, 254, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.08) !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05) !important;
}
.milkdown .milkdown-block-handle .operation-item {
border-radius: 4px !important;
width: 24px !important;
height: 24px !important;
padding: 4px !important;
display: inline-flex !important;
justify-content: center !important;
align-items: center !important;
color: #e4e4e7 !important;
transition: all 0.2s ease !important;
}
.theme-light .milkdown .milkdown-block-handle .operation-item {
color: #57524e !important;
}
.milkdown .milkdown-block-handle .operation-item:hover {
background: rgba(255, 255, 255, 0.05) !important;
color: #ffffff !important;
}
.theme-light .milkdown .milkdown-block-handle .operation-item:hover {
background: rgba(0, 0, 0, 0.04) !important;
color: #1c1917 !important;
}
.milkdown .milkdown-block-handle .operation-item.active {
background: rgba(0, 255, 153, 0.08) !important;
color: var(--accent, #00ff99) !important;
}
.theme-light .milkdown .milkdown-block-handle .operation-item.active {
background: rgba(16, 185, 129, 0.06) !important;
color: #10b981 !important;
}
.milkdown .milkdown-block-handle .operation-item svg {
width: 14px !important;
height: 14px !important;
fill: currentColor !important;
color: currentColor !important;
}
/* 5. Slash Commands Menu */
.milkdown .milkdown-slash-menu {
background: rgba(24, 24, 28, 0.85) !important;
backdrop-filter: blur(12px) !important;
-webkit-backdrop-filter: blur(12px) !important;
border: 1px solid rgba(255, 255, 255, 0.08) !important;
border-radius: 8px !important;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5), 0 12px 28px rgba(0, 0, 0, 0.4) !important;
font-family: var(--nexus-font-sans) !important;
color: #ffffff !important;
}
.theme-light .milkdown .milkdown-slash-menu {
background: rgba(254, 254, 254, 0.95) !important;
border: 1px solid rgba(0, 0, 0, 0.08) !important;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05), 0 10px 30px rgba(0, 0, 0, 0.04) !important;
color: #2d2a26 !important;
}
.milkdown .milkdown-slash-menu .tab-group ul li {
color: #a1a1aa !important;
border-radius: 6px !important;
transition: all 0.2s ease !important;
}
.theme-light .milkdown .milkdown-slash-menu .tab-group ul li {
color: #78716c !important;
}
.milkdown .milkdown-slash-menu .tab-group ul li:hover {
background: rgba(255, 255, 255, 0.05) !important;
color: #ffffff !important;
}
.theme-light .milkdown .milkdown-slash-menu .tab-group ul li:hover {
background: rgba(0, 0, 0, 0.04) !important;
color: #1c1917 !important;
}
.milkdown .milkdown-slash-menu .tab-group ul li.selected {
background: rgba(0, 255, 153, 0.08) !important;
color: var(--accent) !important;
}
.theme-light .milkdown .milkdown-slash-menu .tab-group ul li.selected {
background: rgba(16, 185, 129, 0.06) !important;
color: #10b981 !important;
}
.milkdown .milkdown-slash-menu .menu-groups .menu-group li {
color: #e4e4e7 !important;
border-radius: 6px !important;
transition: all 0.2s ease !important;
}
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li {
color: #57524e !important;
}
.milkdown .milkdown-slash-menu .menu-groups .menu-group li svg {
color: #a1a1aa !important;
fill: #a1a1aa !important;
}
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li svg {
color: #78716c !important;
fill: #78716c !important;
}
.milkdown .milkdown-slash-menu .menu-groups .menu-group li.hover {
background: rgba(255, 255, 255, 0.05) !important;
color: #ffffff !important;
}
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li.hover {
background: rgba(0, 0, 0, 0.04) !important;
color: #1c1917 !important;
}
.milkdown .milkdown-slash-menu .menu-groups .menu-group li.active {
background: rgba(0, 255, 153, 0.08) !important;
color: var(--accent) !important;
}
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li.active {
background: rgba(16, 185, 129, 0.06) !important;
color: #10b981 !important;
}
.milkdown .milkdown-slash-menu .menu-groups .menu-group li.active svg {
color: var(--accent) !important;
fill: var(--accent) !important;
}
.theme-light .milkdown .milkdown-slash-menu .menu-groups .menu-group li.active svg {
color: #10b981 !important;
fill: #10b981 !important;
}
/* 6. Explicit Visibility State Overrides */
.milkdown-popover[data-show="false"],
.popover[data-show="false"],
.prosemirror-bubble-menu[data-show="false"],
.milkdown-toolbar[data-show="false"],
.milkdown-slash-menu[data-show="false"],
.milkdown-table-block .cell-handle .button-group[data-show="false"],
.milkdown-link-preview[data-show="false"],
.milkdown-link-edit[data-show="false"] {
display: none !important;
opacity: 0 !important;
visibility: hidden !important;
pointer-events: none !important;
}
/* 7. Table Overflow Clipping Fix for Handles */
.milkdown .tableWrapper {
overflow: visible !important;
}