npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

tacel-canva

v1.1.0

Published

Premium Canva integration module for Tacel Electron apps with OAuth 2.0, inline design editor, 10 productivity features, 34 themes, keyboard shortcuts, and glassmorphism UI.

Readme

Tacel Canva Module - Premium Edition

Universal Canva integration module for Tacel Electron apps with premium UI and advanced features. A complete design management solution with OAuth authentication, inline editing, analytics, and 10+ productivity features.

✨ Features

Core Features

  • OAuth 2.0 Authentication with PKCE (Proof Key for Code Exchange)
  • Premium Design Gallery with glassmorphism effects and staggered animations
  • Inline Design Editor - Edit designs without leaving the app
  • Export/Download designs in multiple formats (PNG, PDF, JPG)
  • Custom Collections - Organize designs into custom collections
  • Favorites System - Star designs for quick access
  • Advanced Search - Search with filters and sorting
  • 34 Built-in Themes - Professional color schemes
  • Keyboard Shortcuts - Full keyboard navigation (press ? for help)
  • Toast Notifications - Elegant feedback system

Premium Features (NEW)

  1. 🏷️ Brand Kit Access - Quick access to brand colors, logos, and fonts
  2. 📋 Design Templates Browser - Browse Canva templates by category
  3. 📅 Scheduled Publishing Queue - Schedule design exports for specific dates
  4. 📝 Design Annotations & Notes - Add notes, tags, and link to tasks
  5. 📋 Quick Insert to Documents - Copy URLs, HTML for emails, or download
  6. ⚖️ Design Comparison View - Compare up to 4 designs side-by-side
  7. 📦 Asset Library Sync - Designate reusable assets for quick access
  8. 📊 Design Analytics Dashboard - Track views, exports, and usage stats
  9. 🎯 Batch Export with Presets - Export multiple designs with saved settings
  10. 💬 Design Request System - Submit and track design requests

UI/UX Enhancements

  • Glassmorphism Effects - Blurred backgrounds on modals and menus
  • Gradient System - Beautiful gradients throughout the UI
  • Layered Shadows - Depth with xs, sm, md, lg, xl shadow levels
  • Micro-interactions - Hover effects, staggered animations, smooth transitions
  • Premium Context Menus - Right-click anywhere for quick actions
  • Responsive Design - Adapts to all screen sizes
  • Loading Skeletons - Shimmer effects while content loads

Installation

npm install tacel-canva

Quick Start

1. Register Canva Integration

Go to Canva Developer Portal and create an integration:

  • Set redirect URI: http://localhost:3000/canva/callback
  • Enable scopes: design:meta:read, design:content:read, folder:read
  • Save your Client ID and Client Secret

2. Backend Setup (main.js)

const { initCanvaApi } = require('tacel-canva/canva-api');

// Initialize Canva API handlers
initCanvaApi({
  clientId: process.env.CANVA_CLIENT_ID,
  clientSecret: process.env.CANVA_CLIENT_SECRET,
  redirectUri: 'http://localhost:3000/canva/callback',
  channelPrefix: 'canva', // IPC channel prefix
});

3. Frontend Setup (renderer)

<!-- Include CSS -->
<link rel="stylesheet" href="node_modules/tacel-canva/canva.css">

<!-- Include JS -->
<script src="node_modules/tacel-canva/index.js"></script>
const { TacelCanva } = require('tacel-canva');

// Initialize the module
const canva = TacelCanva.initialize(document.getElementById('canva-container'), {
  // Current user context
  currentUserId: 'user-123',
  currentUserName: 'Pierre',
  
  // Token storage callbacks (required)
  onGetToken: async (userId) => {
    // Return stored tokens from your DB
    const tokens = await window.electron.invoke('get-canva-tokens', userId);
    return tokens; // { access_token, refresh_token, expires_at }
  },
  
  onSaveToken: async (userId, tokens) => {
    // Save tokens to your DB
    await window.electron.invoke('save-canva-tokens', { userId, tokens });
  },
  
  onRevokeToken: async (userId) => {
    // Delete tokens from your DB
    await window.electron.invoke('delete-canva-tokens', userId);
  },
  
  // Optional features (all enabled by default)
  features: {
    export: true,
    createNew: true,
    folders: true,
    search: true,
    preview: true,
    sorting: true,
    viewToggle: true,
    contextMenu: true,
    dragDrop: true,
    favorites: true,
    recentlyViewed: true,
    bulkActions: true,
    collections: true,
    themePicker: true,
    // Premium features
    brandKit: true,
    templates: true,
    scheduledExports: true,
    annotations: true,
    quickInsert: true,
    compareView: true,
    assetLibrary: true,
    analytics: true,
    batchExport: true,
    designRequests: true,
  },
  
  // Optional theming
  theme: 'default', // or any of 34 built-in themes
});

