@trishchuk/coolors-mcp 1.0.0 → 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 (140) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +20 -8
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +22 -8
  3. package/.github/pull_request_template.md +33 -8
  4. package/.github/workflows/ci.yml +107 -104
  5. package/.github/workflows/deploy-docs.yml +14 -11
  6. package/.github/workflows/release.yml +25 -23
  7. package/README.md +149 -15
  8. package/dist/bin/server.js +997 -256
  9. package/dist/bin/server.js.map +1 -1
  10. package/dist/{chunk-P3ARRKLS.js → chunk-HOMDMKUY.js} +3 -1
  11. package/dist/{chunk-P3ARRKLS.js.map → chunk-HOMDMKUY.js.map} +1 -1
  12. package/dist/{chunk-IQ7NN26V.js → chunk-LHW2ZTOU.js} +14 -2
  13. package/dist/chunk-LHW2ZTOU.js.map +1 -0
  14. package/dist/color/index.js +1 -1
  15. package/dist/coolors-mcp.d.ts +4 -4
  16. package/dist/coolors-mcp.js +1 -1
  17. package/docs/.vitepress/components/ClientGrid.vue +9 -3
  18. package/docs/.vitepress/components/CodeBlock.vue +51 -44
  19. package/docs/.vitepress/components/ConfigModal.vue +151 -67
  20. package/docs/.vitepress/components/DiagramModal.vue +186 -154
  21. package/docs/.vitepress/components/TroubleshootingModal.vue +101 -96
  22. package/docs/.vitepress/config.js +171 -141
  23. package/docs/.vitepress/theme/FundingLayout.vue +65 -54
  24. package/docs/.vitepress/theme/Layout.vue +21 -21
  25. package/docs/.vitepress/theme/components/AdBanner.vue +73 -52
  26. package/docs/.vitepress/theme/components/AdPlaceholder.vue +3 -3
  27. package/docs/.vitepress/theme/components/FundingEffects.vue +77 -53
  28. package/docs/.vitepress/theme/components/FundingHero.vue +78 -63
  29. package/docs/.vitepress/theme/components/SupportSection.vue +106 -89
  30. package/docs/.vitepress/theme/custom-app.css +19 -12
  31. package/docs/.vitepress/theme/custom.css +33 -25
  32. package/docs/.vitepress/theme/index.js +19 -16
  33. package/docs/concepts/accessibility.md +59 -47
  34. package/docs/concepts/color-spaces.md +28 -6
  35. package/docs/concepts/distance-metrics.md +45 -30
  36. package/docs/concepts/hct.md +30 -27
  37. package/docs/concepts/image-analysis.md +52 -21
  38. package/docs/concepts/material-design.md +43 -17
  39. package/docs/concepts/theme-matching.md +64 -40
  40. package/docs/examples/basic-colors.md +92 -108
  41. package/docs/examples/creating-themes.md +104 -108
  42. package/docs/examples/css-refactoring.md +33 -29
  43. package/docs/examples/image-extraction.md +145 -138
  44. package/docs/getting-started.md +45 -34
  45. package/docs/index.md +5 -1
  46. package/docs/installation.md +15 -1
  47. package/docs/tools/accessibility.md +74 -68
  48. package/docs/tools/image-extraction.md +62 -54
  49. package/docs/tools/theme-matching.md +45 -42
  50. package/eslint.config.ts +13 -0
  51. package/jsr.json +1 -1
  52. package/package.json +17 -13
  53. package/src/bin/server.ts +13 -1
  54. package/src/color/__tests__/extract-colors.test.ts +20 -30
  55. package/src/color/apca.ts +105 -0
  56. package/src/color/color-blindness.ts +109 -0
  57. package/src/coolors-mcp.ts +1 -1
  58. package/src/session.ts +10 -2
  59. package/src/theme/matcher.ts +1 -1
  60. package/src/theme/refactor.ts +1 -1
  61. package/src/theme/types.ts +3 -0
  62. package/src/tools/__tests__/cohesion.test.ts +97 -0
  63. package/src/tools/__tests__/color-blindness.test.ts +45 -0
  64. package/src/tools/__tests__/color-conversion.test.ts +38 -0
  65. package/src/tools/__tests__/contrast-checker.test.ts +56 -0
  66. package/src/tools/__tests__/palette-export.test.ts +54 -0
  67. package/src/tools/adjust-color.tool.ts +80 -0
  68. package/src/tools/cohesion.tools.ts +380 -0
  69. package/src/tools/color-blindness.tool.ts +168 -0
  70. package/src/tools/color-conversion.tool.ts +1 -1
  71. package/src/tools/contrast-checker.tool.ts +53 -14
  72. package/src/tools/dislike-analyzer.tool.ts +41 -54
  73. package/src/tools/image-extraction.tools.ts +62 -115
  74. package/src/tools/index.ts +15 -2
  75. package/src/tools/palette-export.tool.ts +174 -0
  76. package/src/tools/palette-with-locks.tool.ts +8 -6
  77. package/src/types.ts +2 -3
  78. package/tsconfig.json +12 -2
  79. package/vitest.config.js +1 -3
  80. package/.claude/settings.local.json +0 -39
  81. package/.env +0 -2
  82. package/.mcp.json +0 -12
  83. package/CLAUDE.md +0 -201
  84. package/DOCUMENTATION.md +0 -274
  85. package/GEMINI.md +0 -54
  86. package/demo/content_based_color.png +0 -0
  87. package/demo/music-player.html +0 -621
  88. package/demo/podcast-player.html +0 -903
  89. package/dist/chunk-IQ7NN26V.js.map +0 -1
  90. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js +0 -93
  91. package/docs/.vitepress/cache/deps/@braintree_sanitize-url.js.map +0 -7
  92. package/docs/.vitepress/cache/deps/_metadata.json +0 -127
  93. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js +0 -9
  94. package/docs/.vitepress/cache/deps/chunk-BUSYA2B4.js.map +0 -7
  95. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js +0 -12683
  96. package/docs/.vitepress/cache/deps/chunk-JD3CXNQ6.js.map +0 -7
  97. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js +0 -9719
  98. package/docs/.vitepress/cache/deps/chunk-SYPOPCWC.js.map +0 -7
  99. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js +0 -4710
  100. package/docs/.vitepress/cache/deps/cytoscape-cose-bilkent.js.map +0 -7
  101. package/docs/.vitepress/cache/deps/cytoscape.js +0 -30278
  102. package/docs/.vitepress/cache/deps/cytoscape.js.map +0 -7
  103. package/docs/.vitepress/cache/deps/dayjs.js +0 -285
  104. package/docs/.vitepress/cache/deps/dayjs.js.map +0 -7
  105. package/docs/.vitepress/cache/deps/debug.js +0 -468
  106. package/docs/.vitepress/cache/deps/debug.js.map +0 -7
  107. package/docs/.vitepress/cache/deps/package.json +0 -3
  108. package/docs/.vitepress/cache/deps/prismjs.js +0 -1466
  109. package/docs/.vitepress/cache/deps/prismjs.js.map +0 -7
  110. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js +0 -228
  111. package/docs/.vitepress/cache/deps/prismjs_components_prism-bash.js.map +0 -7
  112. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js +0 -142
  113. package/docs/.vitepress/cache/deps/prismjs_components_prism-javascript.js.map +0 -7
  114. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js +0 -27
  115. package/docs/.vitepress/cache/deps/prismjs_components_prism-json.js.map +0 -7
  116. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js +0 -65
  117. package/docs/.vitepress/cache/deps/prismjs_components_prism-python.js.map +0 -7
  118. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js +0 -53
  119. package/docs/.vitepress/cache/deps/prismjs_components_prism-typescript.js.map +0 -7
  120. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js +0 -73
  121. package/docs/.vitepress/cache/deps/prismjs_components_prism-yaml.js.map +0 -7
  122. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js +0 -4507
  123. package/docs/.vitepress/cache/deps/vitepress___@vue_devtools-api.js.map +0 -7
  124. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js +0 -584
  125. package/docs/.vitepress/cache/deps/vitepress___@vueuse_core.js.map +0 -7
  126. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js +0 -1146
  127. package/docs/.vitepress/cache/deps/vitepress___@vueuse_integrations_useFocusTrap.js.map +0 -7
  128. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js +0 -1667
  129. package/docs/.vitepress/cache/deps/vitepress___mark__js_src_vanilla__js.js.map +0 -7
  130. package/docs/.vitepress/cache/deps/vitepress___minisearch.js +0 -1814
  131. package/docs/.vitepress/cache/deps/vitepress___minisearch.js.map +0 -7
  132. package/docs/.vitepress/cache/deps/vue.js +0 -344
  133. package/docs/.vitepress/cache/deps/vue.js.map +0 -7
  134. package/examples/theme-matching.md +0 -113
  135. package/mcp-config.json +0 -8
  136. package/note.md +0 -35
  137. package/research_results.md +0 -53
  138. package/src/tools/colors.ts +0 -31
  139. package/src/tools/registry.ts +0 -142
  140. 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>