Skip to content
On this page

Accent Swatch Plugin

Customize your editor's accent color with a visual color picker that remembers your recent choices.

Overview

The accentSwatchPlugin provides a user-friendly color palette for changing the editor's accent color. It features:

  • 🎨 Visual color swatch picker
  • 💾 Persistent recent colors in localStorage
  • 🎯 Eyedropper support (modern browsers)
  • ⚡ Native color picker integration
  • ✨ Live preview and instant application

Installation

ts
import { Marzipan } from '@pinkpixel/marzipan';
import { accentSwatchPlugin } from '@pinkpixel/marzipan/plugins/accentSwatchPlugin';

new Marzipan('#editor', {
  toolbar: true,
  plugins: [accentSwatchPlugin()]
});

Options

ts
interface AccentSwatchOptions {
  max?: number;          // Max swatches to keep (default: 12)
  defaults?: string[];   // Seed colors if none saved
  title?: string;        // Toolbar tooltip (default: 'Accent color')
  label?: string;        // Toolbar button label (default: ⭘)
}

Usage Examples

Basic Usage

ts
import { accentSwatchPlugin } from '@pinkpixel/marzipan/plugins/accentSwatchPlugin';

new Marzipan('#editor', {
  plugins: [accentSwatchPlugin()]
});

With Default Colors

ts
import { accentSwatchPlugin } from '@pinkpixel/marzipan/plugins/accentSwatchPlugin';

new Marzipan('#editor', {
  plugins: [
    accentSwatchPlugin({
      max: 8,
      defaults: [
        '#8b5cf6', // Purple (default Marzipan accent)
        '#ef4444', // Red
        '#f59e0b', // Amber
        '#10b981', // Green
        '#3b82f6', // Blue
        '#ec4899', // Pink
        '#6366f1', // Indigo
        '#14b8a6'  // Teal
      ],
      title: 'Change theme color',
      label: '🎨'
    })
  ]
});

Coordinated with Theme

ts
import { Marzipan } from '@pinkpixel/marzipan';
import { accentSwatchPlugin } from '@pinkpixel/marzipan/plugins/accentSwatchPlugin';

const themeColors = {
  solar: ['#dc8d10', '#cb4b16', '#d33682', '#6c71c4', '#268bd2'],
  cave: ['#8b5cf6', '#a78bfa', '#c084fc', '#e879f9', '#f0abfc'],
  forest: ['#10b981', '#059669', '#047857', '#065f46', '#064e3b']
};

const theme = 'cave'; // or dynamically determined

new Marzipan('#editor', {
  theme,
  plugins: [
    accentSwatchPlugin({
      defaults: themeColors[theme]
    })
  ]
});

Features

Color Selection Methods

The plugin offers three ways to pick colors:

1. Color Picker (Default)

Click the + button to open native color picker:

  • Visual gradient selector
  • Works in all browsers
  • Instant preview

2. Manual Input (Shift+Click)