4. Handle OAuth Callback

Create a callback route in your app to handle the OAuth redirect:

// In your app's routing logic
if (window.location.pathname === '/canva/callback') {
  const urlParams = new URLSearchParams(window.location.search);
  const code = urlParams.get('code');
  
  if (code) {
    // Complete OAuth flow
    await canva.completeOAuth(code);
  }
}

Configuration

Backend Options

initCanvaApi({
  clientId: string,        // Required: Canva client ID
  clientSecret: string,    // Required: Canva client secret
  redirectUri: string,     // Required: OAuth redirect URI
  channelPrefix: string,   // Optional: IPC channel prefix (default: 'canva')
});

Frontend Options

TacelCanva.initialize(container, {
  // Required
  currentUserId: string,
  onGetToken: async (userId) => tokens,
  onSaveToken: async (userId, tokens) => void,
  onRevokeToken: async (userId) => void,
  
  // Optional
  currentUserName: string,
  features: {
    export: boolean,      // Default: true
    createNew: boolean,   // Default: true
    folders: boolean,     // Default: true
    search: boolean,      // Default: true
  },
  theme: string,          // Default: 'default'
  channelPrefix: string,  // Default: 'canva'
});

Theming

Override CSS variables to match your app's theme:

.tacel-canva {
  --tc-primary: #00c4cc;
  --tc-primary-hover: #00a8b0;
  --tc-bg: #ffffff;
  --tc-bg-secondary: #f5f5f5;
  --tc-border: #e0e0e0;
  --tc-text: #333333;
  --tc-text-muted: #666666;
  --tc-shadow: rgba(0, 0, 0, 0.1);
  --tc-border-radius: 8px;
  --tc-spacing: 16px;
}

Example: Wire-Scheduler Theme

.tacel-canva {
  --tc-primary: #4a90e2;
  --tc-primary-hover: #357abd;
  --tc-bg: #1e1e1e;
  --tc-bg-secondary: #2a2a2a;
  --tc-border: #3a3a3a;
  --tc-text: #ffffff;
  --tc-text-muted: #b0b0b0;
}

API Reference

Frontend Methods

TacelCanva.initialize(container, config)

Initialize the Canva module in a container element.

canva.completeOAuth(code)

Complete the OAuth flow with the authorization code from the callback.

canva.destroy()

Clean up the module and remove all event listeners.

IPC Channels

All channels are prefixed with your configured channelPrefix (default: canva):

  • canva:get-auth-url - Get OAuth authorization URL
  • canva:exchange-token - Exchange authorization code for tokens
  • canva:refresh-token - Refresh access token
  • canva:list-designs - List user's designs
  • canva:get-design - Get design details
  • canva:export-design - Export design to file
  • canva:get-export - Get export job status
  • canva:list-folders - List user's folders
  • canva:revoke-token - Revoke access token

Token Storage

The module does NOT store tokens itself. You must implement token storage in your app's database.

Example Token Schema

CREATE TABLE canva_tokens (
  user_id VARCHAR(255) PRIMARY KEY,
  access_token TEXT NOT NULL,
  refresh_token TEXT NOT NULL,
  expires_at BIGINT NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
);

Example IPC Handlers

// In your app's main.js
ipcMain.handle('get-canva-tokens', async (event, userId) => {
  const row = await db.query('SELECT * FROM canva_tokens WHERE user_id = ?', [userId]);
  return row ? {
    access_token: row.access_token,
    refresh_token: row.refresh_token,
    expires_at: row.expires_at
  } : null;
});

ipcMain.handle('save-canva-tokens', async (event, { userId, tokens }) => {
  await db.query(
    'INSERT INTO canva_tokens (user_id, access_token, refresh_token, expires_at) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE access_token = ?, refresh_token = ?, expires_at = ?',
    [userId, tokens.access_token, tokens.refresh_token, tokens.expires_at, tokens.access_token, tokens.refresh_token, tokens.expires_at]
  );
});

ipcMain.handle('delete-canva-tokens', async (event, userId) => {
  await db.query('DELETE FROM canva_tokens WHERE user_id = ?', [userId]);
});

OAuth Flow

  1. User clicks "Connect Canva Account"
  2. Module generates PKCE challenge
  3. Module requests auth URL from backend
  4. Backend returns Canva authorization URL
  5. Module opens URL in browser
  6. User authorizes in Canva
  7. Canva redirects to your callback URL with code
  8. Your app calls canva.completeOAuth(code)
  9. Module exchanges code for tokens via backend
  10. Module saves tokens via onSaveToken callback
  11. Module loads designs and renders gallery

