@trishchuk/coolors-mcp 1.0.1 → 1.1.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.
Files changed (105) hide show
  1. package/.github/workflows/ci.yml +23 -20
  2. package/.github/workflows/deploy-docs.yml +6 -3
  3. package/.github/workflows/release.yml +11 -9
  4. package/README.md +123 -14
  5. package/dist/bin/server.js +997 -256
  6. package/dist/bin/server.js.map +1 -1
  7. package/dist/{chunk-P3ARRKLS.js → chunk-HOMDMKUY.js} +3 -1
  8. package/dist/{chunk-P3ARRKLS.js.map → chunk-HOMDMKUY.js.map} +1 -1
  9. package/dist/{chunk-IQ7NN26V.js → chunk-LHW2ZTOU.js} +14 -2
  10. package/dist/chunk-LHW2ZTOU.js.map +1 -0
  11. package/dist/color/index.js +1 -1
  12. package/dist/coolors-mcp.d.ts +4 -4
  13. package/dist/coolors-mcp.js +1 -1
  14. package/eslint.config.ts +13 -0
  15. package/jsr.json +1 -1
  16. package/package.json +16 -12
  17. package/src/bin/server.ts +13 -1
  18. package/src/color/__tests__/extract-colors.test.ts +20 -30
  19. package/src/color/apca.ts +105 -0
  20. package/src/color/color-blindness.ts +109 -0
  21. package/src/coolors-mcp.ts +1 -1
  22. package/src/session.ts +10 -2
  23. package/src/theme/matcher.ts +1 -1
  24. package/src/theme/refactor.ts +1 -1
  25. package/src/theme/types.ts +3 -0
  26. package/src/tools/__tests__/cohesion.test.ts +97 -0
  27. package/src/tools/__tests__/color-blindness.test.ts +45 -0
  28. package/src/tools/__tests__/color-conversion.test.ts +38 -0
  29. package/src/tools/__tests__/contrast-checker.test.ts +56 -0
  30. package/src/tools/__tests__/palette-export.test.ts +54 -0
  31. package/src/tools/adjust-color.tool.ts +80 -0
  32. package/src/tools/cohesion.tools.ts +380 -0
  33. package/src/tools/color-blindness.tool.ts +168 -0
  34. package/src/tools/color-conversion.tool.ts +1 -1
  35. package/src/tools/contrast-checker.tool.ts +53 -14
  36. package/src/tools/dislike-analyzer.tool.ts +41 -54
  37. package/src/tools/image-extraction.tools.ts +62 -115
  38. package/src/tools/index.ts +15 -2
  39. package/src/tools/palette-export.tool.ts +174 -0
  40. package/src/tools/palette-with-locks.tool.ts +8 -6
  41. package/src/types.ts +2 -3
  42. package/tsconfig.json +12 -2
  43. package/vitest.config.js +1 -3
  44. package/.claude/settings.local.json +0 -35
  45. package/.env +0 -2
  46. package/.mcp.json +0 -12
  47. package/CLAUDE.md +0 -201
  48. package/DOCUMENTATION.md +0 -274
  49. package/GEMINI.md +0 -54
  50. package/TOOLS_UK.md +0 -233
  51. package/demo/content_based_color.png +0 -0
  52. package/demo/music-player.html +0 -621
  53. package/demo/podcast-player.html +0 -903
  54. package/dist/chunk-IQ7NN26V.js.map +0 -1
  55. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +0 -111
  56. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +0 -7
  57. package/docs/.vitepress/cache/deps/_metadata.json +0 -127
  58. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +0 -12
  59. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +0 -7
  60. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +0 -13614
  61. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +0 -7
  62. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +0 -10698
  63. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +0 -7
  64. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +0 -5609
  65. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +0 -7
  66. package/docs/.vitepress/cache/deps/cytoscape.js +0 -36234
  67. package/docs/.vitepress/cache/deps/cytoscape.js.map +0 -7
  68. package/docs/.vitepress/cache/deps/dayjs.js +0 -507
  69. package/docs/.vitepress/cache/deps/dayjs.js.map +0 -7
  70. package/docs/.vitepress/cache/deps/debug.js +0 -512
  71. package/docs/.vitepress/cache/deps/debug.js.map +0 -7
  72. package/docs/.vitepress/cache/deps/package.json +0 -3
  73. package/docs/.vitepress/cache/deps/prismjs.js +0 -1638
  74. package/docs/.vitepress/cache/deps/prismjs.js.map +0 -7
  75. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +0 -235
  76. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +0 -7
  77. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +0 -173
  78. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +0 -7
  79. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +0 -27
  80. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +0 -7
  81. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +0 -72
  82. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +0 -7
  83. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +0 -56
  84. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +0 -7
  85. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +0 -107
  86. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +0 -7
  87. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -5074
  88. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
  89. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -584
  90. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
  91. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +0 -1483
  92. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +0 -7
  93. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +0 -1779
  94. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +0 -7
  95. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +0 -2023
  96. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +0 -7
  97. package/docs/.vitepress/cache/deps/vue.js +0 -344
  98. package/docs/.vitepress/cache/deps/vue.js.map +0 -7
  99. package/examples/theme-matching.md +0 -113
  100. package/mcp-config.json +0 -8
  101. package/note.md +0 -34
  102. package/research_results.md +0 -53
  103. package/src/tools/colors.ts +0 -31
  104. package/src/tools/registry.ts +0 -142
  105. package/src/tools/simple-tools.ts +0 -37
