feat(wysiwyg): Add language selection for code blocks, block settings menu, fix cursor navigation, and update demo to use dees-panel

- Added modal to select programming language when creating code blocks
- Added settings button (3 dots) on each block for configuration
- Fixed cursor not jumping to new block after pressing Enter
- Special handling for code blocks: Enter creates new line, Shift+Enter creates new block
- Display language indicator on code blocks
- Updated demo to use dees-panel instead of demo-section divs
- Added language selection in block settings modal for existing code blocks
This commit is contained in:
Juergen Kunz
2025-06-23 21:28:58 +00:00
parent 302777feff
commit 7ce282c500
4 changed files with 284 additions and 59 deletions

View File

@ -301,35 +301,11 @@ export const demoFunc = () => html`
margin: 0 auto; margin: 0 auto;
} }
.demo-section { dees-panel {
background: #f8f9fa; margin-bottom: 32px;
border-radius: 12px;
padding: 32px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05);
} }
@media (prefers-color-scheme: dark) { dees-panel p {
.demo-section {
background: #1a1a1a;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
}
.demo-section h3 {
margin-top: 0;
margin-bottom: 20px;
color: #0066cc;
font-size: 20px;
font-weight: 600;
}
@media (prefers-color-scheme: dark) {
.demo-section h3 {
color: #4d94ff;
}
}
.demo-section p {
margin-top: 0; margin-top: 0;
margin-bottom: 24px; margin-bottom: 24px;
color: #666; color: #666;
@ -338,7 +314,7 @@ export const demoFunc = () => html`
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
.demo-section p { dees-panel p {
color: #999; color: #999;
} }
} }
@ -448,8 +424,7 @@ export const demoFunc = () => html`
</style> </style>
<div class="demo-container"> <div class="demo-container">
<div class="demo-section"> <dees-panel .heading=${'🚀 Modern WYSIWYG Editor'}>
<h3>🚀 Modern WYSIWYG Editor</h3>
<p>A powerful block-based editor with slash commands, keyboard shortcuts, and multiple output formats. Perfect for content creation, blog posts, documentation, and more.</p> <p>A powerful block-based editor with slash commands, keyboard shortcuts, and multiple output formats. Perfect for content creation, blog posts, documentation, and more.</p>
<div class="feature-list"> <div class="feature-list">
@ -521,10 +496,9 @@ export const demoFunc = () => html`
</div> </div>
</div> </div>
</div> </div>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'📝 Blog Post Example'}>
<h3>📝 Blog Post Example</h3>
<p>Perfect for creating rich content with multiple block types. The editor preserves formatting and provides a clean editing experience.</p> <p>Perfect for creating rich content with multiple block types. The editor preserves formatting and provides a clean editing experience.</p>
<dees-input-wysiwyg <dees-input-wysiwyg
@ -533,10 +507,9 @@ export const demoFunc = () => html`
.value=${'<h1>Welcome to Our Blog</h1><p>This is an example blog post that demonstrates the capabilities of our WYSIWYG editor.</p><h2>Features Overview</h2><p>Our editor supports multiple block types including headings, paragraphs, quotes, and more.</p><blockquote>The best way to predict the future is to invent it.</blockquote><p>You can also create lists and code blocks for technical content.</p>'} .value=${'<h1>Welcome to Our Blog</h1><p>This is an example blog post that demonstrates the capabilities of our WYSIWYG editor.</p><h2>Features Overview</h2><p>Our editor supports multiple block types including headings, paragraphs, quotes, and more.</p><blockquote>The best way to predict the future is to invent it.</blockquote><p>You can also create lists and code blocks for technical content.</p>'}
.outputFormat=${'html'} .outputFormat=${'html'}
></dees-input-wysiwyg> ></dees-input-wysiwyg>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'🔀 Drag & Drop Reordering'}>
<h3>🔀 Drag & Drop Reordering</h3>
<p>Easily rearrange your content blocks by dragging them. Hover over any block to reveal the drag handle on the left side.</p> <p>Easily rearrange your content blocks by dragging them. Hover over any block to reveal the drag handle on the left side.</p>
<dees-input-wysiwyg <dees-input-wysiwyg
@ -555,10 +528,9 @@ export const demoFunc = () => html`
<li>The editor maintains focus on the moved block after dropping</li> <li>The editor maintains focus on the moved block after dropping</li>
</ul> </ul>
</div> </div>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'📚 Tutorial & Documentation'}>
<h3>📚 Tutorial & Documentation</h3>
<p>Create comprehensive tutorials and documentation with code examples, lists, and structured content.</p> <p>Create comprehensive tutorials and documentation with code examples, lists, and structured content.</p>
<dees-input-wysiwyg <dees-input-wysiwyg
@ -567,10 +539,9 @@ export const demoFunc = () => html`
.outputFormat=${'markdown'} .outputFormat=${'markdown'}
.value=${'# Git Tutorial for Beginners\n\nGit is a distributed version control system that helps you track changes in your code over time. This tutorial will guide you through the basics.\n\n## Prerequisites\n\nBefore starting, ensure you have:\n\n- Git installed on your system\n- A text editor or IDE\n- Basic command line knowledge\n\n## Getting Started\n\n### 1. Configure Git\n\nFirst, set up your identity:\n\n```bash\ngit config --global user.name "Your Name"\ngit config --global user.email "your.email@example.com"\n```\n\n### 2. Initialize a Repository\n\nCreate a new Git repository:\n\n```bash\nmkdir my-project\ncd my-project\ngit init\n```\n\n### 3. Basic Git Workflow\n\n#### Adding Files\n\nCreate a file and add it to staging:\n\n```bash\necho "# My Project" > README.md\ngit add README.md\n```\n\n#### Committing Changes\n\n```bash\ngit commit -m "Initial commit"\n```\n\n> **Best Practice:** Write clear, descriptive commit messages that explain what changes were made and why.\n\n### 4. Working with Branches\n\nBranches allow you to work on features independently:\n\n```bash\n# Create and switch to a new branch\ngit checkout -b feature-branch\n\n# Make changes and commit\ngit add .\ngit commit -m "Add new feature"\n\n# Switch back to main\ngit checkout main\n\n# Merge the feature\ngit merge feature-branch\n```\n\n---\n\n## Common Commands Reference\n\n| Command | Description |\n|---------|-------------|\n| `git status` | Check repository status |\n| `git log` | View commit history |\n| `git diff` | Show changes |\n| `git pull` | Fetch and merge changes |\n| `git push` | Upload changes to remote |\n\n## Next Steps\n\n1. Learn about remote repositories\n2. Explore advanced Git features\n3. Practice with real projects\n4. Contribute to open source\n\n**Happy coding!** 🚀'} .value=${'# Git Tutorial for Beginners\n\nGit is a distributed version control system that helps you track changes in your code over time. This tutorial will guide you through the basics.\n\n## Prerequisites\n\nBefore starting, ensure you have:\n\n- Git installed on your system\n- A text editor or IDE\n- Basic command line knowledge\n\n## Getting Started\n\n### 1. Configure Git\n\nFirst, set up your identity:\n\n```bash\ngit config --global user.name "Your Name"\ngit config --global user.email "your.email@example.com"\n```\n\n### 2. Initialize a Repository\n\nCreate a new Git repository:\n\n```bash\nmkdir my-project\ncd my-project\ngit init\n```\n\n### 3. Basic Git Workflow\n\n#### Adding Files\n\nCreate a file and add it to staging:\n\n```bash\necho "# My Project" > README.md\ngit add README.md\n```\n\n#### Committing Changes\n\n```bash\ngit commit -m "Initial commit"\n```\n\n> **Best Practice:** Write clear, descriptive commit messages that explain what changes were made and why.\n\n### 4. Working with Branches\n\nBranches allow you to work on features independently:\n\n```bash\n# Create and switch to a new branch\ngit checkout -b feature-branch\n\n# Make changes and commit\ngit add .\ngit commit -m "Add new feature"\n\n# Switch back to main\ngit checkout main\n\n# Merge the feature\ngit merge feature-branch\n```\n\n---\n\n## Common Commands Reference\n\n| Command | Description |\n|---------|-------------|\n| `git status` | Check repository status |\n| `git log` | View commit history |\n| `git diff` | Show changes |\n| `git pull` | Fetch and merge changes |\n| `git push` | Upload changes to remote |\n\n## Next Steps\n\n1. Learn about remote repositories\n2. Explore advanced Git features\n3. Practice with real projects\n4. Contribute to open source\n\n**Happy coding!** 🚀'}
></dees-input-wysiwyg> ></dees-input-wysiwyg>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'🔄 Output Formats'}>
<h3>🔄 Output Formats</h3>
<p>Choose between HTML and Markdown output formats depending on your needs. Perfect for static site generators, documentation systems, or any content management workflow.</p> <p>Choose between HTML and Markdown output formats depending on your needs. Perfect for static site generators, documentation systems, or any content management workflow.</p>
<div class="output-section"> <div class="output-section">
@ -579,7 +550,7 @@ export const demoFunc = () => html`
.label=${'Meeting Notes'} .label=${'Meeting Notes'}
.description=${'Structured meeting documentation'} .description=${'Structured meeting documentation'}
.outputFormat=${'html'} .outputFormat=${'html'}
.value=${'<h2>Q4 Planning Meeting</h2><p><strong>Date:</strong> December 15, 2024<br><strong>Attendees:</strong> Product Team, Engineering, Design</p><h3>Agenda Items</h3><ol><li>Review Q3 achievements</li><li>Set Q4 objectives</li><li>Resource allocation</li><li>Timeline discussion</li></ol><h3>Key Decisions</h3><ul><li>Launch new dashboard feature by end of January</li><li>Increase engineering team by 2 developers</li><li>Implement weekly design reviews</li></ul><blockquote>"Focus on user experience improvements based on Q3 feedback" - Product Manager</blockquote><h3>Action Items</h3><ul><li>Sarah: Create detailed project timeline</li><li>Mike: Draft technical requirements</li><li>Lisa: Schedule user research sessions</li></ul><hr><p>Next meeting: January 5, 2025</p>'} .value=${'<h2>Q4 Planning Meeting</h2><p><strong>Date:</strong> December 15, 2024<br><strong>Attendees:</strong> Product Team, Engineering, Design</p><h3>Agenda Items'}><ol><li>Review Q3 achievements</li><li>Set Q4 objectives</li><li>Resource allocation</li><li>Timeline discussion</li></ol><h3>Key Decisions'}><ul><li>Launch new dashboard feature by end of January</li><li>Increase engineering team by 2 developers</li><li>Implement weekly design reviews</li></ul><blockquote>"Focus on user experience improvements based on Q3 feedback" - Product Manager</blockquote><h3>Action Items'}><ul><li>Sarah: Create detailed project timeline</li><li>Mike: Draft technical requirements</li><li>Lisa: Schedule user research sessions</li></ul><hr><p>Next meeting: January 5, 2025</p>'}
></dees-input-wysiwyg> ></dees-input-wysiwyg>
</div> </div>
@ -592,22 +563,20 @@ export const demoFunc = () => html`
></dees-input-wysiwyg> ></dees-input-wysiwyg>
</div> </div>
</div> </div>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'🎨 Advanced Editing'}>
<h3>🎨 Advanced Editing</h3>
<p>Create complex documents with mixed content types. The editor handles all formatting seamlessly.</p> <p>Create complex documents with mixed content types. The editor handles all formatting seamlessly.</p>
<dees-input-wysiwyg <dees-input-wysiwyg
.label=${'Technical Documentation'} .label=${'Technical Documentation'}
.description=${'Create technical docs with code examples and structured content'} .description=${'Create technical docs with code examples and structured content'}
.value=${'<h1>API Documentation</h1><p>Welcome to our API documentation. Below you\'ll find examples of how to use our endpoints.</p><h2>Authentication</h2><p>All API requests require authentication using an API key:</p><pre><code>Authorization: Bearer YOUR_API_KEY</code></pre><h2>Endpoints</h2><h3>GET /users</h3><p>Retrieve a list of users from the system.</p><pre><code>curl -X GET https://api.example.com/users \\\n -H "Authorization: Bearer YOUR_API_KEY"</code></pre><blockquote>Note: Rate limiting applies to all endpoints. You can make up to 100 requests per minute.</blockquote><h3>POST /users</h3><p>Create a new user in the system.</p><pre><code>{\n "name": "John Doe",\n "email": "john@example.com",\n "role": "user"\n}</code></pre><hr><p>For more information, please refer to our complete documentation.</p>'} .value=${'<h1>API Documentation</h1><p>Welcome to our API documentation. Below you\'ll find examples of how to use our endpoints.</p><h2>Authentication</h2><p>All API requests require authentication using an API key:</p><pre><code>Authorization: Bearer YOUR_API_KEY</code></pre><h2>Endpoints</h2><h3>GET /users'}><p>Retrieve a list of users from the system.</p><pre><code>curl -X GET https://api.example.com/users \\\n -H "Authorization: Bearer YOUR_API_KEY"</code></pre><blockquote>Note: Rate limiting applies to all endpoints. You can make up to 100 requests per minute.</blockquote><h3>POST /users'}><p>Create a new user in the system.</p><pre><code>{\n "name": "John Doe",\n "email": "john@example.com",\n "role": "user"\n}</code></pre><hr><p>For more information, please refer to our complete documentation.</p>'}
.outputFormat=${'html'} .outputFormat=${'html'}
></dees-input-wysiwyg> ></dees-input-wysiwyg>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'⚙️ Form Integration'}>
<h3>⚙️ Form Integration</h3>
<p>Seamlessly integrates with dees-form for complete form solutions. All standard form features like validation, required fields, and data binding work out of the box.</p> <p>Seamlessly integrates with dees-form for complete form solutions. All standard form features like validation, required fields, and data binding work out of the box.</p>
<dees-form> <dees-form>
@ -631,10 +600,9 @@ export const demoFunc = () => html`
.tags=${['web-development', 'javascript', 'tutorial']} .tags=${['web-development', 'javascript', 'tutorial']}
></dees-input-tags> ></dees-input-tags>
</dees-form> </dees-form>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'🧩 Programmatic Block Creation'}>
<h3>🧩 Programmatic Block Creation</h3>
<p>Create content programmatically using the block API for dynamic document generation.</p> <p>Create content programmatically using the block API for dynamic document generation.</p>
<dees-input-wysiwyg <dees-input-wysiwyg
@ -659,10 +627,9 @@ export const demoFunc = () => html`
style="padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; background: #f8f8f8; cursor: pointer;" style="padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; background: #f8f8f8; cursor: pointer;"
>Clear Editor</button> >Clear Editor</button>
</div> </div>
</div> </dees-panel>
<div class="demo-section"> <dees-panel .heading=${'📤 Export/Import Features'}>
<h3>📤 Export/Import Features</h3>
<p>The WYSIWYG editor provides multiple export formats and lossless save/restore capabilities for maximum flexibility.</p> <p>The WYSIWYG editor provides multiple export formats and lossless save/restore capabilities for maximum flexibility.</p>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 24px;"> <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 16px; margin-bottom: 24px;">
@ -746,7 +713,7 @@ export const demoFunc = () => html`
}} }}
>Restore State</button> >Restore State</button>
</div> </div>
</div> </dees-panel>
</div> </div>
</dees-demowrapper> </dees-demowrapper>
`; `;

View File

@ -1,5 +1,6 @@
import { DeesInputBase } from '../dees-input-base.js'; import { DeesInputBase } from '../dees-input-base.js';
import { demoFunc } from '../dees-input-wysiwyg.demo.js'; import { demoFunc } from '../dees-input-wysiwyg.demo.js';
import { DeesModal } from '../dees-modal.js';
import { import {
customElement, customElement,
@ -204,6 +205,22 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
onCompositionEnd: () => this.isComposing = false, onCompositionEnd: () => this.isComposing = false,
onMouseUp: (e: MouseEvent) => this.handleTextSelection(e), onMouseUp: (e: MouseEvent) => this.handleTextSelection(e),
})} })}
${block.type !== 'divider' ? html`
<div
class="block-settings"
@click="${(e: MouseEvent) => {
e.preventDefault();
e.stopPropagation();
this.showBlockSettingsModal(block);
}}"
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
<circle cx="12" cy="5" r="2"></circle>
<circle cx="12" cy="12" r="2"></circle>
<circle cx="12" cy="19" r="2"></circle>
</svg>
</div>
` : ''}
</div> </div>
`; `;
} }
@ -315,6 +332,23 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
this.updateValue(); this.updateValue();
this.requestUpdate(); this.requestUpdate();
return; return;
} else if (detectedType.type === 'code') {
// For code blocks, ask for language
this.showLanguageSelectionModal().then(language => {
if (language) {
block.type = 'code';
block.content = '';
block.metadata = { language };
// Clear the DOM element immediately
target.textContent = '';
// Force update
this.updateValue();
this.requestUpdate();
}
});
return;
} else { } else {
// For all other block types // For all other block types
block.type = detectedType.type; block.type = detectedType.type;
@ -638,11 +672,22 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
} }
} }
private insertBlock(type: IBlock['type']) { private async insertBlock(type: IBlock['type']) {
const currentBlockIndex = this.blocks.findIndex(b => b.id === this.selectedBlockId); const currentBlockIndex = this.blocks.findIndex(b => b.id === this.selectedBlockId);
const currentBlock = this.blocks[currentBlockIndex]; const currentBlock = this.blocks[currentBlockIndex];
if (currentBlock && currentBlock.content.startsWith('/')) { if (currentBlock && currentBlock.content.startsWith('/')) {
// If it's a code block, ask for language
if (type === 'code') {
const language = await this.showLanguageSelectionModal();
if (!language) {
// User cancelled
this.closeSlashMenu();
return;
}
currentBlock.metadata = { language };
}
currentBlock.type = type; currentBlock.type = type;
currentBlock.content = ''; currentBlock.content = '';
@ -1027,4 +1072,142 @@ export class DeesInputWysiwyg extends DeesInputBase<string> {
} }
}, 10); }, 10);
} }
private async showLanguageSelectionModal(): Promise<string | null> {
return new Promise((resolve) => {
let selectedLanguage: string | null = null;
DeesModal.createAndShow({
heading: 'Select Programming Language',
content: html`
<style>
.language-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
padding: 16px;
}
.language-button {
padding: 12px;
background: var(--dees-color-box);
border: 1px solid var(--dees-color-line-bright);
border-radius: 4px;
cursor: pointer;
text-align: center;
transition: all 0.2s;
}
.language-button:hover {
background: var(--dees-color-box-highlight);
border-color: var(--dees-color-primary);
}
</style>
<div class="language-grid">
${['JavaScript', 'TypeScript', 'Python', 'Java', 'C++', 'C#', 'Go', 'Rust', 'HTML', 'CSS', 'SQL', 'Shell', 'JSON', 'YAML', 'Markdown', 'Plain Text'].map(lang => html`
<div class="language-button" @click="${(e: MouseEvent) => {
selectedLanguage = lang.toLowerCase();
// Find and click the hidden OK button to close the modal
const modal = (e.target as HTMLElement).closest('dees-modal');
if (modal) {
const okButton = modal.shadowRoot?.querySelector('.bottomButton.ok') as HTMLElement;
if (okButton) okButton.click();
}
}}">${lang}</div>
`)}
</div>
`,
menuOptions: [
{
name: 'Cancel',
action: async (modal) => {
modal.destroy();
resolve(null);
}
},
{
name: 'OK',
action: async (modal) => {
modal.destroy();
resolve(selectedLanguage);
}
}
]
});
});
}
private async showBlockSettingsModal(block: IBlock): Promise<void> {
let content: TemplateResult;
if (block.type === 'code') {
const currentLanguage = block.metadata?.language || 'plain text';
content = html`
<style>
.settings-section {
margin-bottom: 16px;
}
.settings-label {
font-weight: 500;
margin-bottom: 8px;
}
.language-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 8px;
}
.language-button {
padding: 8px;
background: var(--dees-color-box);
border: 1px solid var(--dees-color-line-bright);
border-radius: 4px;
cursor: pointer;
text-align: center;
transition: all 0.2s;
}
.language-button:hover {
background: var(--dees-color-box-highlight);
border-color: var(--dees-color-primary);
}
.language-button.selected {
background: var(--dees-color-primary);
color: white;
}
</style>
<div class="settings-section">
<div class="settings-label">Programming Language</div>
<div class="language-grid">
${['JavaScript', 'TypeScript', 'Python', 'Java', 'C++', 'C#', 'Go', 'Rust', 'HTML', 'CSS', 'SQL', 'Shell', 'JSON', 'YAML', 'Markdown', 'Plain Text'].map(lang => html`
<div class="language-button ${currentLanguage === lang.toLowerCase() ? 'selected' : ''}"
@click="${(e: MouseEvent) => {
if (!block.metadata) block.metadata = {};
block.metadata.language = lang.toLowerCase();
this.updateValue();
this.requestUpdate();
// Find and click the close button
const modal = (e.target as HTMLElement).closest('dees-modal');
if (modal) {
const closeButton = modal.shadowRoot?.querySelector('.bottomButton') as HTMLElement;
if (closeButton) closeButton.click();
}
}}">${lang}</div>
`)}
</div>
</div>
`;
} else {
content = html`<div style="padding: 16px;">No settings available for this block type.</div>`;
}
DeesModal.createAndShow({
heading: 'Block Settings',
content,
menuOptions: [
{
name: 'Close',
action: async (modal) => {
modal.destroy();
}
}
]
});
}
} }

View File

@ -55,6 +55,30 @@ export class WysiwygBlocks {
`; `;
} }
// Special rendering for code blocks with language indicator
if (block.type === 'code') {
const language = block.metadata?.language || 'plain text';
return html`
<div class="code-block-container">
<div class="code-language">${language}</div>
<div
class="block ${block.type} ${isSelected ? 'selected' : ''}"
contenteditable="true"
@input="${handlers.onInput}"
@keydown="${handlers.onKeyDown}"
@focus="${handlers.onFocus}"
@blur="${handlers.onBlur}"
@compositionstart="${handlers.onCompositionStart}"
@compositionend="${handlers.onCompositionEnd}"
@mouseup="${(e: MouseEvent) => {
console.log('Block mouseup event fired');
if (handlers.onMouseUp) handlers.onMouseUp(e);
}}"
></div>
</div>
`;
}
return html` return html`
<div <div
class="block ${block.type} ${isSelected ? 'selected' : ''}" class="block ${block.type} ${isSelected ? 'selected' : ''}"

View File

@ -153,16 +153,36 @@ export const wysiwygStyles = css`
font-style: italic; font-style: italic;
} }
.code-block-container {
position: relative;
margin: 20px 0;
}
.code-language {
position: absolute;
top: 0;
right: 0;
background: ${cssManager.bdTheme('#e1e4e8', '#333333')};
color: ${cssManager.bdTheme('#586069', '#8b949e')};
padding: 4px 12px;
font-size: 12px;
border-radius: 0 6px 0 6px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
text-transform: lowercase;
z-index: 1;
}
.block.code { .block.code {
background: ${cssManager.bdTheme('#f8f8f8', '#0d0d0d')}; background: ${cssManager.bdTheme('#f8f8f8', '#0d0d0d')};
border: 1px solid ${cssManager.bdTheme('#e0e0e0', '#2a2a2a')}; border: 1px solid ${cssManager.bdTheme('#e0e0e0', '#2a2a2a')};
border-radius: 6px; border-radius: 6px;
padding: 16px 20px; padding: 16px 20px;
padding-top: 32px; /* Make room for language indicator */
font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace; font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Fira Code', monospace;
font-size: 14px; font-size: 14px;
line-height: 1.5; line-height: 1.5;
white-space: pre-wrap; white-space: pre-wrap;
color: ${cssManager.bdTheme('#d14', '#ff6b6b')}; color: ${cssManager.bdTheme('#24292e', '#e1e4e8')};
overflow-x: auto; overflow-x: auto;
} }
@ -394,6 +414,37 @@ export const wysiwygStyles = css`
user-select: none; user-select: none;
} }
/* Block Settings Button */
.block-settings {
position: absolute;
right: -40px;
top: 50%;
transform: translateY(-50%);
width: 28px;
height: 28px;
cursor: pointer;
opacity: 0;
transition: opacity 0.2s ease;
display: flex;
align-items: center;
justify-content: center;
color: ${cssManager.bdTheme('#999', '#666')};
border-radius: 4px;
}
.block-wrapper:hover .block-settings {
opacity: 1;
}
.block-settings:hover {
color: ${cssManager.bdTheme('#666', '#999')};
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.05)', 'rgba(255, 255, 255, 0.05)')};
}
.block-settings:active {
background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')};
}
/* Text Selection Styles */ /* Text Selection Styles */
.block ::selection { .block ::selection {
background: ${cssManager.bdTheme('rgba(0, 102, 204, 0.3)', 'rgba(77, 148, 255, 0.3)')}; background: ${cssManager.bdTheme('rgba(0, 102, 204, 0.3)', 'rgba(77, 148, 255, 0.3)')};