diff --git a/ts_web/elements/dees-input-wysiwyg.demo.ts b/ts_web/elements/dees-input-wysiwyg.demo.ts index cdc84ca..2ad06d2 100644 --- a/ts_web/elements/dees-input-wysiwyg.demo.ts +++ b/ts_web/elements/dees-input-wysiwyg.demo.ts @@ -301,35 +301,11 @@ export const demoFunc = () => html` margin: 0 auto; } - .demo-section { - background: #f8f9fa; - border-radius: 12px; - padding: 32px; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + dees-panel { + margin-bottom: 32px; } - @media (prefers-color-scheme: dark) { - .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 { + dees-panel p { margin-top: 0; margin-bottom: 24px; color: #666; @@ -338,7 +314,7 @@ export const demoFunc = () => html` } @media (prefers-color-scheme: dark) { - .demo-section p { + dees-panel p { color: #999; } } @@ -448,8 +424,7 @@ export const demoFunc = () => html`
-
-

🚀 Modern WYSIWYG Editor

+

A powerful block-based editor with slash commands, keyboard shortcuts, and multiple output formats. Perfect for content creation, blog posts, documentation, and more.

@@ -521,10 +496,9 @@ export const demoFunc = () => html`
- + -
-

📝 Blog Post Example

+

Perfect for creating rich content with multiple block types. The editor preserves formatting and provides a clean editing experience.

html` .value=${'

Welcome to Our Blog

This is an example blog post that demonstrates the capabilities of our WYSIWYG editor.

Features Overview

Our editor supports multiple block types including headings, paragraphs, quotes, and more.

The best way to predict the future is to invent it.

You can also create lists and code blocks for technical content.

'} .outputFormat=${'html'} >
-
+ -
-

🔀 Drag & Drop Reordering

+

Easily rearrange your content blocks by dragging them. Hover over any block to reveal the drag handle on the left side.

html`
  • The editor maintains focus on the moved block after dropping
  • - + -
    -

    📚 Tutorial & Documentation

    +

    Create comprehensive tutorials and documentation with code examples, lists, and structured content.

    html` .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!** 🚀'} > -
    + -
    -

    🔄 Output Formats

    +

    Choose between HTML and Markdown output formats depending on your needs. Perfect for static site generators, documentation systems, or any content management workflow.

    @@ -579,7 +550,7 @@ export const demoFunc = () => html` .label=${'Meeting Notes'} .description=${'Structured meeting documentation'} .outputFormat=${'html'} - .value=${'

    Q4 Planning Meeting

    Date: December 15, 2024
    Attendees: Product Team, Engineering, Design

    Agenda Items

    1. Review Q3 achievements
    2. Set Q4 objectives
    3. Resource allocation
    4. Timeline discussion

    Key Decisions

    • Launch new dashboard feature by end of January
    • Increase engineering team by 2 developers
    • Implement weekly design reviews
    "Focus on user experience improvements based on Q3 feedback" - Product Manager

    Action Items

    • Sarah: Create detailed project timeline
    • Mike: Draft technical requirements
    • Lisa: Schedule user research sessions

    Next meeting: January 5, 2025

    '} + .value=${'

    Q4 Planning Meeting

    Date: December 15, 2024
    Attendees: Product Team, Engineering, Design

    Agenda Items'}>
    1. Review Q3 achievements
    2. Set Q4 objectives
    3. Resource allocation
    4. Timeline discussion

    Key Decisions'}>
    • Launch new dashboard feature by end of January
    • Increase engineering team by 2 developers
    • Implement weekly design reviews
    "Focus on user experience improvements based on Q3 feedback" - Product Manager

    Action Items'}>
    • Sarah: Create detailed project timeline
    • Mike: Draft technical requirements
    • Lisa: Schedule user research sessions

    Next meeting: January 5, 2025

    '} >

    @@ -592,22 +563,20 @@ export const demoFunc = () => html` >
    - + -
    -

    🎨 Advanced Editing

    +

    Create complex documents with mixed content types. The editor handles all formatting seamlessly.

    API Documentation

    Welcome to our API documentation. Below you\'ll find examples of how to use our endpoints.

    Authentication

    All API requests require authentication using an API key:

    Authorization: Bearer YOUR_API_KEY

    Endpoints

    GET /users

    Retrieve a list of users from the system.

    curl -X GET https://api.example.com/users \\\n  -H "Authorization: Bearer YOUR_API_KEY"
    Note: Rate limiting applies to all endpoints. You can make up to 100 requests per minute.

    POST /users

    Create a new user in the system.

    {\n  "name": "John Doe",\n  "email": "john@example.com",\n  "role": "user"\n}

    For more information, please refer to our complete documentation.

    '} + .value=${'

    API Documentation

    Welcome to our API documentation. Below you\'ll find examples of how to use our endpoints.

    Authentication

    All API requests require authentication using an API key:

    Authorization: Bearer YOUR_API_KEY

    Endpoints

    GET /users'}>

    Retrieve a list of users from the system.

    curl -X GET https://api.example.com/users \\\n  -H "Authorization: Bearer YOUR_API_KEY"
    Note: Rate limiting applies to all endpoints. You can make up to 100 requests per minute.

    POST /users'}>

    Create a new user in the system.

    {\n  "name": "John Doe",\n  "email": "john@example.com",\n  "role": "user"\n}

    For more information, please refer to our complete documentation.

    '} .outputFormat=${'html'} > -

    + -
    -

    ⚙️ Form Integration

    +

    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.

    @@ -631,10 +600,9 @@ export const demoFunc = () => html` .tags=${['web-development', 'javascript', 'tutorial']} > -
    + -
    -

    🧩 Programmatic Block Creation

    +

    Create content programmatically using the block API for dynamic document generation.

    html` style="padding: 8px 16px; border: 1px solid #ddd; border-radius: 4px; background: #f8f8f8; cursor: pointer;" >Clear Editor
    - + -
    -

    📤 Export/Import Features

    +

    The WYSIWYG editor provides multiple export formats and lossless save/restore capabilities for maximum flexibility.

    @@ -746,7 +713,7 @@ export const demoFunc = () => html` }} >Restore State
    -
    + `; \ No newline at end of file diff --git a/ts_web/elements/wysiwyg/dees-input-wysiwyg.ts b/ts_web/elements/wysiwyg/dees-input-wysiwyg.ts index 11cc30d..13b7e97 100644 --- a/ts_web/elements/wysiwyg/dees-input-wysiwyg.ts +++ b/ts_web/elements/wysiwyg/dees-input-wysiwyg.ts @@ -1,5 +1,6 @@ import { DeesInputBase } from '../dees-input-base.js'; import { demoFunc } from '../dees-input-wysiwyg.demo.js'; +import { DeesModal } from '../dees-modal.js'; import { customElement, @@ -204,6 +205,22 @@ export class DeesInputWysiwyg extends DeesInputBase { onCompositionEnd: () => this.isComposing = false, onMouseUp: (e: MouseEvent) => this.handleTextSelection(e), })} + ${block.type !== 'divider' ? html` +
    + + + + + +
    + ` : ''} `; } @@ -315,6 +332,23 @@ export class DeesInputWysiwyg extends DeesInputBase { this.updateValue(); this.requestUpdate(); 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 { // For all other block types block.type = detectedType.type; @@ -638,11 +672,22 @@ export class DeesInputWysiwyg extends DeesInputBase { } } - private insertBlock(type: IBlock['type']) { + private async insertBlock(type: IBlock['type']) { const currentBlockIndex = this.blocks.findIndex(b => b.id === this.selectedBlockId); const currentBlock = this.blocks[currentBlockIndex]; 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.content = ''; @@ -1027,4 +1072,142 @@ export class DeesInputWysiwyg extends DeesInputBase { } }, 10); } + + private async showLanguageSelectionModal(): Promise { + return new Promise((resolve) => { + let selectedLanguage: string | null = null; + + DeesModal.createAndShow({ + heading: 'Select Programming Language', + content: html` + +
    + ${['JavaScript', 'TypeScript', 'Python', 'Java', 'C++', 'C#', 'Go', 'Rust', 'HTML', 'CSS', 'SQL', 'Shell', 'JSON', 'YAML', 'Markdown', 'Plain Text'].map(lang => html` +
    ${lang}
    + `)} +
    + `, + 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 { + let content: TemplateResult; + + if (block.type === 'code') { + const currentLanguage = block.metadata?.language || 'plain text'; + content = html` + +
    +
    Programming Language
    +
    + ${['JavaScript', 'TypeScript', 'Python', 'Java', 'C++', 'C#', 'Go', 'Rust', 'HTML', 'CSS', 'SQL', 'Shell', 'JSON', 'YAML', 'Markdown', 'Plain Text'].map(lang => html` +
    ${lang}
    + `)} +
    +
    + `; + } else { + content = html`
    No settings available for this block type.
    `; + } + + DeesModal.createAndShow({ + heading: 'Block Settings', + content, + menuOptions: [ + { + name: 'Close', + action: async (modal) => { + modal.destroy(); + } + } + ] + }); + } } \ No newline at end of file diff --git a/ts_web/elements/wysiwyg/wysiwyg.blocks.ts b/ts_web/elements/wysiwyg/wysiwyg.blocks.ts index 0f5f972..bceeed9 100644 --- a/ts_web/elements/wysiwyg/wysiwyg.blocks.ts +++ b/ts_web/elements/wysiwyg/wysiwyg.blocks.ts @@ -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` +
    +
    ${language}
    +
    +
    + `; + } + return html`