Hold Shift and click + to type hex value:

  • Enter format: #RRGGBB or RRGGBB
  • Supports 3-digit shorthand (#abc#aabbcc)
  • Validates input

3. Eyedropper (Alt+Click)

Hold Alt and click + to pick from screen:

  • Pick any color visible on screen
  • Modern browser support (Chrome, Edge)
  • Falls back to manual input if unavailable

Recent Colors

  • Automatically saves selected colors
  • Up to 12 swatches by default (configurable)
  • Most recent colors appear first
  • Persists across browser sessions
  • Syncs between editor instances

Color Management

Select: Click any swatch to apply color
Remove: Right-click swatch to delete
Add Current: Save current accent to swatches
Reset: Restore default colors

Styling

The plugin exports accentSwatchStyles for custom styling:

ts
import { 
  accentSwatchPlugin, 
  accentSwatchStyles 
} from '@pinkpixel/marzipan/plugins/accentSwatchPlugin';

// Inject styles
const styleElement = document.createElement('style');
styleElement.textContent = accentSwatchStyles;
document.head.appendChild(styleElement);

new Marzipan('#editor', {
  plugins: [accentSwatchPlugin()]
});

Custom CSS Variables

css
/* Accent Swatch Panel */
--mz-pop-bd: #333;        /* Swatch border */
--mz-accent: #8b5cf6;     /* Current accent color */

/* Buttons */
--mz-bd: #2b2f36;         /* Button border */
--mz-btn-bg: #1a1e24;     /* Button background */
--mz-btn-fg: #e7e7e7;     /* Button text */

Complete Example

ts
import { Marzipan } from '@pinkpixel/marzipan';
import { 
  accentSwatchPlugin,
  accentSwatchStyles 
} from '@pinkpixel/marzipan/plugins';

// Inject styles
const style = document.createElement('style');
style.textContent = accentSwatchStyles;
document.head.appendChild(style);

// Create editor with accent swatch
const [editor] = new Marzipan('#editor', {
  toolbar: true,
  theme: 'cave',
  
  plugins: [
    accentSwatchPlugin({
      max: 10,
      defaults: [
        '#8b5cf6', // Purple
        '#a78bfa', // Light purple
        '#c084fc', // Lighter purple
        '#e879f9', // Pink-purple
        '#f0abfc', // Pink
        '#ec4899', // Hot pink
        '#ef4444', // Red
        '#f59e0b', // Orange
        '#10b981', // Green
        '#3b82f6'  // Blue
      ],
      title: 'Customize accent color'
    })
  ],
  
  value: `# Welcome to Marzipan

Try changing the accent color! 🎨
`
});

// Listen for accent changes
editor.container.addEventListener('marzipan:accent', (e) => {
  console.log('Accent changed to:', e.detail.color);
  
  // Optionally sync with your app theme
  document.body.style.setProperty('--app-accent', e.detail.color);
});

Programmatic Control

Set Accent Color

ts
const [editor] = new Marzipan('#editor', {
  plugins: [accentSwatchPlugin()]
});

// Set accent programmatically
document.documentElement.style.setProperty('--mz-accent', '#ef4444');

// Or use the editor's method if available
if (editor.setAccent) {
  editor.setAccent('#ef4444');
}

Get Current Accent

ts
// From CSS variable
const accent = getComputedStyle(document.documentElement)
  .getPropertyValue('--mz-accent')
  .trim();

console.log('Current accent:', accent);

Listen for Changes

ts
editor.container.addEventListener('marzipan:accent', (event) => {
  const color = event.detail.color;
  
  // Update your app UI
  updateAppTheme(color);
  
  // Save to user preferences
  saveUserPreference('accentColor', color);
  
  // Analytics
  trackColorChange(color);
});

Accent Color Usage

The accent color is used throughout Marzipan for:

  • Active button states
  • Focus indicators
  • Link colors in preview
  • Selection highlights
  • Progress indicators
  • Custom highlights

CSS Example

css
/* Use accent in your styles */
.my-button:hover {
  background-color: var(--mz-accent);
}

.my-link {
  color: var(--mz-accent);
}

.my-border {
  border-color: var(--mz-accent);
}

Storage Details

localStorage Key

Colors are stored in localStorage under:

marzipan.accent.colors

Data Format

json
[
  "#8b5cf6",
  "#a78bfa",
  "#c084fc"
]

Clear Stored Colors

js
// Clear accent colors from localStorage
localStorage.removeItem('marzipan.accent.colors');

// Or use the Reset button in the UI

Browser Compatibility

Core Features:

  • Chrome/Edge 60+
  • Firefox 55+
  • Safari 11+

Eyedropper API:

  • Chrome/Edge 95+
  • Not yet supported in Firefox/Safari
  • Gracefully falls back to manual input

Native Color Picker:

  • All modern browsers
  • Best support in Chrome/Edge

Best Practices

Design Considerations

  1. Provide defaults that match your app's design system
  2. Limit swatches to prevent clutter (8-12 is ideal)
  3. Choose accessible colors with good contrast
  4. Test combinations with your editor theme
  5. Document colors if using specific palette

Accessibility

Ensure accent colors provide sufficient contrast:

Theming Integration

Dynamic Accent per Theme

ts
const themeDefaults = {
  solar: ['#dc8d10', '#cb4b16', '#d33682'],
  cave: ['#8b5cf6', '#a78bfa', '#c084fc'],
  forest: ['#10b981', '#059669', '#047857']
};

function createEditor(theme: 'solar' | 'cave' | 'forest') {
  return new Marzipan('#editor', {
    theme,
    plugins: [
      accentSwatchPlugin({
        defaults: themeDefaults[theme]
      })
    ]
  });
}

Sync with System Preferences

ts
// Detect dark mode
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

new Marzipan('#editor', {
  theme: prefersDark ? 'cave' : 'solar',
  plugins: [
    accentSwatchPlugin({
      defaults: prefersDark 
        ? ['#8b5cf6', '#a78bfa', '#c084fc'] // Dark mode colors
        : ['#dc8d10', '#cb4b16', '#d33682']  // Light mode colors
    })
  ]
});

Troubleshooting

Accent Not Applying

Check if CSS variable is set:

js
const accent = getComputedStyle(document.documentElement)
  .getPropertyValue('--mz-accent');
console.log('Accent:', accent || 'Not set');

Eyedropper Not Working

ts
// Check support
if ('EyeDropper' in window) {
  console.log('Eyedropper supported!');
} else {
  console.log('Eyedropper not available, use Shift+Click for manual input');
}

Colors Not Persisting

Verify localStorage access:

js
try {
  localStorage.setItem('test', 'test');
  localStorage.removeItem('test');
  console.log('localStorage available');
} catch (e) {
  console.error('localStorage blocked or full');
}

Advanced Usage

Custom Color Validation

ts
// Wrap plugin to add validation
function validatedAccentPlugin(options) {
  const basePlugin = accentSwatchPlugin(options);
  
  return (editor) => {
    basePlugin(editor);
    
    // Add validation listener
    editor.container.addEventListener('marzipan:accent', (e) => {
      const color = e.detail.color;
      
      // Check if color is too light/dark
      const rgb = parseInt(color.slice(1), 16);
      const brightness = (rgb >> 16) + ((rgb >> 8) & 0xff) + (rgb & 0xff);
      
      if (brightness < 100 || brightness > 600) {
        console.warn('Accent color may have poor contrast');
      }
    });
  };
}

new Marzipan('#editor', {
  plugins: [validatedAccentPlugin({ defaults: ['#8b5cf6'] })]
});

Share Colors Across Editors

ts
// Create multiple editors with shared palette
const sharedPlugin = accentSwatchPlugin({
  defaults: ['#8b5cf6', '#ef4444', '#10b981']
});

const editor1 = new Marzipan('#editor1', { plugins: [sharedPlugin] });
const editor2 = new Marzipan('#editor2', { plugins: [sharedPlugin] });

// Changes in one editor affect the other (via localStorage)

See Also

Released under the Apache 2.0 License