Welcome to My Site
This content was loaded from HTML
A simple, pure JavaScript drag-and-drop website builder with zero dependencies.
https://github.com/tsawler/dragon-cms
cms drag-and-drop website-builder
Last synced: 5 months ago
JSON representation
A simple, pure JavaScript drag-and-drop website builder with zero dependencies.




# DragonCMS - Drag & Drop Website Builder
A simple, pure JavaScript drag-and-drop website builder with zero dependencies. Create responsive websites visually by dragging sections, blocks, and snippets onto a canvas, with real-time editing, custom styling, and HTML code access. Features an organized tabbed sidebar for easy component access.
**🚀 [Try the Live Demo](https://tsawler.github.io/dragon-cms/)**
This project is **still in development**, and has not yet reached a stable release. Most features seem to work, and all tests pass, but there are undoubtedly still some rough edges.
## Table of Contents
- [Features](#features)
- [Quick Start](#quick-start)
- [Installation](#installation)
- [Basic Usage](#basic-usage)
- [Advanced Examples](#advanced-examples)
- [API Reference](#api-reference)
- [Customization](#customization)
- [Section System](#section-system)
- [Components](#components)
- [Browser Support](#browser-support)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [License](#license)
## Features
### Core Capabilities
- **Pure JavaScript** - No frameworks, no dependencies, just vanilla JavaScript
- **Drag & Drop Interface** - Intuitive visual building with organized tabbed sidebar for sections, blocks, and snippets
- **Responsive Design** - Built-in viewport preview modes (Desktop, Tablet, Mobile)
- **Real-time Editing** - In-place text editing with rich formatting toolbar
- **Custom Styling** - Visual style editor for every element
- **HTML Access** - Direct HTML code editing for advanced users
- **Undo/Redo** - Complete state history management
- **Import/Export** - Save and load designs as JSON or HTML
### Advanced Features
- **Section System** - Full-width page sections with background control and content centering
- **Block System** - Container-based layout with column management
- **Rich Text Editing** - Full formatting toolbar with fonts, colors, alignment
- **Image Management** - Upload, resize, and position images with visual handles
- **Video Embedding** - YouTube and video file support
- **Button Customization** - Style, URL, and target configuration
- **Page Settings** - Custom CSS and JavaScript injection
- **Background Images** - Upload and position background images for sections and blocks
- **Column Resizing** - Visual column width adjustment
- **Organized Interface** - Tabbed left sidebar with search/filtering for components
### Developer Features
- **Programmatic API** - Full control via JavaScript
- **Custom Snippets** - Create your own components
- **Event System** - Listen to editor mode changes and content modifications
- **Callback System** - onChange and onRender callbacks for content tracking
- **Font Customization** - Easy Google Fonts integration with copy-paste embed links
- **Flexible Configuration** - Customize paths, assets, and behavior
- **Save/Load Integration** - Connect to your backend API
## Quick Start
### Minimal Example
```html
DragonCMS Example
import dragon from './js/dragon.js';
const editor = dragon.New({
containerId: 'editor',
cssPath: 'editor.css',
showCodeIcon: true
});
```
## Installation
### Option 1: Use Built Files (Recommended for Production)
1. Download or clone the repository:
```bash
git clone https://github.com/tsawler/dragon-cms.git
cd dragon-cms
```
2. Install dependencies and build:
```bash
npm install
npm run build
```
3. Use the built files from the `dist/` folder in your project:
```html
```
### Option 2: Use Source Files (Development)
1. Clone the repository:
```bash
git clone https://github.com/tsawler/dragon-cms.git
cd dragon-cms
```
2. Use the source files directly:
```html
```
### File Structure
```
dragoncms/
├── index.html # Example implementation
├── editor.css # Editor styles
├── snippets.js # Block and snippet definitions
├── fonts.js # Google Fonts configuration
├── custom-blocks.js # Custom blocks configuration
├── custom-snippets.js # Custom snippets configuration
├── assets/ # Images and resources
│ └── images/
└── js/ # Core JavaScript modules
├── dragon.js # Main entry point
├── editor-core.js # Core editor class
├── modals.js # Modal components
├── formatting-toolbar.js
├── snippet-panel.js
├── state-history.js
├── image-uploader.js
├── column-resizer.js
└── [other modules]
```
## Development
### Build System
DragonCMS uses Rollup and Babel for building and bundling. The build system creates both development and production versions.
#### Available Scripts
```bash
# Install dependencies
npm install
# Build for production (creates dist/ folder)
npm run build
# Serve built files on localhost:8000
npm run serve
# Serve development files on localhost:8000
npm run serve:dev
# Run tests
npm test
# Run tests in watch mode
npm run test:watch
# Generate test coverage report
npm run test:coverage
```
#### Development Workflows
**Fast Development (Recommended):**
```bash
npm run serve:dev # Serves source files directly with ES modules
# Edit source files, refresh browser to see changes immediately
```
**Production Testing:**
```bash
npm run build # Build once
npm run serve # Serve built files
# Test the production build
```
**Testing:**
```bash
npm test # Run all tests once
npm run test:watch # Run tests in watch mode (auto-rerun on file changes)
npm run test:coverage # Generate test coverage report
```
DragonCMS includes a comprehensive test suite covering:
- Core editor functionality
- Font system and Google Fonts integration
- Custom blocks system and configuration
- Custom snippets system and configuration
- State management and history
- Modal components and UI interactions
- Callback system
- Error handling and edge cases
#### Build Output
The build process creates:
- `dist/dragon.js` - Development bundle (unminified)
- `dist/dragon.min.js` - Production bundle (minified, console logs removed)
- `dist/editor.css` - Editor styles (unminified)
- `dist/editor.min.css` - Editor styles (minified)
- `dist/snippets.js` - Components (unminified)
- `dist/snippets.min.js` - Components (minified)
- `dist/fonts.js` - Google Fonts configuration (copied from source)
- `dist/custom-blocks.js` - Custom blocks configuration (copied from source)
- `dist/custom-snippets.js` - Custom snippets configuration (copied from source)
- `dist/index.html` - Example page (copied from source)
- `dist/assets/` - Static assets (copied from source)
#### Using Built Files
For production, use the minified bundles:
```html
My Website Builder
// Note: Built version creates global 'dragon' object
const editor = dragon.New({
containerId: 'editor'
});
```
#### Build Configuration
The build is configured through:
- `rollup.config.js` - Rollup bundling configuration for JavaScript
- `postcss.config.js` - PostCSS configuration for CSS minification
- `.babelrc` - Babel transpilation settings (ES6+ to ES5)
- `package.json` - Build scripts and dependencies
Target browsers: `> 1%`, `last 2 versions`, `not dead`, `IE 11`
**Minification:**
- JavaScript: Terser (removes console logs in production)
- CSS: cssnano (optimizes and minifies styles)
## Basic Usage
### Simple Implementation
```html
My Website Builder
body { margin: 0; padding: 0; }
#my-editor { width: 100vw; height: 100vh; }
window.addEventListener('load', function() {
const editor = dragon.New({
containerId: 'my-editor',
cssPath: 'editor.css',
showCodeIcon: true,
snippetsPath: 'snippets.js',
assetsPath: 'assets/'
});
});
```
### With Existing Content
```javascript
const editor = dragon.New({
containerId: 'my-editor',
cssPath: 'editor.css',
initialContent: `
Welcome to My Site
This content was loaded from HTML
`
});
```
### Display Mode with Edit Button
```html
Website with Edit Mode
#edit-btn {
position: fixed;
top: 20px;
right: 20px;
z-index: 10000;
background: #007bff;
color: white;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 24px;
cursor: pointer;
box-shadow: 0 2px 8px rgba(0,0,0,0.2);
}
#edit-btn.editing { display: none; }
✏️
window.addEventListener('load', function() {
const editor = dragon.New({
containerId: 'content',
cssPath: 'editor.css'
});
// Start in display mode
editor.setMode('display');
// Edit button functionality
document.getElementById('edit-btn').addEventListener('click', function() {
editor.setMode('edit');
this.classList.add('editing');
});
// Listen for mode changes
window.addEventListener('dragonModeChanged', function(e) {
document.getElementById('edit-btn').classList.toggle('editing',
e.detail.mode === 'edit');
});
});
```
## Advanced Examples
### Save to Backend API
```javascript
const editor = dragon.New({
containerId: 'editor',
cssPath: 'editor.css',
publishUrl: 'https://api.example.com/pages/save',
loadUrl: 'https://api.example.com/pages/load'
});
// Save button is automatically connected to publishUrl
// Load button is automatically connected to loadUrl
// Manual save
document.getElementById('custom-save').addEventListener('click', async () => {
const content = editor.exportHTML();
const response = await fetch('/api/save', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
html: content,
timestamp: new Date().toISOString()
})
});
if (response.ok) {
alert('Saved successfully!');
}
});
```
### Custom Snippet Creation
Add custom components to `snippets.js`:
```javascript
// In snippets.js
window.getSnippets = function() {
return [
// Custom hero section
{
id: 'custom-hero',
name: 'Hero Section',
type: 'block',
preview: 'text',
html: `
Amazing Hero Title
Your compelling subtitle here
Get Started
`
},
// Custom testimonial card
{
id: 'testimonial',
name: 'Testimonial',
type: 'snippet',
preview: 'text',
html: `
Customer Name
CEO, Company
"This is an amazing product that has transformed our business..."
`
},
// Existing snippets...
...window.getDefaultSnippets()
];
};
```
### Using Callbacks for Custom Behavior
```javascript
const editor = dragon.New({
containerId: 'editor',
cssPath: 'editor.css',
onChange: (event) => {
// Auto-save on changes
if (event.type.includes('added') || event.type.includes('deleted')) {
autoSave(event.html);
}
// Track analytics
analytics.track('editor_change', {
action: event.type,
timestamp: event.timestamp
});
},
onRender: (event) => {
// Apply custom enhancements to rendered elements
if (event.type === 'block') {
// Add animation classes
event.element.classList.add('fade-in');
}
// Initialize third-party libraries
if (event.element.querySelector('.chart-container')) {
initializeCharts(event.element);
}
}
});
```
### Programmatic Content Manipulation
```javascript
const editor = dragon.New({
containerId: 'editor',
cssPath: 'editor.css'
});
// Switch modes programmatically
editor.setMode('edit'); // or 'display'
// Get current mode
const currentMode = editor.getMode();
// Export HTML
const htmlContent = editor.exportHTML();
// Load content dynamically
async function loadTemplate(templateId) {
const response = await fetch(`/templates/${templateId}.html`);
const html = await response.text();
// Clear current content and load new
document.getElementById('editable-area').innerHTML = html;
// Re-initialize editable elements
editor.makeExistingBlocksEditable();
}
// Listen for mode changes
window.addEventListener('dragonModeChanged', (e) => {
console.log('Mode changed to:', e.detail.mode);
if (e.detail.mode === 'display') {
// Auto-save when switching to display mode
autoSave();
}
});
```
## API Reference
### dragon.New(options)
Creates a new DragonCMS editor instance.
#### Parameters
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `containerId` | string | `'dragon-editor'` | ID of the container element |
| `cssPath` | string | `'editor.css'` | Path to the editor CSS file |
| `showCodeIcon` | boolean | `true` | Show HTML editor icon |
| `snippetsPath` | string | `'snippets.js'` | Path to snippets definition file |
| `assetsPath` | string | `'assets/'` | Path to assets folder |
| `initialContent` | string | `null` | Initial HTML content to load |
| `publishUrl` | string | `null` | API endpoint for saving |
| `loadUrl` | string | `null` | API endpoint for loading |
| `onChange` | function | `null` | Callback when content changes (add/delete/move) |
| `onRender` | function | `null` | Callback when element is rendered |
#### Returns
An `Editor` instance with the following methods:
### Editor Methods
#### editor.setMode(mode)
Sets the editor mode.
```javascript
editor.setMode('edit'); // Enable editing mode
editor.setMode('display'); // Enable display mode
```
#### editor.getMode()
Returns the current mode ('edit' or 'display').
```javascript
const mode = editor.getMode();
console.log(mode); // 'edit' or 'display'
```
#### editor.exportHTML()
Exports the current content as HTML.
```javascript
const html = editor.exportHTML();
// Returns complete HTML with styles
```
#### editor.exportData()
Exports the current state as JSON.
```javascript
const data = editor.exportData();
// Returns: { html: '...', pageSettings: {...} }
```
#### editor.makeExistingBlocksEditable()
Re-initializes editing capabilities for dynamically loaded content.
```javascript
// After loading new HTML content
document.getElementById('editable-area').innerHTML = newContent;
editor.makeExistingBlocksEditable();
```
### Events
#### dragonModeChanged
Fired when the editor mode changes.
```javascript
window.addEventListener('dragonModeChanged', (e) => {
console.log('New mode:', e.detail.mode);
// e.detail.mode is 'edit' or 'display'
});
```
### Callbacks
#### onChange Callback
Triggered when content changes (sections/blocks/snippets added, deleted, or moved).
```javascript
const editor = dragon.New({
containerId: 'editor',
onChange: (event) => {
console.log('Content changed:', event);
// event.type: 'section-added', 'section-deleted', 'section-moved',
// 'block-added', 'block-deleted', 'block-moved',
// 'snippet-added', 'snippet-deleted', 'snippet-moved'
// event.element: The affected element (null for deletions)
// event.html: Current HTML content of the editor
// event.timestamp: ISO timestamp of the change
}
});
```
#### onRender Callback
Triggered when a new section, block, or snippet is rendered.
```javascript
const editor = dragon.New({
containerId: 'editor',
onRender: (event) => {
console.log('Element rendered:', event);
// event.type: 'section', 'block', or 'snippet'
// event.element: The rendered DOM element
// event.timestamp: ISO timestamp of the render
// Example: Add custom initialization
if (event.type === 'section') {
// Initialize any custom JavaScript for the section
initializeCustomSection(event.element);
}
}
});
```
## Customization
### Font Customization
DragonCMS supports easy Google Fonts integration through the `fonts.js` configuration file. Users can simply copy and paste Google Fonts embed links to add custom typography to the formatting toolbar.
#### Adding Google Fonts
1. Visit [fonts.google.com](https://fonts.google.com) and select your desired fonts
2. Copy the `` embed code provided by Google Fonts
3. Add it to the `googleFontLinks` array in `fonts.js`
```javascript
// In fonts.js
window.DragonFonts = {
// Default system fonts (always available)
systemFonts: [
{ name: "Arial", family: "Arial, sans-serif" },
{ name: "Georgia", family: "Georgia, serif" },
// ... other system fonts
],
// Google Fonts - just paste embed links here
googleFontLinks: [
'',
'',
'',
// Add your fonts here
]
};
```
#### Supported Font Formats
The font parser automatically handles various Google Fonts URL formats:
```javascript
// Simple single font
''
// Multiple weights
''
// Multiple fonts in one URL
''
// Complex variations with italics
''
```
#### Font Fallback Assignment
The system automatically assigns appropriate fallbacks:
- **Serif fonts** (Playfair Display, Merriweather, etc.) → `serif`
- **Monospace fonts** (Fira Code, Source Code Pro, etc.) → `monospace`
- **All other fonts** → `sans-serif`
#### Custom Font Integration
For production builds, ensure `fonts.js` is loaded before the Dragon library:
```html
```
#### Font Loading
Google Fonts are automatically loaded when the editor initializes. The system:
1. Parses font names from embed links
2. Injects `` tags into the document head
3. Adds fonts to the formatting toolbar dropdown
4. Prevents duplicate font loading
#### Example: Adding Popular Fonts
```javascript
// Popular Google Fonts examples
googleFontLinks: [
// Sans-serif fonts
'',
'',
'',
// Serif fonts
'',
'',
// Monospace fonts
'',
''
]
```
### Custom Blocks
DragonCMS supports user-defined custom blocks through the `custom-blocks.js` configuration file. Custom blocks are container elements that can hold other content and appear in the editor's block panel alongside default blocks.
#### Adding Custom Blocks
Custom blocks are defined in the `custom-blocks.js` file. **Simply add your blocks to the `customBlocks` array - that's all you need to do!**
```javascript
// In custom-blocks.js - This is ALL you need to edit:
window.DragonBlocks = {
customBlocks: [
// Just add your blocks here:
{
id: 'custom-card-block',
name: 'Card Block',
type: 'block',
preview: 'text',
description: 'A card-style container with shadow and padding',
category: 'layout',
html: `
Card Title
This is a custom card block. Add your content here.
`
},
// Add more blocks here...
]
// Note: Management methods are automatically provided by DragonCMS
// You don't need to implement these - they're built-in!
};
```
**That's it!** Include the script tag and your blocks automatically appear:
```html
```
#### Block Configuration Properties
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `id` | string | ✓ | Unique identifier for the block |
| `name` | string | ✓ | Display name in the editor panel |
| `type` | string | ✓ | Must be 'block' for container elements |
| `html` | string | ✓ | The HTML structure of the block |
| `preview` | string | ✓ | 'text' or 'image' - how to display in panel |
| `description` | string | ✗ | Tooltip description |
| `category` | string | ✗ | Category for organization (e.g., 'layout', 'marketing') |
| `previewImage` | string | ✗ | **Required if preview='image'** - See preview options below |
#### Preview Options
**Text Preview (`preview: 'text'`):**
- Shows the block name as text in the editor panel
- Simple and straightforward - no additional configuration needed
- Best for most use cases
**Image Preview (`preview: 'image'`):**
- Shows a custom icon/image in the editor panel instead of text
- Requires `previewImage` property with one of these formats:
**Supported Image Formats:**
- **File path**: `'./assets/my-preview.png'` (PNG, JPG, WebP, GIF, SVG files)
- **Absolute URL**: `'https://example.com/preview.jpg'`
- **Data URL**: `'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...'`
- **SVG data URL**: `svgToDataUrl('...')` (for inline SVG)
**Example with Image Preview:**
```javascript
{
id: 'hero-block',
name: 'Hero Section',
type: 'block',
preview: 'image',
previewImage: './assets/hero-icon.png', // Simple file path
html: '
Hero content'
}
```
**Example with Text Preview:**
```javascript
{
id: 'card-block',
name: 'Card Block',
type: 'block',
preview: 'text', // No previewImage needed
html: '
Card content'
}
```
#### Built-in Custom Blocks
DragonCMS includes several pre-configured custom blocks:
**Layout Blocks:**
- **Card Block** - Card-style container with shadow and padding
- **Feature Grid** - Multi-column grid layout for features
**Marketing Blocks:**
- **CTA Section** - Call-to-action container with centered content
- **Testimonial Block** - Customer testimonial with avatar layout
- **Pricing Table** - Multi-tier pricing comparison
**Content Blocks:**
- Various content-focused containers with predefined styling
#### Creating Custom Blocks
1. **Basic Block Structure:**
```javascript
{
id: 'my-custom-block',
name: 'My Custom Block',
type: 'block',
preview: 'text',
category: 'layout',
html: `
Custom Block Title
Add your content here
`
}
```
2. **Advanced Block with Styling:**
```javascript
{
id: 'hero-section-block',
name: 'Hero Section',
type: 'block',
preview: 'text',
description: 'Full-width hero section with gradient background',
category: 'marketing',
html: `
Hero Title
Your compelling message here
Get Started
`
}
```
#### Block Categories
Organize blocks using categories:
- **layout** - Structural containers and layout blocks
- **marketing** - CTA, testimonial, pricing blocks
- **content** - Content-focused containers
- **media** - Image galleries, video containers
- **custom** - User-specific blocks
#### Integration with Editor
Custom blocks automatically integrate with the editor:
- **Block Panel** - Appear in blocks tab (🧱) with filtering support
- **Drag & Drop** - Full drag and drop functionality
- **Block Settings** - Access to gear icon settings (layout, columns, background)
- **Content Editing** - All text elements are editable
- **Column Management** - Support for adding/removing columns
- **Responsive Design** - Blocks adapt to tablet/mobile preview modes
#### Block Loading
For production builds, ensure both custom files are loaded before the Dragon library:
```html
```
#### Dynamic Block Management (Advanced)
**Note: These methods are automatically provided by DragonCMS - you don't need to implement them!** They're available for advanced runtime management:
```javascript
// Built-in methods available on window.DragonBlocks:
// Get all custom blocks
const blocks = window.DragonBlocks.getAllCustomBlocks();
// Get blocks by category
const layoutBlocks = window.DragonBlocks.getBlocksByCategory('layout');
// Get specific block
const cardBlock = window.DragonBlocks.getBlockById('custom-card-block');
// Get all available categories
const categories = window.DragonBlocks.getCategories();
// Add new block dynamically (advanced usage)
const success = window.DragonBlocks.addCustomBlock({
id: 'new-block',
name: 'New Block',
type: 'block',
html: '
New content'
});
```
**For most users: Just edit the `customBlocks` array in custom-blocks.js - these methods are only needed for advanced programmatic manipulation.**
#### Best Practices
1. **Use semantic HTML structure** with proper accessibility
2. **Include responsive design patterns** (flexbox, grid, percentages)
3. **Provide meaningful descriptions** for better user experience
4. **Use consistent naming conventions** for IDs and classes
5. **Test blocks across devices** using preview modes
6. **Avoid inline scripts** for security (use external initialization if needed)
7. **Use appropriate categories** for better organization
### Custom Snippets
DragonCMS supports user-defined custom snippets through the `custom-snippets.js` configuration file. Custom snippets are content elements like text, images, buttons, or custom HTML components that can be dragged into blocks.
#### Adding Custom Snippets
Custom snippets are defined in the `custom-snippets.js` file. **Simply add your snippets to the `customSnippets` array - that's all you need to do!**
```javascript
// In custom-snippets.js - This is ALL you need to edit:
window.DragonSnippets = {
customSnippets: [
// Just add your snippets here:
{
id: 'custom-alert-box',
name: 'Alert Box',
type: 'snippet',
snippetType: 'content',
preview: 'text',
description: 'A styled alert box with icon and message',
category: 'content',
html: `
This is an important message for your visitors.
`
},
// Add more snippets here...
]
// Note: Management methods are automatically provided by DragonCMS
// You don't need to implement these - they're built-in!
};
```
**That's it!** Include the script tag and your snippets automatically appear in the "Custom Snippets" section:
```html
```
#### Snippet Configuration Properties
| Property | Type | Required | Description |
|----------|------|----------|-------------|
| `id` | string | ✓ | Unique identifier for the snippet |
| `name` | string | ✓ | Display name in the editor panel |
| `type` | string | ✓ | Must be 'snippet' for content elements |
| `html` | string | ✓ | The HTML structure of the snippet |
| `preview` | string | ✓ | 'text' or 'image' - how to display in panel |
| `description` | string | ✗ | Tooltip description |
| `category` | string | ✗ | Category for organization (e.g., 'content', 'marketing') |
| `snippetType` | string | ✗ | Sub-type (e.g., 'text', 'media', 'button') |
| `previewImage` | string | ✗ | **Required if preview='image'** - See preview options below |
#### Preview Options
**Text Preview (`preview: 'text'`):**
- Shows the snippet name as text in the editor panel
- Simple and straightforward - no additional configuration needed
- Best for most use cases
**Image Preview (`preview: 'image'`):**
- Shows a custom icon/image in the editor panel instead of text
- Requires `previewImage` property with one of these formats:
**Supported Image Formats:**
- **File path**: `'./assets/my-preview.png'` (PNG, JPG, WebP, GIF, SVG files)
- **Absolute URL**: `'https://example.com/preview.jpg'`
- **Data URL**: `'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...'`
- **SVG data URL**: `svgToDataUrl('...')` (for inline SVG)
**Example with Image Preview:**
```javascript
{
id: 'testimonial-card',
name: 'Testimonial Card',
type: 'snippet',
preview: 'image',
previewImage: './assets/testimonial-icon.svg', // Simple file path
html: '
Customer testimonial content'
}
```
**Example with Text Preview:**
```javascript
{
id: 'alert-box',
name: 'Alert Box',
type: 'snippet',
preview: 'text', // No previewImage needed
html: '
Alert message content'
}
```
#### Built-in Custom Snippets
DragonCMS includes several pre-configured custom snippets:
**Content Snippets:**
- **Alert Box** - Styled notification box with icon and message
- **Feature Highlight** - Feature showcase with icon and description
- **Code Block** - Syntax-highlighted code display with terminal styling
**Marketing Snippets:**
- **Testimonial Card** - Customer testimonial with avatar and star rating
- **Stat Counter** - Statistics display with large number and description
#### Creating Custom Snippets
1. **Basic Snippet Structure:**
```javascript
{
id: 'my-custom-snippet',
name: 'My Custom Snippet',
type: 'snippet',
preview: 'text',
category: 'content',
html: `
Custom Content
Add your content here
`
}
```
2. **Advanced Snippet with Rich Styling:**
```javascript
{
id: 'pricing-card',
name: 'Pricing Card',
type: 'snippet',
snippetType: 'marketing',
preview: 'text',
description: 'A pricing card with features and call-to-action',
category: 'marketing',
html: `
Pro Plan
$29/month
- ✓ All features included
- ✓ Priority support
- ✓ Advanced analytics
Get Started
`
}
```
#### Snippet Categories
Organize snippets using categories:
- **content** - Text elements, alerts, highlights
- **marketing** - Testimonials, pricing cards, CTAs
- **media** - Image galleries, video players
- **navigation** - Breadcrumbs, pagination, menus
- **social** - Social media widgets, share buttons
#### Integration with Editor
Custom snippets automatically integrate with the editor:
- **Snippet Panel** - Appear in snippets tab (⚡) with filtering support
- **Drag & Drop** - Full drag and drop functionality into blocks
- **Text Editing** - All text elements become editable when dropped
- **Formatting Toolbar** - Rich text formatting available for text content
- **Content Flexibility** - Can be placed in any block or column
#### Dynamic Snippet Management (Advanced)
**Note: These methods are automatically provided by DragonCMS - you don't need to implement them!** They're available for advanced runtime management:
```javascript
// Built-in methods available on window.DragonSnippets:
// Get all custom snippets
const snippets = window.DragonSnippets.getAllCustomSnippets();
// Get snippets by category
const contentSnippets = window.DragonSnippets.getSnippetsByCategory('content');
// Get specific snippet
const alertBox = window.DragonSnippets.getSnippetById('custom-alert-box');
// Get all available categories
const categories = window.DragonSnippets.getCategories();
// Add new snippet dynamically (advanced usage)
const success = window.DragonSnippets.addCustomSnippet({
id: 'new-snippet',
name: 'New Snippet',
type: 'snippet',
html: '
New content'
});
```
**For most users: Just edit the `customSnippets` array in custom-snippets.js - these methods are only needed for advanced programmatic manipulation.**
#### Best Practices
1. **Keep snippets focused** on single components or content types
2. **Use inline styles** for better portability and self-containment
3. **Provide clear descriptions** to help users understand the purpose
4. **Test across devices** to ensure responsive behavior
5. **Use semantic HTML** with proper accessibility attributes
6. **Avoid complex JavaScript** - keep snippets simple and reliable
7. **Category organization** helps users find snippets quickly
### Custom Styles
Override default styles by adding CSS after the editor.css:
```css
/* Custom theme */
.dragon-editor .editor-header {
background: linear-gradient(90deg, #4a90e2, #7b68ee);
}
.dragon-editor .btn-primary {
background: #7b68ee;
border-color: #7b68ee;
}
.dragon-editor .editor-block {
border-color: #e0e0e0;
}
/* Custom snippet styles */
.dragon-editor .custom-snippet {
background: #f8f9fa;
padding: 20px;
border-left: 4px solid #7b68ee;
}
```
### Custom Snippets
Create rich, interactive snippets:
```javascript
// Advanced snippet with JavaScript
{
id: 'countdown-timer',
name: 'Countdown Timer',
type: 'snippet',
preview: 'text',
html: `
`,
script: `
document.querySelectorAll('.countdown-widget').forEach(widget => {
const target = new Date(widget.dataset.target);
setInterval(() => {
const now = new Date();
const diff = target - now;
const days = Math.floor(diff / (1000 * 60 * 60 * 24));
const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((diff % (1000 * 60)) / 1000);
widget.querySelector('.days').textContent = days;
widget.querySelector('.hours').textContent = hours;
widget.querySelector('.minutes').textContent = minutes;
widget.querySelector('.seconds').textContent = seconds;
}, 1000);
});
`
}
```
### Custom Block Templates
```javascript
// Multi-column responsive block
{
id: 'three-column-block',
name: 'Three Column Layout',
type: 'block',
preview: 'text',
html: `
Column 1
Content for the first column
Column 2
Content for the second column
Column 3
Content for the third column
`
}
```
## Section System
DragonCMS uses a hierarchical 3-level content structure: **Sections > Blocks > Snippets**. This provides better organization and enables modern full-width designs.
### Content Hierarchy
```
Section (Full-width page regions)
├── Block (Content containers with columns)
│ ├── Snippet (Text, images, buttons)
│ ├── Snippet
│ └── ...
├── Block
└── ...
```
### Sections
Sections are full-width page regions that span the entire viewport. They're perfect for creating modern website layouts with distinct page areas.
**Key Features:**
- **Full viewport width** - True edge-to-edge spanning
- **Background control** - Colors, gradients, and images
- **Content centering** - Inner content stays centered with configurable max-width
- **Semantic structure** - Proper HTML5 `` elements
**Section Settings (⚙️ icon):**
- **Layout Tab:**
- Section width (usually 100% for full-width)
- Content max-width (centers content within section)
- Padding (vertical and horizontal spacing)
- Minimum height (for consistent sizing)
- **Background Tab:**
- Background color with color picker
- Background image upload with browse button
- Background size (cover, contain, auto, stretch)
- Background position (center, top, bottom, etc.)
### Blocks within Sections
Blocks live inside sections and provide structured content areas:
- **Drag blocks into section content areas** to organize content
- **Column management** - Add/remove columns within blocks
- **Responsive behavior** - Columns stack on tablet/mobile
- **Block settings** available via gear icon
### Working with Sections
**Creating Sections:**
1. Click the sections icon (📋) in the left sidebar to open the sections panel
2. Drag a section from the panel to the main editor area
3. Choose from: Hero, Content, Features, CTA, Footer, or Empty sections
**Adding Content to Sections:**
1. Click the blocks icon (🧱) in the left sidebar to access blocks
2. Drag blocks into the section's content area
3. Click the snippets icon (⚡) for content elements
4. Drag snippets into blocks within sections
5. Use the hierarchical structure to organize content logically
**Section vs Block Backgrounds:**
- **Section backgrounds** span the full viewport width
- **Block backgrounds** only cover the block content area
- Use sections for page-wide visual themes
### Example Section Structure
```html
Hero Title
Hero description
CTA Button
Column 1 Title
Column 1 content
Column 2 Title
Column 2 content
```
### Benefits of the Section System
**Better Organization:**
- Clear visual separation between page regions
- Semantic HTML structure improves SEO and accessibility
- Logical content hierarchy
**Design Flexibility:**
- True full-width backgrounds without CSS hacks
- Independent styling for each page section
- Consistent content centering
**Responsive Design:**
- Sections adapt to all viewport sizes
- Content remains centered and readable
- Background images scale appropriately
**Modern Web Standards:**
- Follows industry-standard page building patterns
- Compatible with CSS Grid and Flexbox
- Future-ready architecture
## Components
### Available Sections
1. **Hero Section** - Full-width hero with gradient background
2. **Content Section** - Standard content area with centered container
3. **Features Section** - Feature showcase section with light background
4. **Call to Action Section** - CTA section with dark background
5. **Footer Section** - Page footer with dark styling
### Available Blocks
1. **Container Block** - Basic container with columns
2. **Two Column Block** - Side-by-side layout
3. **Three Column Block** - Three equal columns
4. **Hero Block** - Hero content container
### Available Snippets
1. **Text Elements**
- Heading (H1-H6)
- Paragraph
- Blockquote
- Lists (ordered/unordered)
2. **Media Elements**
- Image
- Video (YouTube/file)
- Image Gallery
3. **Interactive Elements**
- Button
- Link
- Form elements
4. **Layout Elements**
- Divider
- Spacer
- Custom HTML
## Browser Support
DragonCMS supports all modern browsers:
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
### Known Browser Issues
#### Firefox
- Cursor positioning in contentEditable elements requires special handling (implemented)
- Drag handle conflicts with contentEditable (resolved with workarounds)
#### Safari
- Some drag-and-drop behaviors may differ slightly
- Touch events on iOS require additional handling
## Troubleshooting
### Common Issues
#### Accessing Components
**Problem:** Cannot find sections, blocks, or snippets to drag
**Solution:** Use the tabbed left sidebar:
- Click the sections icon (📋) to access page sections
- Click the blocks icon (🧱) to access layout containers
- Click the snippets icon (⚡) to access content elements
- Click the same icon again to close the panel
#### Blocks not dragging
**Problem:** Blocks can only be dragged by the handle (⋮⋮)
**Solution:** Click and drag the dotted handle on the left side of each block
#### Text not editable
**Problem:** After using HTML editor, text becomes uneditable
**Solution:** The editor automatically re-initializes contentEditable. If issues persist, call:
```javascript
editor.makeExistingBlocksEditable();
```
#### Styles not applying
**Problem:** Custom styles not showing
**Solution:** Ensure CSS specificity is high enough:
```css
.dragon-editor .editor-block.custom-class {
/* Your styles */
}
```
#### Save/Load not working
**Problem:** Save/Load buttons not functioning
**Solution:** Set the `publishUrl` and `loadUrl` options:
```javascript
const editor = dragon.New({
publishUrl: '/api/save',
loadUrl: '/api/load'
});
```
## Contributing
We welcome contributions! Please see our [Contributing Guidelines](CONTRIBUTING.md) for details.
### Development Setup
1. Clone the repository
2. Install dependencies: `npm install`
3. Run tests: `npm test`
4. Open `index.html` in a browser or use `npm run serve:dev`
5. Make changes to the JavaScript modules
6. Run tests again to ensure no regressions
7. Test across different browsers
8. Submit a pull request
### Testing
DragonCMS uses Jest for unit and integration testing. Tests are located in the `tests/` directory.
**Running Tests:**
```bash
# Run all tests
npm test
# Run specific test file
npm test -- tests/fonts.test.js
# Run tests in watch mode (recommended for development)
npm run test:watch
# Generate coverage report
npm run test:coverage
```
**Test Structure:**
- `tests/fonts.test.js` - Google Fonts system tests
- `tests/blocks.test.js` - Custom blocks system tests
- `tests/custom-snippets.test.js` - Custom snippets system tests
- `tests/callbacks.test.js` - onChange/onRender callback tests
- `tests/editor-core.test.js` - Core editor functionality tests
- `tests/modals.test.js` - Modal component tests
- `tests/[component].test.js` - Individual component tests
**Writing Tests:**
Follow the existing test patterns. All tests should:
- Use descriptive test names
- Test both success and error scenarios
- Mock external dependencies appropriately
- Maintain good coverage of critical functionality
### Testing Checklist
- [ ] Run `npm test` and ensure all tests pass
- [ ] Test drag and drop in Chrome, Firefox, Safari
- [ ] Verify responsive preview modes
- [ ] Test HTML editor functionality
- [ ] Check undo/redo behavior
- [ ] Test font customization with Google Fonts
- [ ] Test custom blocks functionality and integration
- [ ] Test custom snippets functionality and integration
- [ ] Verify save/load if configured
- [ ] Test custom snippets
- [ ] Test callback functionality (onChange/onRender)
- [ ] Validate mobile touch events
## License
MIT License - see [LICENSE.md](LICENSE.md) file for details.
## Support
For issues, questions, or suggestions:
- Open an issue on [GitHub](https://github.com/tsawler/dragon-cms)