tacel-canva 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +637 -0
- package/canva-api.js +271 -0
- package/canva.css +2928 -0
- package/canva.js +2910 -0
- package/index.js +20 -0
- package/package.json +38 -0
- package/themes.js +705 -0
- package/utils/dom.js +98 -0
- package/utils/pkce.js +57 -0
package/README.md
ADDED
|
@@ -0,0 +1,637 @@
|
|
|
1
|
+
# Tacel Canva Module - Premium Edition
|
|
2
|
+
|
|
3
|
+
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.
|
|
4
|
+
|
|
5
|
+
## ✨ Features
|
|
6
|
+
|
|
7
|
+
### Core Features
|
|
8
|
+
- ✅ **OAuth 2.0 Authentication** with PKCE (Proof Key for Code Exchange)
|
|
9
|
+
- ✅ **Premium Design Gallery** with glassmorphism effects and staggered animations
|
|
10
|
+
- ✅ **Inline Design Editor** - Edit designs without leaving the app
|
|
11
|
+
- ✅ **Export/Download** designs in multiple formats (PNG, PDF, JPG)
|
|
12
|
+
- ✅ **Custom Collections** - Organize designs into custom collections
|
|
13
|
+
- ✅ **Favorites System** - Star designs for quick access
|
|
14
|
+
- ✅ **Advanced Search** - Search with filters and sorting
|
|
15
|
+
- ✅ **34 Built-in Themes** - Professional color schemes
|
|
16
|
+
- ✅ **Keyboard Shortcuts** - Full keyboard navigation (press `?` for help)
|
|
17
|
+
- ✅ **Toast Notifications** - Elegant feedback system
|
|
18
|
+
|
|
19
|
+
### Premium Features (NEW)
|
|
20
|
+
1. **🏷️ Brand Kit Access** - Quick access to brand colors, logos, and fonts
|
|
21
|
+
2. **📋 Design Templates Browser** - Browse Canva templates by category
|
|
22
|
+
3. **📅 Scheduled Publishing Queue** - Schedule design exports for specific dates
|
|
23
|
+
4. **📝 Design Annotations & Notes** - Add notes, tags, and link to tasks
|
|
24
|
+
5. **📋 Quick Insert to Documents** - Copy URLs, HTML for emails, or download
|
|
25
|
+
6. **⚖️ Design Comparison View** - Compare up to 4 designs side-by-side
|
|
26
|
+
7. **📦 Asset Library Sync** - Designate reusable assets for quick access
|
|
27
|
+
8. **📊 Design Analytics Dashboard** - Track views, exports, and usage stats
|
|
28
|
+
9. **🎯 Batch Export with Presets** - Export multiple designs with saved settings
|
|
29
|
+
10. **💬 Design Request System** - Submit and track design requests
|
|
30
|
+
|
|
31
|
+
### UI/UX Enhancements
|
|
32
|
+
- **Glassmorphism Effects** - Blurred backgrounds on modals and menus
|
|
33
|
+
- **Gradient System** - Beautiful gradients throughout the UI
|
|
34
|
+
- **Layered Shadows** - Depth with xs, sm, md, lg, xl shadow levels
|
|
35
|
+
- **Micro-interactions** - Hover effects, staggered animations, smooth transitions
|
|
36
|
+
- **Premium Context Menus** - Right-click anywhere for quick actions
|
|
37
|
+
- **Responsive Design** - Adapts to all screen sizes
|
|
38
|
+
- **Loading Skeletons** - Shimmer effects while content loads
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install tacel-canva
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Quick Start
|
|
47
|
+
|
|
48
|
+
### 1. Register Canva Integration
|
|
49
|
+
|
|
50
|
+
Go to [Canva Developer Portal](https://www.canva.com/developers/) and create an integration:
|
|
51
|
+
- Set redirect URI: `http://localhost:3000/canva/callback`
|
|
52
|
+
- Enable scopes: `design:meta:read`, `design:content:read`, `folder:read`
|
|
53
|
+
- Save your Client ID and Client Secret
|
|
54
|
+
|
|
55
|
+
### 2. Backend Setup (main.js)
|
|
56
|
+
|
|
57
|
+
```javascript
|
|
58
|
+
const { initCanvaApi } = require('tacel-canva/canva-api');
|
|
59
|
+
|
|
60
|
+
// Initialize Canva API handlers
|
|
61
|
+
initCanvaApi({
|
|
62
|
+
clientId: process.env.CANVA_CLIENT_ID,
|
|
63
|
+
clientSecret: process.env.CANVA_CLIENT_SECRET,
|
|
64
|
+
redirectUri: 'http://localhost:3000/canva/callback',
|
|
65
|
+
channelPrefix: 'canva', // IPC channel prefix
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. Frontend Setup (renderer)
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<!-- Include CSS -->
|
|
73
|
+
<link rel="stylesheet" href="node_modules/tacel-canva/canva.css">
|
|
74
|
+
|
|
75
|
+
<!-- Include JS -->
|
|
76
|
+
<script src="node_modules/tacel-canva/index.js"></script>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```javascript
|
|
80
|
+
const { TacelCanva } = require('tacel-canva');
|
|
81
|
+
|
|
82
|
+
// Initialize the module
|
|
83
|
+
const canva = TacelCanva.initialize(document.getElementById('canva-container'), {
|
|
84
|
+
// Current user context
|
|
85
|
+
currentUserId: 'user-123',
|
|
86
|
+
currentUserName: 'Pierre',
|
|
87
|
+
|
|
88
|
+
// Token storage callbacks (required)
|
|
89
|
+
onGetToken: async (userId) => {
|
|
90
|
+
// Return stored tokens from your DB
|
|
91
|
+
const tokens = await window.electron.invoke('get-canva-tokens', userId);
|
|
92
|
+
return tokens; // { access_token, refresh_token, expires_at }
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
onSaveToken: async (userId, tokens) => {
|
|
96
|
+
// Save tokens to your DB
|
|
97
|
+
await window.electron.invoke('save-canva-tokens', { userId, tokens });
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
onRevokeToken: async (userId) => {
|
|
101
|
+
// Delete tokens from your DB
|
|
102
|
+
await window.electron.invoke('delete-canva-tokens', userId);
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
// Optional features (all enabled by default)
|
|
106
|
+
features: {
|
|
107
|
+
export: true,
|
|
108
|
+
createNew: true,
|
|
109
|
+
folders: true,
|
|
110
|
+
search: true,
|
|
111
|
+
preview: true,
|
|
112
|
+
sorting: true,
|
|
113
|
+
viewToggle: true,
|
|
114
|
+
contextMenu: true,
|
|
115
|
+
dragDrop: true,
|
|
116
|
+
favorites: true,
|
|
117
|
+
recentlyViewed: true,
|
|
118
|
+
bulkActions: true,
|
|
119
|
+
collections: true,
|
|
120
|
+
themePicker: true,
|
|
121
|
+
// Premium features
|
|
122
|
+
brandKit: true,
|
|
123
|
+
templates: true,
|
|
124
|
+
scheduledExports: true,
|
|
125
|
+
annotations: true,
|
|
126
|
+
quickInsert: true,
|
|
127
|
+
compareView: true,
|
|
128
|
+
assetLibrary: true,
|
|
129
|
+
analytics: true,
|
|
130
|
+
batchExport: true,
|
|
131
|
+
designRequests: true,
|
|
132
|
+
},
|
|
133
|
+
|
|
134
|
+
// Optional theming
|
|
135
|
+
theme: 'default', // or any of 34 built-in themes
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### 4. Handle OAuth Callback
|
|
140
|
+
|
|
141
|
+
Create a callback route in your app to handle the OAuth redirect:
|
|
142
|
+
|
|
143
|
+
```javascript
|
|
144
|
+
// In your app's routing logic
|
|
145
|
+
if (window.location.pathname === '/canva/callback') {
|
|
146
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
147
|
+
const code = urlParams.get('code');
|
|
148
|
+
|
|
149
|
+
if (code) {
|
|
150
|
+
// Complete OAuth flow
|
|
151
|
+
await canva.completeOAuth(code);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Configuration
|
|
157
|
+
|
|
158
|
+
### Backend Options
|
|
159
|
+
|
|
160
|
+
```javascript
|
|
161
|
+
initCanvaApi({
|
|
162
|
+
clientId: string, // Required: Canva client ID
|
|
163
|
+
clientSecret: string, // Required: Canva client secret
|
|
164
|
+
redirectUri: string, // Required: OAuth redirect URI
|
|
165
|
+
channelPrefix: string, // Optional: IPC channel prefix (default: 'canva')
|
|
166
|
+
});
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Frontend Options
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
TacelCanva.initialize(container, {
|
|
173
|
+
// Required
|
|
174
|
+
currentUserId: string,
|
|
175
|
+
onGetToken: async (userId) => tokens,
|
|
176
|
+
onSaveToken: async (userId, tokens) => void,
|
|
177
|
+
onRevokeToken: async (userId) => void,
|
|
178
|
+
|
|
179
|
+
// Optional
|
|
180
|
+
currentUserName: string,
|
|
181
|
+
features: {
|
|
182
|
+
export: boolean, // Default: true
|
|
183
|
+
createNew: boolean, // Default: true
|
|
184
|
+
folders: boolean, // Default: true
|
|
185
|
+
search: boolean, // Default: true
|
|
186
|
+
},
|
|
187
|
+
theme: string, // Default: 'default'
|
|
188
|
+
channelPrefix: string, // Default: 'canva'
|
|
189
|
+
});
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Theming
|
|
193
|
+
|
|
194
|
+
Override CSS variables to match your app's theme:
|
|
195
|
+
|
|
196
|
+
```css
|
|
197
|
+
.tacel-canva {
|
|
198
|
+
--tc-primary: #00c4cc;
|
|
199
|
+
--tc-primary-hover: #00a8b0;
|
|
200
|
+
--tc-bg: #ffffff;
|
|
201
|
+
--tc-bg-secondary: #f5f5f5;
|
|
202
|
+
--tc-border: #e0e0e0;
|
|
203
|
+
--tc-text: #333333;
|
|
204
|
+
--tc-text-muted: #666666;
|
|
205
|
+
--tc-shadow: rgba(0, 0, 0, 0.1);
|
|
206
|
+
--tc-border-radius: 8px;
|
|
207
|
+
--tc-spacing: 16px;
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Example: Wire-Scheduler Theme
|
|
212
|
+
|
|
213
|
+
```css
|
|
214
|
+
.tacel-canva {
|
|
215
|
+
--tc-primary: #4a90e2;
|
|
216
|
+
--tc-primary-hover: #357abd;
|
|
217
|
+
--tc-bg: #1e1e1e;
|
|
218
|
+
--tc-bg-secondary: #2a2a2a;
|
|
219
|
+
--tc-border: #3a3a3a;
|
|
220
|
+
--tc-text: #ffffff;
|
|
221
|
+
--tc-text-muted: #b0b0b0;
|
|
222
|
+
}
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## API Reference
|
|
226
|
+
|
|
227
|
+
### Frontend Methods
|
|
228
|
+
|
|
229
|
+
#### `TacelCanva.initialize(container, config)`
|
|
230
|
+
Initialize the Canva module in a container element.
|
|
231
|
+
|
|
232
|
+
#### `canva.completeOAuth(code)`
|
|
233
|
+
Complete the OAuth flow with the authorization code from the callback.
|
|
234
|
+
|
|
235
|
+
#### `canva.destroy()`
|
|
236
|
+
Clean up the module and remove all event listeners.
|
|
237
|
+
|
|
238
|
+
### IPC Channels
|
|
239
|
+
|
|
240
|
+
All channels are prefixed with your configured `channelPrefix` (default: `canva`):
|
|
241
|
+
|
|
242
|
+
- `canva:get-auth-url` - Get OAuth authorization URL
|
|
243
|
+
- `canva:exchange-token` - Exchange authorization code for tokens
|
|
244
|
+
- `canva:refresh-token` - Refresh access token
|
|
245
|
+
- `canva:list-designs` - List user's designs
|
|
246
|
+
- `canva:get-design` - Get design details
|
|
247
|
+
- `canva:export-design` - Export design to file
|
|
248
|
+
- `canva:get-export` - Get export job status
|
|
249
|
+
- `canva:list-folders` - List user's folders
|
|
250
|
+
- `canva:revoke-token` - Revoke access token
|
|
251
|
+
|
|
252
|
+
## Token Storage
|
|
253
|
+
|
|
254
|
+
The module does NOT store tokens itself. You must implement token storage in your app's database.
|
|
255
|
+
|
|
256
|
+
### Example Token Schema
|
|
257
|
+
|
|
258
|
+
```sql
|
|
259
|
+
CREATE TABLE canva_tokens (
|
|
260
|
+
user_id VARCHAR(255) PRIMARY KEY,
|
|
261
|
+
access_token TEXT NOT NULL,
|
|
262
|
+
refresh_token TEXT NOT NULL,
|
|
263
|
+
expires_at BIGINT NOT NULL,
|
|
264
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
265
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
|
|
266
|
+
);
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Example IPC Handlers
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
// In your app's main.js
|
|
273
|
+
ipcMain.handle('get-canva-tokens', async (event, userId) => {
|
|
274
|
+
const row = await db.query('SELECT * FROM canva_tokens WHERE user_id = ?', [userId]);
|
|
275
|
+
return row ? {
|
|
276
|
+
access_token: row.access_token,
|
|
277
|
+
refresh_token: row.refresh_token,
|
|
278
|
+
expires_at: row.expires_at
|
|
279
|
+
} : null;
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
ipcMain.handle('save-canva-tokens', async (event, { userId, tokens }) => {
|
|
283
|
+
await db.query(
|
|
284
|
+
'INSERT INTO canva_tokens (user_id, access_token, refresh_token, expires_at) VALUES (?, ?, ?, ?) ON DUPLICATE KEY UPDATE access_token = ?, refresh_token = ?, expires_at = ?',
|
|
285
|
+
[userId, tokens.access_token, tokens.refresh_token, tokens.expires_at, tokens.access_token, tokens.refresh_token, tokens.expires_at]
|
|
286
|
+
);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
ipcMain.handle('delete-canva-tokens', async (event, userId) => {
|
|
290
|
+
await db.query('DELETE FROM canva_tokens WHERE user_id = ?', [userId]);
|
|
291
|
+
});
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## OAuth Flow
|
|
295
|
+
|
|
296
|
+
1. User clicks "Connect Canva Account"
|
|
297
|
+
2. Module generates PKCE challenge
|
|
298
|
+
3. Module requests auth URL from backend
|
|
299
|
+
4. Backend returns Canva authorization URL
|
|
300
|
+
5. Module opens URL in browser
|
|
301
|
+
6. User authorizes in Canva
|
|
302
|
+
7. Canva redirects to your callback URL with code
|
|
303
|
+
8. Your app calls `canva.completeOAuth(code)`
|
|
304
|
+
9. Module exchanges code for tokens via backend
|
|
305
|
+
10. Module saves tokens via `onSaveToken` callback
|
|
306
|
+
11. Module loads designs and renders gallery
|
|
307
|
+
|
|
308
|
+
## Canva API Limits
|
|
309
|
+
|
|
310
|
+
- **List designs**: 100 requests/minute per user
|
|
311
|
+
- **Export design**: 20 requests/minute per user
|
|
312
|
+
- **Thumbnails**: Expire after 15 minutes
|
|
313
|
+
- **Edit/View URLs**: Expire after 30 days
|
|
314
|
+
|
|
315
|
+
## Troubleshooting
|
|
316
|
+
|
|
317
|
+
### "No tokens found" error
|
|
318
|
+
Make sure your `onGetToken` callback returns tokens in the correct format:
|
|
319
|
+
```javascript
|
|
320
|
+
{ access_token: string, refresh_token: string, expires_at: number }
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### OAuth redirect not working
|
|
324
|
+
Verify your redirect URI in Canva Developer Portal matches exactly:
|
|
325
|
+
```
|
|
326
|
+
http://localhost:3000/canva/callback
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
### CORS errors
|
|
330
|
+
Token exchange must happen on the backend (Electron main process), not in the renderer. The module handles this automatically via IPC.
|
|
331
|
+
|
|
332
|
+
### Designs not loading
|
|
333
|
+
Check that you enabled the correct scopes in Canva Developer Portal:
|
|
334
|
+
- `design:meta:read`
|
|
335
|
+
- `design:content:read`
|
|
336
|
+
- `folder:read`
|
|
337
|
+
|
|
338
|
+
## License
|
|
339
|
+
|
|
340
|
+
UNLICENSED - Internal use only
|
|
341
|
+
|
|
342
|
+
## Keyboard Shortcuts
|
|
343
|
+
|
|
344
|
+
Press `?` to view the keyboard shortcuts help modal in the app.
|
|
345
|
+
|
|
346
|
+
| Key | Action |
|
|
347
|
+
|-----|--------|
|
|
348
|
+
| `1` | Navigate to My Designs |
|
|
349
|
+
| `2` | Navigate to Favorites |
|
|
350
|
+
| `3` | Navigate to Brand Kit |
|
|
351
|
+
| `4` | Navigate to Templates |
|
|
352
|
+
| `5` | Navigate to Asset Library |
|
|
353
|
+
| `6` | Navigate to Compare View |
|
|
354
|
+
| `7` | Navigate to Scheduled Exports |
|
|
355
|
+
| `8` | Navigate to Analytics |
|
|
356
|
+
| `9` | Navigate to Design Requests |
|
|
357
|
+
| `/` or `Ctrl+F` | Focus search input |
|
|
358
|
+
| `V` | Toggle grid/list view |
|
|
359
|
+
| `Ctrl+A` | Select all designs |
|
|
360
|
+
| `Esc` | Deselect all / Close modals |
|
|
361
|
+
| `?` | Show keyboard shortcuts help |
|
|
362
|
+
|
|
363
|
+
## Premium Features Guide
|
|
364
|
+
|
|
365
|
+
### 1. Brand Kit Access
|
|
366
|
+
Access your brand colors, logos, and fonts quickly.
|
|
367
|
+
- Navigate via sidebar or press `3`
|
|
368
|
+
- Add custom brand colors with color picker
|
|
369
|
+
- Copy hex codes with one click
|
|
370
|
+
- Persistent storage per user
|
|
371
|
+
|
|
372
|
+
### 2. Design Templates Browser
|
|
373
|
+
Browse Canva's template library by category.
|
|
374
|
+
- Navigate via sidebar or press `4`
|
|
375
|
+
- Click any category to open in Canva
|
|
376
|
+
- Categories: Social Media, Presentations, Marketing, Documents, and more
|
|
377
|
+
|
|
378
|
+
### 3. Scheduled Publishing Queue
|
|
379
|
+
Schedule design exports for specific dates and times.
|
|
380
|
+
- Navigate via sidebar or press `7`
|
|
381
|
+
- Click "+ Schedule Export" to add new
|
|
382
|
+
- Set date, time, format, and quality
|
|
383
|
+
- Cancel scheduled exports anytime
|
|
384
|
+
- Persistent queue per user
|
|
385
|
+
|
|
386
|
+
### 4. Design Annotations & Notes
|
|
387
|
+
Add notes, tags, and link designs to tasks.
|
|
388
|
+
- Right-click any design → "Notes & Tags"
|
|
389
|
+
- Add markdown-formatted notes
|
|
390
|
+
- Tag designs for organization
|
|
391
|
+
- Link to task IDs for tracking
|
|
392
|
+
- All annotations persist per user
|
|
393
|
+
|
|
394
|
+
### 5. Quick Insert to Documents
|
|
395
|
+
Quickly insert designs into emails and documents.
|
|
396
|
+
- Right-click any design → "Quick Insert"
|
|
397
|
+
- Copy image URL for embedding
|
|
398
|
+
- Copy HTML snippet for emails
|
|
399
|
+
- Download directly to clipboard
|
|
400
|
+
|
|
401
|
+
### 6. Design Comparison View
|
|
402
|
+
Compare up to 4 designs side-by-side.
|
|
403
|
+
- Navigate via sidebar or press `6`
|
|
404
|
+
- Right-click designs → "Add to Compare"
|
|
405
|
+
- View designs in grid layout
|
|
406
|
+
- Remove individual designs or clear all
|
|
407
|
+
|
|
408
|
+
### 7. Asset Library Sync
|
|
409
|
+
Designate frequently-used designs as reusable assets.
|
|
410
|
+
- Navigate via sidebar or press `5`
|
|
411
|
+
- Right-click designs → "Add to Asset Library"
|
|
412
|
+
- Quick access to logos, icons, templates
|
|
413
|
+
- Copy URLs or download assets
|
|
414
|
+
- Persistent library per user
|
|
415
|
+
|
|
416
|
+
### 8. Design Analytics Dashboard
|
|
417
|
+
Track design usage, views, and exports.
|
|
418
|
+
- Navigate via sidebar or press `8`
|
|
419
|
+
- View total designs, favorites, assets
|
|
420
|
+
- See recently viewed designs
|
|
421
|
+
- Track most viewed designs
|
|
422
|
+
- Export history and trends
|
|
423
|
+
|
|
424
|
+
### 9. Batch Export with Presets
|
|
425
|
+
Export multiple designs with saved settings.
|
|
426
|
+
- Select multiple designs (Ctrl+Click)
|
|
427
|
+
- Click "Export" in toolbar
|
|
428
|
+
- Choose format, quality, naming pattern
|
|
429
|
+
- Save presets for future use
|
|
430
|
+
- Exports all selected designs
|
|
431
|
+
|
|
432
|
+
### 10. Design Request System
|
|
433
|
+
Submit and track design requests.
|
|
434
|
+
- Navigate via sidebar or press `9`
|
|
435
|
+
- Click "+ New Request" to submit
|
|
436
|
+
- Track pending and completed requests
|
|
437
|
+
- Add title, description, dimensions, deadline
|
|
438
|
+
- Team collaboration feature
|
|
439
|
+
|
|
440
|
+
## Built-in Themes
|
|
441
|
+
|
|
442
|
+
The module includes 34 professionally designed themes:
|
|
443
|
+
|
|
444
|
+
**Light Themes:** Default, Ocean, Forest, Sunset, Lavender, Rose, Mint, Peach, Sky, Coral
|
|
445
|
+
|
|
446
|
+
**Dark Themes:** Dark, Midnight, Forest Dark, Ocean Dark, Purple Dark, Red Dark, Teal Dark, Amber Dark, Blue Dark, Green Dark
|
|
447
|
+
|
|
448
|
+
**Vibrant Themes:** Neon, Cyberpunk, Retro, Pastel, Monochrome, High Contrast
|
|
449
|
+
|
|
450
|
+
**App-Specific:** Wire Scheduler, Office HQ, Tech Portal, ShipWorks
|
|
451
|
+
|
|
452
|
+
### Applying Themes
|
|
453
|
+
|
|
454
|
+
```javascript
|
|
455
|
+
// Via config
|
|
456
|
+
const canva = TacelCanva.initialize(container, {
|
|
457
|
+
theme: 'ocean',
|
|
458
|
+
// ... other config
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
// Programmatically
|
|
462
|
+
canva.setTheme('midnight');
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Custom Theme
|
|
466
|
+
|
|
467
|
+
```css
|
|
468
|
+
.tacel-canva {
|
|
469
|
+
--tc-primary: #your-color;
|
|
470
|
+
--tc-primary-hover: #your-hover-color;
|
|
471
|
+
--tc-primary-light: rgba(your-color, 0.12);
|
|
472
|
+
--tc-bg: #ffffff;
|
|
473
|
+
--tc-bg-secondary: #f8fafc;
|
|
474
|
+
--tc-border: #e2e8f0;
|
|
475
|
+
--tc-text: #0f172a;
|
|
476
|
+
--tc-text-muted: #64748b;
|
|
477
|
+
/* ... see canva.css for all variables */
|
|
478
|
+
}
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Advanced Configuration
|
|
482
|
+
|
|
483
|
+
### Feature Data Storage
|
|
484
|
+
|
|
485
|
+
The module requires IPC handlers for storing feature data:
|
|
486
|
+
|
|
487
|
+
```javascript
|
|
488
|
+
// In main.js
|
|
489
|
+
const fs = require('fs');
|
|
490
|
+
const path = require('path');
|
|
491
|
+
|
|
492
|
+
const DATA_DIR = path.join(app.getPath('userData'), 'canva-data');
|
|
493
|
+
|
|
494
|
+
function ensureDataDir() {
|
|
495
|
+
if (!fs.existsSync(DATA_DIR)) {
|
|
496
|
+
fs.mkdirSync(DATA_DIR, { recursive: true });
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function createFeatureStorage(filename) {
|
|
501
|
+
const filePath = path.join(DATA_DIR, filename);
|
|
502
|
+
return {
|
|
503
|
+
get: async (userId) => {
|
|
504
|
+
ensureDataDir();
|
|
505
|
+
if (fs.existsSync(filePath)) {
|
|
506
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
507
|
+
return data[userId] || null;
|
|
508
|
+
}
|
|
509
|
+
return null;
|
|
510
|
+
},
|
|
511
|
+
save: async (userId, data) => {
|
|
512
|
+
ensureDataDir();
|
|
513
|
+
let cache = {};
|
|
514
|
+
if (fs.existsSync(filePath)) {
|
|
515
|
+
cache = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
516
|
+
}
|
|
517
|
+
cache[userId] = data;
|
|
518
|
+
fs.writeFileSync(filePath, JSON.stringify(cache, null, 2));
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// Create storages
|
|
524
|
+
const brandKitStorage = createFeatureStorage('brand-kit.json');
|
|
525
|
+
const annotationsStorage = createFeatureStorage('annotations.json');
|
|
526
|
+
const assetLibraryStorage = createFeatureStorage('asset-library.json');
|
|
527
|
+
const analyticsStorage = createFeatureStorage('analytics.json');
|
|
528
|
+
const scheduledExportsStorage = createFeatureStorage('scheduled-exports.json');
|
|
529
|
+
const designRequestsStorage = createFeatureStorage('design-requests.json');
|
|
530
|
+
|
|
531
|
+
// Register handlers
|
|
532
|
+
ipcMain.handle('get-canva-brand-kit', async (event, userId) => {
|
|
533
|
+
return await brandKitStorage.get(userId);
|
|
534
|
+
});
|
|
535
|
+
|
|
536
|
+
ipcMain.handle('save-canva-brand-kit', async (event, { userId, brandKit }) => {
|
|
537
|
+
await brandKitStorage.save(userId, brandKit);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
// Repeat for all feature storages...
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Design Cache Storage
|
|
544
|
+
|
|
545
|
+
For faster loading, implement design caching:
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
const designsCacheStorage = createFeatureStorage('designs-cache.json');
|
|
549
|
+
|
|
550
|
+
ipcMain.handle('get-canva-designs-cache', async (event, userId) => {
|
|
551
|
+
return await designsCacheStorage.get(userId);
|
|
552
|
+
});
|
|
553
|
+
|
|
554
|
+
ipcMain.handle('save-canva-designs-cache', async (event, { userId, designs, lastSync }) => {
|
|
555
|
+
await designsCacheStorage.save(userId, { designs, lastSync, count: designs.length });
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
## Complete IPC Channel Reference
|
|
560
|
+
|
|
561
|
+
### Authentication Channels
|
|
562
|
+
- `canva:get-auth-url` - Get OAuth authorization URL
|
|
563
|
+
- `canva:exchange-token` - Exchange authorization code for tokens
|
|
564
|
+
- `canva:refresh-token` - Refresh access token
|
|
565
|
+
- `canva:revoke-token` - Revoke access token
|
|
566
|
+
|
|
567
|
+
### Design Channels
|
|
568
|
+
- `canva:list-designs` - List user's designs with pagination
|
|
569
|
+
- `canva:get-design` - Get design details by ID
|
|
570
|
+
- `canva:export-design` - Export design to file
|
|
571
|
+
- `canva:get-export` - Get export job status
|
|
572
|
+
|
|
573
|
+
### Storage Channels (App-Implemented)
|
|
574
|
+
- `get-canva-tokens` - Retrieve stored tokens
|
|
575
|
+
- `save-canva-tokens` - Save tokens to storage
|
|
576
|
+
- `delete-canva-tokens` - Delete tokens from storage
|
|
577
|
+
- `get-canva-collections` - Get user's collections
|
|
578
|
+
- `save-canva-collections` - Save collections
|
|
579
|
+
- `get-canva-designs-cache` - Get cached designs
|
|
580
|
+
- `save-canva-designs-cache` - Save designs cache
|
|
581
|
+
- `get-canva-brand-kit` - Get brand kit data
|
|
582
|
+
- `save-canva-brand-kit` - Save brand kit data
|
|
583
|
+
- `get-canva-annotations` - Get design annotations
|
|
584
|
+
- `save-canva-annotations` - Save annotations
|
|
585
|
+
- `get-canva-asset-library` - Get asset library
|
|
586
|
+
- `save-canva-asset-library` - Save asset library
|
|
587
|
+
- `get-canva-analytics` - Get analytics data
|
|
588
|
+
- `save-canva-analytics` - Save analytics data
|
|
589
|
+
- `get-canva-scheduled-exports` - Get scheduled exports
|
|
590
|
+
- `save-canva-scheduled-exports` - Save scheduled exports
|
|
591
|
+
- `get-canva-design-requests` - Get design requests
|
|
592
|
+
- `save-canva-design-requests` - Save design requests
|
|
593
|
+
- `download-canva-design` - Download design to file system
|
|
594
|
+
|
|
595
|
+
## Performance Optimization
|
|
596
|
+
|
|
597
|
+
### Design Caching
|
|
598
|
+
The module implements cache-first loading:
|
|
599
|
+
1. Loads cached designs immediately for instant display
|
|
600
|
+
2. Syncs with Canva API in background
|
|
601
|
+
3. Updates UI when new designs are found
|
|
602
|
+
4. Reduces API calls and improves perceived performance
|
|
603
|
+
|
|
604
|
+
### Lazy Loading
|
|
605
|
+
- Thumbnails load with `loading="lazy"` attribute
|
|
606
|
+
- Pagination with continuation tokens
|
|
607
|
+
- Load more designs on demand
|
|
608
|
+
|
|
609
|
+
### Debounced Search
|
|
610
|
+
Search input is debounced to reduce API calls while typing.
|
|
611
|
+
|
|
612
|
+
## Browser Compatibility
|
|
613
|
+
|
|
614
|
+
- Chrome/Edge 90+
|
|
615
|
+
- Firefox 88+
|
|
616
|
+
- Safari 14+
|
|
617
|
+
- Electron 13+
|
|
618
|
+
|
|
619
|
+
## Version History
|
|
620
|
+
|
|
621
|
+
### v1.0.0 (Current)
|
|
622
|
+
- Initial release with all premium features
|
|
623
|
+
- 34 built-in themes
|
|
624
|
+
- 10 productivity features
|
|
625
|
+
- Keyboard shortcuts
|
|
626
|
+
- Inline design editor
|
|
627
|
+
- Toast notification system
|
|
628
|
+
- Glassmorphism UI
|
|
629
|
+
- Complete documentation
|
|
630
|
+
|
|
631
|
+
## Support
|
|
632
|
+
|
|
633
|
+
For issues or questions, contact the Tacel development team.
|
|
634
|
+
|
|
635
|
+
## License
|
|
636
|
+
|
|
637
|
+
UNLICENSED - Internal use only
|