Canva API Limits

  • List designs: 100 requests/minute per user
  • Export design: 20 requests/minute per user
  • Thumbnails: Expire after 15 minutes
  • Edit/View URLs: Expire after 30 days

Troubleshooting

"No tokens found" error

Make sure your onGetToken callback returns tokens in the correct format:

{ access_token: string, refresh_token: string, expires_at: number }

OAuth redirect not working

Verify your redirect URI in Canva Developer Portal matches exactly:

http://localhost:3000/canva/callback

CORS errors

Token exchange must happen on the backend (Electron main process), not in the renderer. The module handles this automatically via IPC.

Designs not loading

Check that you enabled the correct scopes in Canva Developer Portal:

  • design:meta:read
  • design:content:read
  • folder:read

License

UNLICENSED - Internal use only

Keyboard Shortcuts

Press ? to view the keyboard shortcuts help modal in the app.

| Key | Action | |-----|--------| | 1 | Navigate to My Designs | | 2 | Navigate to Favorites | | 3 | Navigate to Brand Kit | | 4 | Navigate to Templates | | 5 | Navigate to Asset Library | | 6 | Navigate to Compare View | | 7 | Navigate to Scheduled Exports | | 8 | Navigate to Analytics | | 9 | Navigate to Design Requests | | / or Ctrl+F | Focus search input | | V | Toggle grid/list view | | Ctrl+A | Select all designs | | Esc | Deselect all / Close modals | | ? | Show keyboard shortcuts help |

Premium Features Guide

1. Brand Kit Access

Access your brand colors, logos, and fonts quickly.

  • Navigate via sidebar or press 3
  • Add custom brand colors with color picker
  • Copy hex codes with one click
  • Persistent storage per user

2. Design Templates Browser

Browse Canva's template library by category.

  • Navigate via sidebar or press 4
  • Click any category to open in Canva
  • Categories: Social Media, Presentations, Marketing, Documents, and more

3. Scheduled Publishing Queue

Schedule design exports for specific dates and times.

  • Navigate via sidebar or press 7
  • Click "+ Schedule Export" to add new
  • Set date, time, format, and quality
  • Cancel scheduled exports anytime
  • Persistent queue per user

4. Design Annotations & Notes

Add notes, tags, and link designs to tasks.

  • Right-click any design → "Notes & Tags"
  • Add markdown-formatted notes
  • Tag designs for organization
  • Link to task IDs for tracking
  • All annotations persist per user

5. Quick Insert to Documents

Quickly insert designs into emails and documents.

  • Right-click any design → "Quick Insert"
  • Copy image URL for embedding
  • Copy HTML snippet for emails
  • Download directly to clipboard

6. Design Comparison View

Compare up to 4 designs side-by-side.

  • Navigate via sidebar or press 6
  • Right-click designs → "Add to Compare"
  • View designs in grid layout
  • Remove individual designs or clear all

7. Asset Library Sync

Designate frequently-used designs as reusable assets.

  • Navigate via sidebar or press 5
  • Right-click designs → "Add to Asset Library"
  • Quick access to logos, icons, templates
  • Copy URLs or download assets
  • Persistent library per user

8. Design Analytics Dashboard

Track design usage, views, and exports.

  • Navigate via sidebar or press 8
  • View total designs, favorites, assets
  • See recently viewed designs
  • Track most viewed designs
  • Export history and trends

9. Batch Export with Presets

Export multiple designs with saved settings.

  • Select multiple designs (Ctrl+Click)
  • Click "Export" in toolbar
  • Choose format, quality, naming pattern
  • Save presets for future use
  • Exports all selected designs

10. Design Request System

Submit and track design requests.

  • Navigate via sidebar or press 9
  • Click "+ New Request" to submit
  • Track pending and completed requests
  • Add title, description, dimensions, deadline
  • Team collaboration feature

Built-in Themes

The module includes 34 professionally designed themes:

Light Themes: Default, Ocean, Forest, Sunset, Lavender, Rose, Mint, Peach, Sky, Coral

Dark Themes: Dark, Midnight, Forest Dark, Ocean Dark, Purple Dark, Red Dark, Teal Dark, Amber Dark, Blue Dark, Green Dark

Vibrant Themes: Neon, Cyberpunk, Retro, Pastel, Monochrome, High Contrast

App-Specific: Wire Scheduler, Office HQ, Tech Portal, ShipWorks

Applying Themes

// Via config
const canva = TacelCanva.initialize(container, {
  theme: 'ocean',
  // ... other config
});

// Programmatically
canva.setTheme('midnight');

Custom Theme