@@ -1,903 +0,0 @@
1
- <!doctype html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8" />
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
- <title>Podcast Player with Chapters - Content-Based Colors</title>
7
- <style>
8
- :root {
9
- /* Material Design 3 - Generated from podcast cover */
10
- --md-sys-color-primary: #7c4dff;
11
- --md-sys-color-on-primary: #ffffff;
12
- --md-sys-color-primary-container: #e1d5ff;
13
- --md-sys-color-on-primary-container: #21005d;
14
-
15
- --md-sys-color-secondary: #625b71;
16
- --md-sys-color-on-secondary: #ffffff;
17
- --md-sys-color-secondary-container: #e8def8;
18
- --md-sys-color-on-secondary-container: #1d192b;
19
-
20
- --md-sys-color-tertiary: #7d5260;
21
- --md-sys-color-on-tertiary: #ffffff;
22
- --md-sys-color-tertiary-container: #ffd8e4;
23
- --md-sys-color-on-tertiary-container: #31111d;
24
-
25
- --md-sys-color-background: #fdfbff;
26
- --md-sys-color-on-background: #1c1b1f;
27
- --md-sys-color-surface: #fdfbff;
28
- --md-sys-color-on-surface: #1c1b1f;
29
- --md-sys-color-surface-variant: #e7e0ec;
30
- --md-sys-color-on-surface-variant: #49454f;
31
-
32
- --md-sys-color-outline: #79747e;
33
- --md-sys-color-outline-variant: #cac4d0;
34
-
35
- --md-sys-color-surface-container: #f4eff7;
36
- --md-sys-color-surface-container-high: #ece7f0;
37
- --md-sys-color-surface-container-highest: #e7e0ec;
38
- }
39
-
40
- @media (prefers-color-scheme: dark) {
41
- :root {
42
- --md-sys-color-primary: #c9a8ff;
43
- --md-sys-color-on-primary: #370093;
44
- --md-sys-color-primary-container: #5029ca;
45
- --md-sys-color-on-primary-container: #e1d5ff;
46
-
47
- --md-sys-color-secondary: #ccc2dc;
48
- --md-sys-color-on-secondary: #332d41;
49
- --md-sys-color-secondary-container: #4a4459;
50
- --md-sys-color-on-secondary-container: #e8def8;
51
-
52
- --md-sys-color-tertiary: #efb8c8;
53
- --md-sys-color-on-tertiary: #492532;
54
- --md-sys-color-tertiary-container: #633b48;
55
- --md-sys-color-on-tertiary-container: #ffd8e4;
56
-
57
- --md-sys-color-background: #141318;
58
- --md-sys-color-on-background: #e6e1e5;
59
- --md-sys-color-surface: #1c1b1f;
60
- --md-sys-color-on-surface: #e6e1e5;
61
- --md-sys-color-surface-variant: #49454f;
62
- --md-sys-color-on-surface-variant: #cac4d0;
63
-
64
- --md-sys-color-outline: #938f99;
65
- --md-sys-color-outline-variant: #49454f;
66
-
67
- --md-sys-color-surface-container: #211f26;
68
- --md-sys-color-surface-container-high: #2b2930;
69
- --md-sys-color-surface-container-highest: #36343b;
70
- }
71
- }
72
-
73
- * {
74
- margin: 0;
75
- padding: 0;
76
- box-sizing: border-box;
77
- }
78
-
79
- body {
80
- font-family:
81
- -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu,
82
- sans-serif;
83
- background: var(--md-sys-color-background);
84
- color: var(--md-sys-color-on-background);
85
- min-height: 100vh;
86
- display: flex;
87
- justify-content: center;
88
- align-items: center;
89
- padding: 20px;
90
- background: linear-gradient(
91
- 135deg,
92
- var(--md-sys-color-primary-container) 0%,
93
- var(--md-sys-color-secondary-container) 50%,
94
- var(--md-sys-color-tertiary-container) 100%
95
- );
96
- }
97
-
98
- .container {
99
- width: 100%;
100
- max-width: 480px;
101
- background: var(--md-sys-color-surface);
102
- border-radius: 28px;
103
- box-shadow:
104
- 0 10px 40px rgba(0, 0, 0, 0.2),
105
- 0 0 0 1px var(--md-sys-color-outline-variant);
106
- overflow: hidden;
107
- }
108
-
109
- .player-section {
110
- padding: 24px;
111
- background: var(--md-sys-color-surface);
112
- border-bottom: 1px solid var(--md-sys-color-outline-variant);
113
- }
114
-
115
- .podcast-header {
116
- display: flex;
117
- gap: 16px;
118
- margin-bottom: 24px;
119
- }
120
-
121
- .podcast-cover {
122
- width: 120px;
123
- height: 120px;
124
- border-radius: 16px;
125
- background: linear-gradient(
126
- 135deg,
127
- var(--md-sys-color-primary),
128
- var(--md-sys-color-secondary)
129
- );
130
- display: flex;
131
- align-items: center;
132
- justify-content: center;
133
- font-size: 48px;
134
- color: var(--md-sys-color-on-primary);
135
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
136
- position: relative;
137
- overflow: hidden;
138
- }
139
-
140
- .cover-pattern {
141
- position: absolute;
142
- inset: 0;
143
- opacity: 0.3;
144
- background-image:
145
- repeating-linear-gradient(
146
- 45deg,
147
- transparent,
148
- transparent 10px,
149
- rgba(255, 255, 255, 0.1) 10px,
150
- rgba(255, 255, 255, 0.1) 20px
151
- ),
152
- repeating-linear-gradient(
153
- -45deg,
154
- transparent,
155
- transparent 10px,
156
- rgba(0, 0, 0, 0.1) 10px,
157
- rgba(0, 0, 0, 0.1) 20px
158
- );
159
- }
160
-
161
- .podcast-info {
162
- flex: 1;
163
- display: flex;
164
- flex-direction: column;
165
- justify-content: center;
166
- }
167
-
168
- .podcast-title {
169
- font-size: 20px;
170
- font-weight: 600;
171
- color: var(--md-sys-color-on-surface);
172
- margin-bottom: 4px;
173
- }
174
-
175
- .podcast-author {
176
- font-size: 14px;
177
- color: var(--md-sys-color-on-surface-variant);
178
- margin-bottom: 8px;
179
- }
180
-
181
- .episode-title {
182
- font-size: 16px;
183
- color: var(--md-sys-color-primary);
184
- font-weight: 500;
185
- }
186
-
187
- .waveform-container {
188
- height: 60px;
189
- margin-bottom: 16px;
190
- background: var(--md-sys-color-surface-container);
191
- border-radius: 8px;
192
- padding: 8px;
193
- position: relative;
194
- overflow: hidden;
195
- }
196
-
197
- .waveform {
198
- display: flex;
199
- align-items: center;
200
- height: 100%;
201
- gap: 2px;
202
- }
203
-
204
- .wave-bar {
205
- flex: 1;
206
- background: var(--md-sys-color-primary);
207
- opacity: 0.3;
208
- border-radius: 2px;
209
- transition: opacity 0.3s;
210
- }
211
-
212
- .wave-bar.active {
213
- opacity: 1;
214
- background: var(--md-sys-color-primary);
215
- }
216
-
217
- .wave-bar.played {
218
- opacity: 0.6;
219
- background: var(--md-sys-color-secondary);
220
- }
221
-
222
- .progress-time {
223
- display: flex;
224
- justify-content: space-between;
225
- font-size: 12px;
226
- color: var(--md-sys-color-on-surface-variant);
227
- margin-bottom: 20px;
228
- }
229
-
230
- .controls {
231
- display: flex;
232
- align-items: center;
233
- justify-content: center;
234
- gap: 16px;
235
- margin-bottom: 20px;
236
- }
237
-
238
- .control-btn {
239
- background: transparent;
240
- border: none;
241
- color: var(--md-sys-color-on-surface);
242
- cursor: pointer;
243
- display: flex;
244
- align-items: center;
245
- justify-content: center;
246
- transition: all 0.2s;
247
- border-radius: 50%;
248
- }
249
-
250
- .control-btn:hover {
251
- background: var(--md-sys-color-surface-variant);
252
- }
253
-
254
- .control-btn.small {
255
- width: 40px;
256
- height: 40px;
257
- }
258
-
259
- .control-btn.primary {
260
- width: 56px;
261
- height: 56px;
262
- background: var(--md-sys-color-primary);
263
- color: var(--md-sys-color-on-primary);
264
- box-shadow: 0 4px 12px rgba(124, 77, 255, 0.3);
265
- }
266
-
267
- .control-btn.primary:hover {
268
- transform: scale(1.05);
269
- box-shadow: 0 6px 16px rgba(124, 77, 255, 0.4);
270
- }
271
-
272
- .speed-controls {
273
- display: flex;
274
- align-items: center;
275
- justify-content: center;
276
- gap: 12px;
277
- }
278
-
279
- .speed-btn {
280
- padding: 6px 12px;
281
- background: var(--md-sys-color-surface-container);
282
- color: var(--md-sys-color-on-surface);
283
- border: none;
284
- border-radius: 8px;
285
- font-size: 13px;
286
- cursor: pointer;
287
- transition: all 0.2s;
288
- }
289
-
290
- .speed-btn.active {
291
- background: var(--md-sys-color-primary);
292
- color: var(--md-sys-color-on-primary);
293
- }
294
-
295
- .speed-btn:hover {
296
- background: var(--md-sys-color-surface-container-high);
297
- }
298
-
299
- .speed-btn.active:hover {
300
- background: var(--md-sys-color-primary);
301
- }
302
-
303
- .chapters-section {
304
- padding: 20px;
305
- background: var(--md-sys-color-surface);
306
- max-height: 400px;
307
- overflow-y: auto;
308
- }
309
-
310
- .section-title {
311
- font-size: 18px;
312
- font-weight: 600;
313
- color: var(--md-sys-color-on-surface);
314
- margin-bottom: 16px;
315
- display: flex;
316
- align-items: center;
317
- gap: 8px;
318
- }
319
-
320
- .chapter-list {
321
- display: flex;
322
- flex-direction: column;
323
- gap: 2px;
324
- }
325
-
326
- .chapter-item {
327
- display: flex;
328
- align-items: center;
329
- padding: 12px;
330
- background: var(--md-sys-color-surface);
331
- border-radius: 12px;
332
- cursor: pointer;
333
- transition: all 0.2s;
334
- border: 1px solid transparent;
335
- }
336
-
337
- .chapter-item:hover {
338
- background: var(--md-sys-color-surface-container);
339
- }
340
-
341
- .chapter-item.active {
342
- background: var(--md-sys-color-primary-container);
343
- border-color: var(--md-sys-color-primary);
344
- }
345
-
346
- .chapter-item.played {
347
- opacity: 0.7;
348
- }
349
-
350
- .chapter-number {
351
- width: 32px;
352
- height: 32px;
353
- border-radius: 8px;
354
- background: var(--md-sys-color-surface-variant);
355
- color: var(--md-sys-color-on-surface-variant);
356
- display: flex;
357
- align-items: center;
358
- justify-content: center;
359
- font-size: 14px;
360
- font-weight: 600;
361
- margin-right: 12px;
362
- }
363
-
364
- .chapter-item.active .chapter-number {
365
- background: var(--md-sys-color-primary);
366
- color: var(--md-sys-color-on-primary);
367
- }
368
-
369
- .chapter-info {
370
- flex: 1;
371
- }
372
-
373
- .chapter-title {
374
- font-size: 15px;
375
- font-weight: 500;
376
- color: var(--md-sys-color-on-surface);
377
- margin-bottom: 2px;
378
- }
379
-
380
- .chapter-description {
381
- font-size: 13px;
382
- color: var(--md-sys-color-on-surface-variant);
383
- display: -webkit-box;
384
- -webkit-line-clamp: 1;
385
- -webkit-box-orient: vertical;
386
- overflow: hidden;
387
- }
388
-
389
- .chapter-time {
390
- display: flex;
391
- flex-direction: column;
392
- align-items: flex-end;
393
- gap: 2px;
394
- }
395
-
396
- .chapter-timestamp {
397
- font-size: 13px;
398
- color: var(--md-sys-color-primary);
399
- font-weight: 500;
400
- }
401
-
402
- .chapter-duration {
403
- font-size: 11px;
404
- color: var(--md-sys-color-on-surface-variant);
405
- }
406
-
407
- .icon {
408
- width: 24px;
409
- height: 24px;
410
- fill: currentColor;
411
- }
412
-
413
- .icon.large {
414
- width: 32px;
415
- height: 32px;
416
- }
417
-
418
- /* Custom scrollbar */
419
- .chapters-section::-webkit-scrollbar {
420
- width: 6px;
421
- }
422
-
423
- .chapters-section::-webkit-scrollbar-track {
424
- background: var(--md-sys-color-surface-container);
425
- border-radius: 3px;
426
- }
427
-
428
- .chapters-section::-webkit-scrollbar-thumb {
429
- background: var(--md-sys-color-outline);
430
- border-radius: 3px;
431
- }
432
-
433
- .chapters-section::-webkit-scrollbar-thumb:hover {
434
- background: var(--md-sys-color-primary);
435
- }
436
-
437
- /* Playing animation */
438
- @keyframes pulse {
439
- 0%,
440
- 100% {
441
- transform: scaleY(0.3);
442
- }
443
- 50% {
444
- transform: scaleY(1);
445
- }
446
- }
447
-
448
- .playing-indicator {
449
- display: none;
450
- gap: 2px;
451
- height: 16px;
452
- align-items: flex-end;
453
- }
454
-
455
- .chapter-item.active .playing-indicator {
456
- display: flex;
457
- }
458
-
459
- .playing-bar {
460
- width: 3px;
461
- height: 100%;
462
- background: var(--md-sys-color-primary);
463
- animation: pulse 1s ease-in-out infinite;
464
- }
465
-
466
- .playing-bar:nth-child(2) {
467
- animation-delay: 0.2s;
468
- }
469
-
470
- .playing-bar:nth-child(3) {
471
- animation-delay: 0.4s;
472
- }
473
-
474
- /* Theme switcher */
475
- .theme-fab {
476
- position: fixed;
477
- bottom: 24px;
478
- right: 24px;
479
- width: 56px;
480
- height: 56px;
481
- border-radius: 16px;
482
- background: var(--md-sys-color-primary);
483
- color: var(--md-sys-color-on-primary);
484
- border: none;
485
- cursor: pointer;
486
- display: flex;
487
- align-items: center;
488
- justify-content: center;
489
- box-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
490
- transition: all 0.3s;
491
- }
492
-
493
- .theme-fab:hover {
494
- transform: scale(1.05);
495
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
496
- }
497
- </style>
498
- </head>
499
- <body>
500
- <div class="container">
501
- <div class="player-section">
502
- <div class="podcast-header">
503
- <div class="podcast-cover">
504
- <div class="cover-pattern"></div>
505
- <span>🎙️</span>
506
- </div>
507
- <div class="podcast-info">
508
- <div class="podcast-title">Tech Talks Daily</div>
509
- <div class="podcast-author">by Sarah Chen</div>
510
- <div class="episode-title">Episode 42: The Future of AI</div>
511
- </div>
512
- </div>
513
-
514
- <div class="waveform-container">
515
- <div class="waveform" id="waveform"></div>
516
- </div>
517
-
518
- <div class="progress-time">
519
- <span id="currentTime">15:32</span>
520
- <span id="totalTime">45:00</span>
521
- </div>
522
-
523
- <div class="controls">
524
- <button class="control-btn small" onclick="skipBack()">
525
- <svg class="icon" viewBox="0 0 24 24">
526
- <path d="M11 18V6l-8.5 6 8.5 6zm.5-6l8.5 6V6l-8.5 6z" />
527
- </svg>
528
- </button>
529
-
530
- <button class="control-btn small" onclick="rewind()">
531
- <svg class="icon" viewBox="0 0 24 24">
532
- <text
533
- x="50%"
534
- y="50%"
535
- text-anchor="middle"
536
- dy=".3em"
537
- font-size="12"
538
- font-weight="bold"
539
- >
540
- -15
541
- </text>
542
- </svg>
543
- </button>
544
-
545
- <button
546
- class="control-btn primary"
547
- onclick="togglePlay()"
548
- id="playBtn"
549
- >
550
- <svg class="icon large" viewBox="0 0 24 24">
551
- <path d="M8 5v14l11-7z" />
552
- </svg>
553
- </button>
554
-
555
- <button class="control-btn small" onclick="forward()">
556
- <svg class="icon" viewBox="0 0 24 24">
557
- <text
558
- x="50%"
559
- y="50%"
560
- text-anchor="middle"
561
- dy=".3em"
562
- font-size="12"
563
- font-weight="bold"
564
- >
565
- +30
566
- </text>
567
- </svg>
568
- </button>
569
-
570
- <button class="control-btn small" onclick="skipForward()">
571
- <svg class="icon" viewBox="0 0 24 24">
572
- <path d="M4 18l8.5-6L4 6v12zm9-12v12l8.5-6L13 6z" />
573
- </svg>
574
- </button>
575
- </div>
576
-
577
- <div class="speed-controls">
578
- <button class="speed-btn" onclick="setSpeed(0.75)">0.75x</button>
579
- <button class="speed-btn active" onclick="setSpeed(1)">1x</button>
580
- <button class="speed-btn" onclick="setSpeed(1.25)">1.25x</button>
581
- <button class="speed-btn" onclick="setSpeed(1.5)">1.5x</button>
582
- <button class="speed-btn" onclick="setSpeed(2)">2x</button>
583
- </div>
584
- </div>
585
-
586
- <div class="chapters-section">
587
- <div class="section-title">
588
- <svg class="icon" viewBox="0 0 24 24">
589
- <path
590
- d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"
591
- />
592
- </svg>
593
- Chapters
594
- </div>
595
-
596
- <div class="chapter-list">
597
- <div class="chapter-item played" onclick="playChapter(0)">
598
- <div class="chapter-number">1</div>
599
- <div class="chapter-info">
600
- <div class="chapter-title">Introduction</div>
601
- <div class="chapter-description">
602
- Welcome to today's episode about AI
603
- </div>
604
- </div>
605
- <div class="chapter-time">
606
- <span class="chapter-timestamp">00:00</span>
607
- <span class="chapter-duration">2:15</span>
608
- </div>
609
- </div>
610
-
611
- <div class="chapter-item played" onclick="playChapter(1)">
612
- <div class="chapter-number">2</div>
613
- <div class="chapter-info">
614
- <div class="chapter-title">Guest Introduction</div>
615
- <div class="chapter-description">
616
- Meet Dr. Alex Johnson from OpenAI
617
- </div>
618
- </div>
619
- <div class="chapter-time">
620
- <span class="chapter-timestamp">02:15</span>
621
- <span class="chapter-duration">3:45</span>
622
- </div>
623
- </div>
624
-
625
- <div class="chapter-item played" onclick="playChapter(2)">
626
- <div class="chapter-number">3</div>
627
- <div class="chapter-info">
628
- <div class="chapter-title">Current State of AI</div>
629
- <div class="chapter-description">
630
- Overview of where we are today with artificial intelligence
631
- </div>
632
- </div>
633
- <div class="chapter-time">
634
- <span class="chapter-timestamp">06:00</span>
635
- <span class="chapter-duration">8:30</span>
636
- </div>
637
- </div>
638
-
639
- <div class="chapter-item active" onclick="playChapter(3)">
640
- <div class="chapter-number">
641
- <div class="playing-indicator">
642
- <div class="playing-bar"></div>
643
- <div class="playing-bar"></div>
644
- <div class="playing-bar"></div>
645
- </div>
646
- </div>
647
- <div class="chapter-info">
648
- <div class="chapter-title">Large Language Models</div>
649
- <div class="chapter-description">
650
- Deep dive into GPT and similar models
651
- </div>
652
- </div>
653
- <div class="chapter-time">
654
- <span class="chapter-timestamp">14:30</span>
655
- <span class="chapter-duration">10:15</span>
656
- </div>
657
- </div>
658
-
659
- <div class="chapter-item" onclick="playChapter(4)">
660
- <div class="chapter-number">5</div>
661
- <div class="chapter-info">
662
- <div class="chapter-title">Ethical Considerations</div>
663
- <div class="chapter-description">
664
- Discussing the importance of responsible AI development
665
- </div>
666
- </div>
667
- <div class="chapter-time">
668
- <span class="chapter-timestamp">24:45</span>
669
- <span class="chapter-duration">7:20</span>
670
- </div>
671
- </div>
672
-
673
- <div class="chapter-item" onclick="playChapter(5)">
674
- <div class="chapter-number">6</div>
675
- <div class="chapter-info">
676
- <div class="chapter-title">Future Predictions</div>
677
- <div class="chapter-description">
678
- What might the next 5 years look like?
679
- </div>
680
- </div>
681
- <div class="chapter-time">
682
- <span class="chapter-timestamp">32:05</span>
683
- <span class="chapter-duration">6:40</span>
684
- </div>
685
- </div>
686
-
687
- <div class="chapter-item" onclick="playChapter(6)">
688
- <div class="chapter-number">7</div>
689
- <div class="chapter-info">
690
- <div class="chapter-title">Q&A Session</div>
691
- <div class="chapter-description">
692
- Answering listener questions
693
- </div>
694
- </div>
695
- <div class="chapter-time">
696
- <span class="chapter-timestamp">38:45</span>
697
- <span class="chapter-duration">4:30</span>
698
- </div>
699
- </div>
700
-
701
- <div class="chapter-item" onclick="playChapter(7)">
702
- <div class="chapter-number">8</div>
703
- <div class="chapter-info">
704
- <div class="chapter-title">Closing Thoughts</div>
705
- <div class="chapter-description">
706
- Wrapping up and next episode preview
707
- </div>
708
- </div>
709
- <div class="chapter-time">
710
- <span class="chapter-timestamp">43:15</span>
711
- <span class="chapter-duration">1:45</span>
712
- </div>
713
- </div>
714
- </div>
715
- </div>
716
- </div>
717
-
718
- <button class="theme-fab" onclick="changeTheme()">
719
- <svg class="icon" viewBox="0 0 24 24">
720
- <path
721
- d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"
722
- />
723
- </svg>
724
- </button>
725
-
726
- <script>
727
- // Generate waveform bars
728
- const waveform = document.getElementById("waveform");
729
- for (let i = 0; i < 50; i++) {
730
- const bar = document.createElement("div");
731
- bar.className = "wave-bar";
732
- bar.style.height = Math.random() * 80 + 20 + "%";
733
-
734
- // Simulate played progress
735
- if (i < 17) {
736
- bar.classList.add("played");
737
- } else if (i === 17) {
738
- bar.classList.add("active");
739
- }
740
-
741
- waveform.appendChild(bar);
742
- }
743
-
744
- let isPlaying = false;
745
- let currentSpeed = 1;
746
- let currentChapter = 3;
747
-
748
- function togglePlay() {
749
- isPlaying = !isPlaying;
750
- const playBtn = document.getElementById("playBtn");
751
- if (isPlaying) {
752
- playBtn.innerHTML =
753
- '<svg class="icon large" viewBox="0 0 24 24"><path d="M6 19h4V5H6v14zm8-14v14h4V5h-4z"/></svg>';
754
- } else {
755
- playBtn.innerHTML =
756
- '<svg class="icon large" viewBox="0 0 24 24"><path d="M8 5v14l11-7z"/></svg>';
757
- }
758
- }
759
-
760
- function setSpeed(speed) {
761
- currentSpeed = speed;
762
- document.querySelectorAll(".speed-btn").forEach((btn) => {
763
- btn.classList.remove("active");
764
- });
765
- event.target.classList.add("active");
766
- }
767
-
768
- function playChapter(index) {
769
- currentChapter = index;
770
- document.querySelectorAll(".chapter-item").forEach((item, i) => {
771
- item.classList.remove("active");
772
- if (i < index) {
773
- item.classList.add("played");
774
- } else {
775
- item.classList.remove("played");
776
- }
777
- });
778
- document
779
- .querySelectorAll(".chapter-item")
780
- [index].classList.add("active");
781
-
782
- // Update waveform
783
- updateWaveform(index);
784
- }
785
-
786
- function updateWaveform(chapterIndex) {
787
- const bars = document.querySelectorAll(".wave-bar");
788
- const progress = (chapterIndex + 0.5) / 8; // 8 chapters total
789
- const activeBar = Math.floor(progress * bars.length);
790
-
791
- bars.forEach((bar, i) => {
792
- bar.classList.remove("played", "active");
793
- if (i < activeBar) {
794
- bar.classList.add("played");
795
- } else if (i === activeBar) {
796
- bar.classList.add("active");
797
- }
798
- });
799
- }
800
-
801
- function skipBack() {
802
- if (currentChapter > 0) {
803
- playChapter(currentChapter - 1);
804
- }
805
- }
806
-
807
- function skipForward() {
808
- if (currentChapter < 7) {
809
- playChapter(currentChapter + 1);
810
- }
811
- }
812
-
813
- function rewind() {
814
- // Simulate 15 second rewind
815
- console.log("Rewind 15 seconds");
816
- }
817
-
818
- function forward() {
819
- // Simulate 30 second forward
820
- console.log("Forward 30 seconds");
821
- }
822
-
823
- // Theme variations
824
- const themes = [
825
- {
826
- name: "Purple Dream",
827
- primary: "#7c4dff",
828
- secondary: "#625b71",
829
- tertiary: "#7d5260",
830
- primaryContainer: "#e1d5ff",
831
- secondaryContainer: "#e8def8",
832
- tertiaryContainer: "#ffd8e4",
833
- },
834
- {
835
- name: "Ocean Breeze",
836
- primary: "#0061a4",
837
- secondary: "#535f70",
838
- tertiary: "#6f5575",
839
- primaryContainer: "#d1e4ff",
840
- secondaryContainer: "#d9e3f0",
841
- tertiaryContainer: "#f8d8ff",
842
- },
843
- {
844
- name: "Forest",
845
- primary: "#006e1c",
846
- secondary: "#52634f",
847
- tertiary: "#386666",
848
- primaryContainer: "#b6f397",
849
- secondaryContainer: "#d6e8cd",
850
- tertiaryContainer: "#bbebeb",
851
- },
852
- {
853
- name: "Sunset",
854
- primary: "#bc004b",
855
- secondary: "#775653",
856
- tertiary: "#775a00",
857
- primaryContainer: "#ffd9dc",
858
- secondaryContainer: "#ffdad7",
859
- tertiaryContainer: "#ffdeaa",
860
- },
861
- ];
862
-
863
- let currentTheme = 0;
864
-
865
- function changeTheme() {
866
- currentTheme = (currentTheme + 1) % themes.length;
867
- const theme = themes[currentTheme];
868
- const root = document.documentElement;
869
-
870
- root.style.setProperty("--md-sys-color-primary", theme.primary);
871
- root.style.setProperty("--md-sys-color-secondary", theme.secondary);
872
- root.style.setProperty("--md-sys-color-tertiary", theme.tertiary);
873
- root.style.setProperty(
874
- "--md-sys-color-primary-container",
875
- theme.primaryContainer,
876
- );
877
- root.style.setProperty(
878
- "--md-sys-color-secondary-container",
879
- theme.secondaryContainer,
880
- );
881
- root.style.setProperty(
882
- "--md-sys-color-tertiary-container",
883
- theme.tertiaryContainer,
884
- );
885
-
886
- // Animate the change
887
- root.style.transition = "all 0.3s ease";
888
- }
889
-
890
- // Simulate time updates
891
- let seconds = 932; // 15:32
892
- setInterval(() => {
893
- if (isPlaying) {
894
- seconds += currentSpeed;
895
- const mins = Math.floor(seconds / 60);
896
- const secs = Math.floor(seconds % 60);
897
- document.getElementById("currentTime").textContent =
898
- `${mins}:${secs.toString().padStart(2, "0")}`;
899
- }
900
- }, 1000);
901
- </script>
902
- </body>
903
- </html>