.tacel-canva {
  --tc-primary: #your-color;
  --tc-primary-hover: #your-hover-color;
  --tc-primary-light: rgba(your-color, 0.12);
  --tc-bg: #ffffff;
  --tc-bg-secondary: #f8fafc;
  --tc-border: #e2e8f0;
  --tc-text: #0f172a;
  --tc-text-muted: #64748b;
  /* ... see canva.css for all variables */
}

Advanced Configuration

Feature Data Storage

The module requires IPC handlers for storing feature data:

// In main.js
const fs = require('fs');
const path = require('path');

const DATA_DIR = path.join(app.getPath('userData'), 'canva-data');

function ensureDataDir() {
  if (!fs.existsSync(DATA_DIR)) {
    fs.mkdirSync(DATA_DIR, { recursive: true });
  }
}

function createFeatureStorage(filename) {
  const filePath = path.join(DATA_DIR, filename);
  return {
    get: async (userId) => {
      ensureDataDir();
      if (fs.existsSync(filePath)) {
        const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
        return data[userId] || null;
      }
      return null;
    },
    save: async (userId, data) => {
      ensureDataDir();
      let cache = {};
      if (fs.existsSync(filePath)) {
        cache = JSON.parse(fs.readFileSync(filePath, 'utf8'));
      }
      cache[userId] = data;
      fs.writeFileSync(filePath, JSON.stringify(cache, null, 2));
    }
  };
}

// Create storages
const brandKitStorage = createFeatureStorage('brand-kit.json');
const annotationsStorage = createFeatureStorage('annotations.json');
const assetLibraryStorage = createFeatureStorage('asset-library.json');
const analyticsStorage = createFeatureStorage('analytics.json');
const scheduledExportsStorage = createFeatureStorage('scheduled-exports.json');
const designRequestsStorage = createFeatureStorage('design-requests.json');

// Register handlers
ipcMain.handle('get-canva-brand-kit', async (event, userId) => {
  return await brandKitStorage.get(userId);
});

ipcMain.handle('save-canva-brand-kit', async (event, { userId, brandKit }) => {
  await brandKitStorage.save(userId, brandKit);
});

// Repeat for all feature storages...

Design Cache Storage

For faster loading, implement design caching:

const designsCacheStorage = createFeatureStorage('designs-cache.json');

ipcMain.handle('get-canva-designs-cache', async (event, userId) => {
  return await designsCacheStorage.get(userId);
});

ipcMain.handle('save-canva-designs-cache', async (event, { userId, designs, lastSync }) => {
  await designsCacheStorage.save(userId, { designs, lastSync, count: designs.length });
});

Complete IPC Channel Reference

Authentication Channels

  • canva:get-auth-url - Get OAuth authorization URL
  • canva:exchange-token - Exchange authorization code for tokens
  • canva:refresh-token - Refresh access token
  • canva:revoke-token - Revoke access token

Design Channels

  • canva:list-designs - List user's designs with pagination
  • canva:get-design - Get design details by ID
  • canva:export-design - Export design to file
  • canva:get-export - Get export job status

Storage Channels (App-Implemented)

  • get-canva-tokens - Retrieve stored tokens
  • save-canva-tokens - Save tokens to storage
  • delete-canva-tokens - Delete tokens from storage
  • get-canva-collections - Get user's collections
  • save-canva-collections - Save collections
  • get-canva-designs-cache - Get cached designs
  • save-canva-designs-cache - Save designs cache
  • get-canva-brand-kit - Get brand kit data
  • save-canva-brand-kit - Save brand kit data
  • get-canva-annotations - Get design annotations
  • save-canva-annotations - Save annotations
  • get-canva-asset-library - Get asset library
  • save-canva-asset-library - Save asset library
  • get-canva-analytics - Get analytics data
  • save-canva-analytics - Save analytics data
  • get-canva-scheduled-exports - Get scheduled exports
  • save-canva-scheduled-exports - Save scheduled exports
  • get-canva-design-requests - Get design requests
  • save-canva-design-requests - Save design requests
  • download-canva-design - Download design to file system

Performance Optimization

Design Caching

The module implements cache-first loading:

  1. Loads cached designs immediately for instant display
  2. Syncs with Canva API in background
  3. Updates UI when new designs are found
  4. Reduces API calls and improves perceived performance

Lazy Loading

  • Thumbnails load with loading="lazy" attribute
  • Pagination with continuation tokens
  • Load more designs on demand

Debounced Search

Search input is debounced to reduce API calls while typing.

Browser Compatibility

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • Electron 13+

Version History

v1.0.0 (Current)

  • Initial release with all premium features
  • 34 built-in themes
  • 10 productivity features
  • Keyboard shortcuts
  • Inline design editor
  • Toast notification system
  • Glassmorphism UI
  • Complete documentation

Support

For issues or questions, contact the Tacel development team.

License

UNLICENSED - Internal use only