@jtalk22/slack-mcp 1.0.6 → 1.1.1
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 +13 -1
- package/package.json +1 -1
- package/public/demo.html +695 -612
- package/public/index.html +128 -16
- package/scripts/verify-web.js +221 -0
- package/src/server.js +2 -2
- package/src/web-server.js +9 -6
package/public/demo.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="UTF-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
-
<title>Slack MCP Server - Demo</title>
|
|
6
|
+
<title>Slack MCP Server - Interactive Demo</title>
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -17,6 +17,8 @@
|
|
|
17
17
|
--accent-hover: #45b7aa;
|
|
18
18
|
--accent-glow: rgba(78, 205, 196, 0.3);
|
|
19
19
|
--danger: #e94560;
|
|
20
|
+
--claude-orange: #da7756;
|
|
21
|
+
--claude-bg: #2d2a24;
|
|
20
22
|
--text-primary: #ffffff;
|
|
21
23
|
--text-secondary: rgba(255, 255, 255, 0.7);
|
|
22
24
|
--text-muted: rgba(255, 255, 255, 0.5);
|
|
@@ -34,887 +36,968 @@
|
|
|
34
36
|
line-height: 1.5;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
/*
|
|
38
|
-
.
|
|
39
|
-
|
|
39
|
+
/* Preview Banner */
|
|
40
|
+
.preview-banner {
|
|
41
|
+
background: linear-gradient(135deg, var(--danger), #ff8c00);
|
|
42
|
+
color: white;
|
|
43
|
+
padding: 12px 20px;
|
|
44
|
+
text-align: center;
|
|
45
|
+
font-size: 14px;
|
|
46
|
+
font-weight: 500;
|
|
47
|
+
position: sticky;
|
|
40
48
|
top: 0;
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
background:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
z-index: 100;
|
|
50
|
+
}
|
|
51
|
+
.preview-banner code {
|
|
52
|
+
background: rgba(0,0,0,0.2);
|
|
53
|
+
padding: 2px 8px;
|
|
54
|
+
border-radius: 4px;
|
|
55
|
+
font-family: monospace;
|
|
56
|
+
}
|
|
57
|
+
.preview-banner a {
|
|
58
|
+
color: white;
|
|
59
|
+
text-decoration: underline;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/* Main Layout */
|
|
63
|
+
.split-container {
|
|
64
|
+
display: grid;
|
|
65
|
+
grid-template-columns: 420px 1fr;
|
|
66
|
+
height: calc(100vh - 44px);
|
|
67
|
+
overflow: hidden;
|
|
55
68
|
}
|
|
56
69
|
|
|
57
|
-
/*
|
|
58
|
-
.
|
|
70
|
+
/* ========== LEFT PANEL: CLAUDE CHAT ========== */
|
|
71
|
+
.claude-panel {
|
|
72
|
+
background: var(--claude-bg);
|
|
73
|
+
border-right: 1px solid rgba(255,255,255,0.1);
|
|
59
74
|
display: flex;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
margin-bottom: 24px;
|
|
63
|
-
padding-bottom: 24px;
|
|
64
|
-
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
|
75
|
+
flex-direction: column;
|
|
76
|
+
overflow: hidden;
|
|
65
77
|
}
|
|
66
78
|
|
|
67
|
-
.
|
|
79
|
+
.claude-header {
|
|
80
|
+
padding: 16px 20px;
|
|
81
|
+
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
68
82
|
display: flex;
|
|
69
83
|
align-items: center;
|
|
70
84
|
gap: 12px;
|
|
71
85
|
}
|
|
72
86
|
|
|
73
|
-
.logo
|
|
74
|
-
width:
|
|
75
|
-
height:
|
|
76
|
-
background: linear-gradient(135deg, var(--
|
|
77
|
-
border-radius:
|
|
87
|
+
.claude-logo {
|
|
88
|
+
width: 36px;
|
|
89
|
+
height: 36px;
|
|
90
|
+
background: linear-gradient(135deg, var(--claude-orange), #c4694a);
|
|
91
|
+
border-radius: 10px;
|
|
78
92
|
display: flex;
|
|
79
93
|
align-items: center;
|
|
80
94
|
justify-content: center;
|
|
81
|
-
font-size: 24px;
|
|
82
|
-
box-shadow: 0 4px 20px var(--accent-glow);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.logo h1 {
|
|
86
|
-
font-size: 24px;
|
|
87
95
|
font-weight: 700;
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
-webkit-text-fill-color: transparent;
|
|
91
|
-
background-clip: text;
|
|
96
|
+
font-size: 18px;
|
|
97
|
+
color: white;
|
|
92
98
|
}
|
|
93
99
|
|
|
94
|
-
.
|
|
95
|
-
font-size:
|
|
100
|
+
.claude-header h2 {
|
|
101
|
+
font-size: 16px;
|
|
102
|
+
font-weight: 600;
|
|
103
|
+
color: var(--text-primary);
|
|
104
|
+
}
|
|
105
|
+
.claude-header .subtitle {
|
|
106
|
+
font-size: 12px;
|
|
96
107
|
color: var(--text-muted);
|
|
97
|
-
font-weight: 400;
|
|
98
108
|
}
|
|
99
109
|
|
|
100
|
-
.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
border
|
|
110
|
+
.reset-btn {
|
|
111
|
+
margin-left: auto;
|
|
112
|
+
padding: 6px 14px;
|
|
113
|
+
background: rgba(255,255,255,0.1);
|
|
114
|
+
border: 1px solid rgba(255,255,255,0.2);
|
|
115
|
+
border-radius: 6px;
|
|
116
|
+
color: var(--text-secondary);
|
|
117
|
+
cursor: pointer;
|
|
105
118
|
font-size: 12px;
|
|
106
|
-
font-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
119
|
+
font-family: inherit;
|
|
120
|
+
transition: var(--transition);
|
|
121
|
+
}
|
|
122
|
+
.reset-btn:hover {
|
|
123
|
+
background: rgba(233, 69, 96, 0.2);
|
|
124
|
+
border-color: var(--danger);
|
|
125
|
+
color: var(--danger);
|
|
110
126
|
}
|
|
111
127
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
128
|
+
.claude-chat {
|
|
129
|
+
flex: 1;
|
|
130
|
+
overflow-y: auto;
|
|
131
|
+
padding: 20px;
|
|
132
|
+
scroll-behavior: smooth;
|
|
115
133
|
}
|
|
116
134
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
padding: 16px 20px;
|
|
121
|
-
border-radius: var(--border-radius);
|
|
122
|
-
margin-bottom: 24px;
|
|
123
|
-
display: flex;
|
|
124
|
-
align-items: center;
|
|
125
|
-
justify-content: space-between;
|
|
126
|
-
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
135
|
+
.chat-message {
|
|
136
|
+
margin-bottom: 20px;
|
|
137
|
+
animation: fadeIn 0.3s ease;
|
|
127
138
|
}
|
|
128
139
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
gap: 10px;
|
|
140
|
+
@keyframes fadeIn {
|
|
141
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
142
|
+
to { opacity: 1; transform: translateY(0); }
|
|
133
143
|
}
|
|
134
144
|
|
|
135
|
-
.
|
|
136
|
-
|
|
137
|
-
height: 10px;
|
|
138
|
-
background: #22c55e;
|
|
139
|
-
border-radius: 50%;
|
|
140
|
-
box-shadow: 0 0 10px rgba(34, 197, 94, 0.5);
|
|
141
|
-
animation: blink 2s infinite;
|
|
145
|
+
.chat-message.user {
|
|
146
|
+
text-align: right;
|
|
142
147
|
}
|
|
143
148
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
149
|
+
.chat-message.user .bubble {
|
|
150
|
+
background: var(--bg-input);
|
|
151
|
+
display: inline-block;
|
|
152
|
+
text-align: left;
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
.
|
|
155
|
+
.chat-message .bubble {
|
|
156
|
+
background: rgba(255,255,255,0.05);
|
|
157
|
+
padding: 14px 18px;
|
|
158
|
+
border-radius: 16px;
|
|
159
|
+
max-width: 90%;
|
|
150
160
|
font-size: 14px;
|
|
151
|
-
|
|
161
|
+
line-height: 1.6;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.chat-message.claude .bubble {
|
|
165
|
+
border-top-left-radius: 4px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
.chat-message.user .bubble {
|
|
169
|
+
border-top-right-radius: 4px;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/* Tool call styling */
|
|
173
|
+
.tool-call {
|
|
174
|
+
background: rgba(78, 205, 196, 0.1);
|
|
175
|
+
border: 1px solid rgba(78, 205, 196, 0.3);
|
|
176
|
+
border-radius: 8px;
|
|
177
|
+
padding: 12px;
|
|
178
|
+
margin: 10px 0;
|
|
179
|
+
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
180
|
+
font-size: 12px;
|
|
152
181
|
}
|
|
153
182
|
|
|
154
|
-
.
|
|
183
|
+
.tool-call .tool-name {
|
|
155
184
|
color: var(--accent);
|
|
185
|
+
font-weight: 600;
|
|
156
186
|
}
|
|
157
187
|
|
|
158
|
-
.
|
|
159
|
-
display: flex;
|
|
160
|
-
align-items: center;
|
|
161
|
-
gap: 16px;
|
|
162
|
-
font-size: 13px;
|
|
188
|
+
.tool-call .tool-params {
|
|
163
189
|
color: var(--text-muted);
|
|
190
|
+
margin-top: 4px;
|
|
164
191
|
}
|
|
165
192
|
|
|
166
|
-
|
|
193
|
+
/* Typing indicator */
|
|
194
|
+
.typing-indicator {
|
|
167
195
|
display: flex;
|
|
168
|
-
|
|
169
|
-
|
|
196
|
+
gap: 4px;
|
|
197
|
+
padding: 8px 0;
|
|
170
198
|
}
|
|
171
199
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
min-height: 500px;
|
|
200
|
+
.typing-indicator span {
|
|
201
|
+
width: 8px;
|
|
202
|
+
height: 8px;
|
|
203
|
+
background: var(--claude-orange);
|
|
204
|
+
border-radius: 50%;
|
|
205
|
+
animation: bounce 1.4s infinite ease-in-out;
|
|
179
206
|
}
|
|
180
207
|
|
|
181
|
-
|
|
182
|
-
.
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
overflow: hidden;
|
|
208
|
+
.typing-indicator span:nth-child(1) { animation-delay: 0s; }
|
|
209
|
+
.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
|
|
210
|
+
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }
|
|
211
|
+
|
|
212
|
+
@keyframes bounce {
|
|
213
|
+
0%, 80%, 100% { transform: scale(0.6); opacity: 0.4; }
|
|
214
|
+
40% { transform: scale(1); opacity: 1; }
|
|
189
215
|
}
|
|
190
216
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
217
|
+
/* Try It Buttons */
|
|
218
|
+
.try-buttons {
|
|
219
|
+
padding: 16px 20px;
|
|
220
|
+
border-top: 1px solid rgba(255,255,255,0.1);
|
|
221
|
+
background: rgba(0,0,0,0.2);
|
|
194
222
|
}
|
|
195
223
|
|
|
196
|
-
.
|
|
224
|
+
.try-buttons h4 {
|
|
197
225
|
font-size: 11px;
|
|
198
|
-
font-weight: 600;
|
|
199
226
|
text-transform: uppercase;
|
|
200
227
|
letter-spacing: 1px;
|
|
201
228
|
color: var(--text-muted);
|
|
202
229
|
margin-bottom: 12px;
|
|
203
230
|
}
|
|
204
231
|
|
|
205
|
-
.
|
|
232
|
+
.try-buttons .scenarios {
|
|
206
233
|
display: flex;
|
|
234
|
+
flex-direction: column;
|
|
207
235
|
gap: 8px;
|
|
208
236
|
}
|
|
209
237
|
|
|
210
|
-
.
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
border
|
|
238
|
+
.scenario-btn {
|
|
239
|
+
display: flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
gap: 12px;
|
|
242
|
+
padding: 12px 16px;
|
|
243
|
+
background: rgba(255,255,255,0.05);
|
|
244
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
245
|
+
border-radius: 10px;
|
|
246
|
+
color: var(--text-primary);
|
|
217
247
|
cursor: pointer;
|
|
218
|
-
font-size: 13px;
|
|
219
|
-
font-weight: 500;
|
|
220
248
|
transition: var(--transition);
|
|
221
|
-
|
|
249
|
+
text-align: left;
|
|
222
250
|
}
|
|
223
251
|
|
|
224
|
-
.
|
|
252
|
+
.scenario-btn:hover {
|
|
225
253
|
background: rgba(78, 205, 196, 0.1);
|
|
226
|
-
color: var(--accent);
|
|
254
|
+
border-color: var(--accent);
|
|
227
255
|
}
|
|
228
256
|
|
|
229
|
-
.
|
|
230
|
-
|
|
231
|
-
|
|
257
|
+
.scenario-btn:disabled {
|
|
258
|
+
opacity: 0.5;
|
|
259
|
+
cursor: not-allowed;
|
|
232
260
|
}
|
|
233
261
|
|
|
234
|
-
.
|
|
235
|
-
|
|
262
|
+
.scenario-btn .icon {
|
|
263
|
+
font-size: 20px;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
.scenario-btn .text {
|
|
236
267
|
flex: 1;
|
|
237
|
-
overflow-y: auto;
|
|
238
|
-
padding: 12px;
|
|
239
268
|
}
|
|
240
269
|
|
|
241
|
-
.
|
|
242
|
-
|
|
270
|
+
.scenario-btn .title {
|
|
271
|
+
font-weight: 600;
|
|
272
|
+
font-size: 13px;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.scenario-btn .desc {
|
|
276
|
+
font-size: 11px;
|
|
277
|
+
color: var(--text-muted);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/* ========== RIGHT PANEL: SLACK DASHBOARD ========== */
|
|
281
|
+
.dashboard-panel {
|
|
282
|
+
background: var(--bg-primary);
|
|
283
|
+
display: flex;
|
|
284
|
+
flex-direction: column;
|
|
285
|
+
overflow: hidden;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
.dashboard-header {
|
|
289
|
+
padding: 16px 24px;
|
|
290
|
+
border-bottom: 1px solid rgba(255,255,255,0.1);
|
|
291
|
+
display: flex;
|
|
292
|
+
align-items: center;
|
|
293
|
+
justify-content: space-between;
|
|
294
|
+
background: var(--bg-secondary);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.dashboard-title {
|
|
298
|
+
display: flex;
|
|
299
|
+
align-items: center;
|
|
300
|
+
gap: 12px;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.dashboard-title h2 {
|
|
304
|
+
font-size: 18px;
|
|
305
|
+
font-weight: 600;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
.status-badge {
|
|
309
|
+
background: rgba(34, 197, 94, 0.2);
|
|
310
|
+
color: #22c55e;
|
|
311
|
+
padding: 4px 12px;
|
|
312
|
+
border-radius: 20px;
|
|
313
|
+
font-size: 12px;
|
|
314
|
+
font-weight: 500;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.dashboard-content {
|
|
318
|
+
flex: 1;
|
|
319
|
+
display: grid;
|
|
320
|
+
grid-template-columns: 280px 1fr;
|
|
321
|
+
overflow: hidden;
|
|
243
322
|
}
|
|
244
323
|
|
|
245
|
-
|
|
246
|
-
|
|
324
|
+
/* Sidebar */
|
|
325
|
+
.sidebar {
|
|
326
|
+
background: var(--bg-secondary);
|
|
327
|
+
border-right: 1px solid rgba(255,255,255,0.05);
|
|
328
|
+
display: flex;
|
|
329
|
+
flex-direction: column;
|
|
330
|
+
overflow: hidden;
|
|
247
331
|
}
|
|
248
332
|
|
|
249
|
-
.
|
|
250
|
-
|
|
251
|
-
border-
|
|
333
|
+
.sidebar-section {
|
|
334
|
+
padding: 16px;
|
|
335
|
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
.sidebar-section h3 {
|
|
339
|
+
font-size: 11px;
|
|
340
|
+
text-transform: uppercase;
|
|
341
|
+
letter-spacing: 1px;
|
|
342
|
+
color: var(--text-muted);
|
|
343
|
+
margin-bottom: 12px;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
.conversation-list {
|
|
347
|
+
list-style: none;
|
|
348
|
+
flex: 1;
|
|
349
|
+
overflow-y: auto;
|
|
350
|
+
padding: 8px;
|
|
252
351
|
}
|
|
253
352
|
|
|
254
353
|
.conversation-item {
|
|
255
|
-
padding: 14px
|
|
256
|
-
border-radius:
|
|
354
|
+
padding: 12px 14px;
|
|
355
|
+
border-radius: 8px;
|
|
257
356
|
cursor: pointer;
|
|
258
|
-
margin-bottom:
|
|
259
|
-
background: transparent;
|
|
260
|
-
transition: var(--transition);
|
|
357
|
+
margin-bottom: 4px;
|
|
261
358
|
display: flex;
|
|
262
359
|
align-items: center;
|
|
263
360
|
gap: 12px;
|
|
361
|
+
transition: var(--transition);
|
|
264
362
|
}
|
|
265
363
|
|
|
266
364
|
.conversation-item:hover {
|
|
267
|
-
background: rgba(255,
|
|
365
|
+
background: rgba(255,255,255,0.05);
|
|
268
366
|
}
|
|
269
367
|
|
|
270
368
|
.conversation-item.active {
|
|
271
369
|
background: linear-gradient(135deg, var(--accent), #3b82f6);
|
|
272
|
-
box-shadow: 0 4px 15px var(--accent-glow);
|
|
273
370
|
}
|
|
274
371
|
|
|
275
372
|
.conversation-item.active .conv-name,
|
|
276
|
-
.conversation-item.active .conv-
|
|
373
|
+
.conversation-item.active .conv-preview {
|
|
277
374
|
color: var(--bg-primary);
|
|
278
375
|
}
|
|
279
376
|
|
|
377
|
+
.conversation-item.highlight {
|
|
378
|
+
background: rgba(78, 205, 196, 0.2);
|
|
379
|
+
border: 1px solid var(--accent);
|
|
380
|
+
animation: pulse-highlight 1s ease-in-out;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
@keyframes pulse-highlight {
|
|
384
|
+
0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
|
|
385
|
+
50% { box-shadow: 0 0 20px 5px var(--accent-glow); }
|
|
386
|
+
}
|
|
387
|
+
|
|
280
388
|
.avatar {
|
|
281
|
-
width:
|
|
282
|
-
height:
|
|
283
|
-
border-radius:
|
|
389
|
+
width: 36px;
|
|
390
|
+
height: 36px;
|
|
391
|
+
border-radius: 8px;
|
|
284
392
|
display: flex;
|
|
285
393
|
align-items: center;
|
|
286
394
|
justify-content: center;
|
|
287
395
|
font-weight: 600;
|
|
288
|
-
font-size:
|
|
396
|
+
font-size: 13px;
|
|
289
397
|
flex-shrink: 0;
|
|
290
398
|
}
|
|
291
399
|
|
|
292
400
|
.avatar.dm { background: linear-gradient(135deg, #8b5cf6, #ec4899); }
|
|
293
401
|
.avatar.channel { background: linear-gradient(135deg, #3b82f6, #06b6d4); }
|
|
294
|
-
.avatar.group { background: linear-gradient(135deg, #f59e0b, #ef4444); }
|
|
295
402
|
|
|
296
|
-
.conv-info {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
}
|
|
403
|
+
.conv-info { flex: 1; min-width: 0; }
|
|
404
|
+
.conv-name { font-weight: 500; font-size: 14px; }
|
|
405
|
+
.conv-preview { font-size: 12px; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
300
406
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
color: var(--text-primary);
|
|
305
|
-
white-space: nowrap;
|
|
306
|
-
overflow: hidden;
|
|
307
|
-
text-overflow: ellipsis;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
.conv-type {
|
|
311
|
-
font-size: 12px;
|
|
312
|
-
color: var(--text-muted);
|
|
313
|
-
margin-top: 2px;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
.unread-badge {
|
|
317
|
-
background: var(--danger);
|
|
318
|
-
color: white;
|
|
319
|
-
font-size: 11px;
|
|
320
|
-
font-weight: 600;
|
|
321
|
-
padding: 2px 8px;
|
|
322
|
-
border-radius: 10px;
|
|
323
|
-
min-width: 20px;
|
|
324
|
-
text-align: center;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/* Main panel */
|
|
328
|
-
.main-panel {
|
|
329
|
-
background: var(--bg-secondary);
|
|
330
|
-
border-radius: var(--border-radius);
|
|
331
|
-
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
407
|
+
/* Main Content Area */
|
|
408
|
+
.main-area {
|
|
409
|
+
background: var(--bg-tertiary);
|
|
332
410
|
display: flex;
|
|
333
411
|
flex-direction: column;
|
|
334
412
|
overflow: hidden;
|
|
335
413
|
}
|
|
336
414
|
|
|
337
|
-
.
|
|
338
|
-
padding:
|
|
339
|
-
border-bottom: 1px solid rgba(255,
|
|
415
|
+
.main-header {
|
|
416
|
+
padding: 16px 24px;
|
|
417
|
+
border-bottom: 1px solid rgba(255,255,255,0.05);
|
|
340
418
|
display: flex;
|
|
341
419
|
align-items: center;
|
|
342
420
|
justify-content: space-between;
|
|
343
421
|
}
|
|
344
422
|
|
|
345
|
-
.
|
|
423
|
+
.main-header h3 {
|
|
424
|
+
font-size: 16px;
|
|
425
|
+
font-weight: 600;
|
|
346
426
|
display: flex;
|
|
347
427
|
align-items: center;
|
|
348
|
-
gap:
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
.channel-title h2 {
|
|
352
|
-
font-size: 18px;
|
|
353
|
-
font-weight: 600;
|
|
354
|
-
color: var(--text-primary);
|
|
428
|
+
gap: 8px;
|
|
355
429
|
}
|
|
356
430
|
|
|
357
|
-
.
|
|
431
|
+
.online-dot {
|
|
358
432
|
width: 8px;
|
|
359
433
|
height: 8px;
|
|
360
434
|
background: #22c55e;
|
|
361
435
|
border-radius: 50%;
|
|
362
436
|
}
|
|
363
437
|
|
|
364
|
-
.
|
|
365
|
-
display: flex;
|
|
366
|
-
gap: 8px;
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
.search-box input {
|
|
370
|
-
width: 250px;
|
|
371
|
-
padding: 10px 16px;
|
|
372
|
-
background: var(--bg-input);
|
|
373
|
-
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
374
|
-
border-radius: 8px;
|
|
375
|
-
color: var(--text-primary);
|
|
376
|
-
font-size: 13px;
|
|
377
|
-
font-family: inherit;
|
|
378
|
-
transition: var(--transition);
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
.search-box input:focus {
|
|
382
|
-
outline: none;
|
|
383
|
-
border-color: var(--accent);
|
|
384
|
-
box-shadow: 0 0 0 3px var(--accent-glow);
|
|
385
|
-
}
|
|
386
|
-
|
|
387
|
-
.search-box input::placeholder {
|
|
388
|
-
color: var(--text-muted);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
.search-box button {
|
|
392
|
-
padding: 10px 20px;
|
|
393
|
-
background: var(--danger);
|
|
394
|
-
color: white;
|
|
395
|
-
border: none;
|
|
396
|
-
border-radius: 8px;
|
|
397
|
-
cursor: pointer;
|
|
398
|
-
font-size: 13px;
|
|
399
|
-
font-weight: 500;
|
|
400
|
-
font-family: inherit;
|
|
401
|
-
transition: var(--transition);
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
.search-box button:hover {
|
|
405
|
-
background: #d63d56;
|
|
406
|
-
transform: translateY(-1px);
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
/* Messages */
|
|
410
|
-
.messages {
|
|
438
|
+
.messages-container {
|
|
411
439
|
flex: 1;
|
|
412
440
|
overflow-y: auto;
|
|
413
|
-
padding: 24px;
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
.messages::-webkit-scrollbar {
|
|
417
|
-
width: 6px;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
.messages::-webkit-scrollbar-thumb {
|
|
421
|
-
background: rgba(255, 255, 255, 0.1);
|
|
422
|
-
border-radius: 3px;
|
|
441
|
+
padding: 20px 24px;
|
|
423
442
|
}
|
|
424
443
|
|
|
425
444
|
.message {
|
|
426
445
|
display: flex;
|
|
427
|
-
gap:
|
|
428
|
-
padding:
|
|
429
|
-
border-radius:
|
|
446
|
+
gap: 14px;
|
|
447
|
+
padding: 12px;
|
|
448
|
+
border-radius: 10px;
|
|
430
449
|
margin-bottom: 8px;
|
|
431
450
|
transition: var(--transition);
|
|
432
|
-
animation: fadeIn 0.3s ease;
|
|
433
451
|
}
|
|
434
452
|
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
to { opacity: 1; transform: translateY(0); }
|
|
453
|
+
.message:hover {
|
|
454
|
+
background: rgba(255,255,255,0.03);
|
|
438
455
|
}
|
|
439
456
|
|
|
440
|
-
.message
|
|
441
|
-
background: rgba(
|
|
457
|
+
.message.highlight {
|
|
458
|
+
background: rgba(78, 205, 196, 0.15);
|
|
459
|
+
border: 1px solid rgba(78, 205, 196, 0.4);
|
|
442
460
|
}
|
|
443
461
|
|
|
444
462
|
.message-avatar {
|
|
445
|
-
width:
|
|
446
|
-
height:
|
|
447
|
-
border-radius:
|
|
463
|
+
width: 40px;
|
|
464
|
+
height: 40px;
|
|
465
|
+
border-radius: 10px;
|
|
448
466
|
display: flex;
|
|
449
467
|
align-items: center;
|
|
450
468
|
justify-content: center;
|
|
451
469
|
font-weight: 600;
|
|
452
|
-
font-size: 16px;
|
|
453
470
|
flex-shrink: 0;
|
|
454
471
|
}
|
|
455
472
|
|
|
456
|
-
.message-content {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
.message-header {
|
|
462
|
-
display: flex;
|
|
463
|
-
align-items: baseline;
|
|
464
|
-
gap: 12px;
|
|
465
|
-
margin-bottom: 6px;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
.message-user {
|
|
469
|
-
font-weight: 600;
|
|
470
|
-
font-size: 14px;
|
|
471
|
-
color: var(--accent);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
.message-time {
|
|
475
|
-
font-size: 12px;
|
|
476
|
-
color: var(--text-muted);
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
.message-text {
|
|
480
|
-
font-size: 14px;
|
|
481
|
-
color: var(--text-secondary);
|
|
482
|
-
line-height: 1.6;
|
|
483
|
-
white-space: pre-wrap;
|
|
484
|
-
}
|
|
473
|
+
.message-content { flex: 1; }
|
|
474
|
+
.message-header { display: flex; align-items: baseline; gap: 10px; margin-bottom: 4px; }
|
|
475
|
+
.message-user { font-weight: 600; font-size: 14px; color: var(--accent); }
|
|
476
|
+
.message-time { font-size: 12px; color: var(--text-muted); }
|
|
477
|
+
.message-text { font-size: 14px; color: var(--text-secondary); line-height: 1.5; }
|
|
485
478
|
|
|
486
479
|
.message-text code {
|
|
487
|
-
background: rgba(0,
|
|
480
|
+
background: rgba(0,0,0,0.3);
|
|
488
481
|
padding: 2px 6px;
|
|
489
482
|
border-radius: 4px;
|
|
490
|
-
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
491
|
-
font-size: 13px;
|
|
492
483
|
color: #f472b6;
|
|
484
|
+
font-family: monospace;
|
|
493
485
|
}
|
|
494
486
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
border-radius:
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
487
|
+
/* User Profile Card */
|
|
488
|
+
.user-card {
|
|
489
|
+
background: var(--bg-secondary);
|
|
490
|
+
border-radius: 12px;
|
|
491
|
+
padding: 24px;
|
|
492
|
+
text-align: center;
|
|
493
|
+
max-width: 300px;
|
|
494
|
+
margin: 40px auto;
|
|
495
|
+
border: 1px solid rgba(255,255,255,0.1);
|
|
496
|
+
display: none;
|
|
502
497
|
}
|
|
503
498
|
|
|
504
|
-
.
|
|
505
|
-
background: none;
|
|
506
|
-
padding: 0;
|
|
507
|
-
color: #e2e8f0;
|
|
499
|
+
.user-card.visible {
|
|
508
500
|
display: block;
|
|
509
|
-
|
|
501
|
+
animation: fadeIn 0.4s ease;
|
|
510
502
|
}
|
|
511
503
|
|
|
512
|
-
.
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
.reaction {
|
|
519
|
-
background: rgba(255, 255, 255, 0.05);
|
|
520
|
-
padding: 4px 10px;
|
|
521
|
-
border-radius: 16px;
|
|
522
|
-
font-size: 13px;
|
|
504
|
+
.user-card .profile-avatar {
|
|
505
|
+
width: 80px;
|
|
506
|
+
height: 80px;
|
|
507
|
+
border-radius: 20px;
|
|
508
|
+
margin: 0 auto 16px;
|
|
523
509
|
display: flex;
|
|
524
510
|
align-items: center;
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
511
|
+
justify-content: center;
|
|
512
|
+
font-size: 32px;
|
|
513
|
+
font-weight: 700;
|
|
514
|
+
background: linear-gradient(135deg, #8b5cf6, #ec4899);
|
|
528
515
|
}
|
|
529
516
|
|
|
530
|
-
.
|
|
531
|
-
|
|
517
|
+
.user-card h4 {
|
|
518
|
+
font-size: 20px;
|
|
519
|
+
margin-bottom: 4px;
|
|
532
520
|
}
|
|
533
521
|
|
|
534
|
-
.
|
|
522
|
+
.user-card .title {
|
|
535
523
|
color: var(--text-muted);
|
|
536
|
-
font-size:
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
.thread-indicator {
|
|
540
|
-
display: flex;
|
|
541
|
-
align-items: center;
|
|
542
|
-
gap: 8px;
|
|
543
|
-
margin-top: 12px;
|
|
544
|
-
padding: 8px 12px;
|
|
545
|
-
background: rgba(78, 205, 196, 0.1);
|
|
546
|
-
border-radius: 8px;
|
|
547
|
-
font-size: 13px;
|
|
548
|
-
color: var(--accent);
|
|
549
|
-
cursor: pointer;
|
|
550
|
-
transition: var(--transition);
|
|
551
|
-
width: fit-content;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
.thread-indicator:hover {
|
|
555
|
-
background: rgba(78, 205, 196, 0.15);
|
|
524
|
+
font-size: 14px;
|
|
525
|
+
margin-bottom: 16px;
|
|
556
526
|
}
|
|
557
527
|
|
|
558
|
-
|
|
559
|
-
.send-box {
|
|
560
|
-
padding: 20px 24px;
|
|
561
|
-
border-top: 1px solid rgba(255, 255, 255, 0.05);
|
|
528
|
+
.user-card .stats {
|
|
562
529
|
display: flex;
|
|
563
|
-
|
|
530
|
+
justify-content: center;
|
|
531
|
+
gap: 24px;
|
|
532
|
+
padding-top: 16px;
|
|
533
|
+
border-top: 1px solid rgba(255,255,255,0.1);
|
|
564
534
|
}
|
|
565
535
|
|
|
566
|
-
.
|
|
567
|
-
|
|
568
|
-
padding: 14px 20px;
|
|
569
|
-
background: var(--bg-input);
|
|
570
|
-
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
571
|
-
border-radius: 12px;
|
|
572
|
-
color: var(--text-primary);
|
|
573
|
-
font-size: 14px;
|
|
574
|
-
font-family: inherit;
|
|
575
|
-
transition: var(--transition);
|
|
536
|
+
.user-card .stat {
|
|
537
|
+
text-align: center;
|
|
576
538
|
}
|
|
577
539
|
|
|
578
|
-
.
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
540
|
+
.user-card .stat-value {
|
|
541
|
+
font-size: 20px;
|
|
542
|
+
font-weight: 700;
|
|
543
|
+
color: var(--accent);
|
|
582
544
|
}
|
|
583
545
|
|
|
584
|
-
.
|
|
546
|
+
.user-card .stat-label {
|
|
547
|
+
font-size: 11px;
|
|
585
548
|
color: var(--text-muted);
|
|
549
|
+
text-transform: uppercase;
|
|
586
550
|
}
|
|
587
551
|
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
background: linear-gradient(135deg, var(--accent), #3b82f6);
|
|
591
|
-
color: var(--bg-primary);
|
|
592
|
-
border: none;
|
|
593
|
-
border-radius: 12px;
|
|
594
|
-
cursor: pointer;
|
|
595
|
-
font-size: 14px;
|
|
596
|
-
font-weight: 600;
|
|
597
|
-
font-family: inherit;
|
|
598
|
-
transition: var(--transition);
|
|
599
|
-
box-shadow: 0 4px 15px var(--accent-glow);
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
.send-box button:hover {
|
|
603
|
-
transform: translateY(-2px);
|
|
604
|
-
box-shadow: 0 6px 20px var(--accent-glow);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
/* Footer */
|
|
608
|
-
.footer {
|
|
552
|
+
/* Empty State */
|
|
553
|
+
.empty-state {
|
|
609
554
|
text-align: center;
|
|
610
|
-
padding:
|
|
555
|
+
padding: 60px 20px;
|
|
611
556
|
color: var(--text-muted);
|
|
612
|
-
font-size: 13px;
|
|
613
557
|
}
|
|
614
558
|
|
|
615
|
-
.
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
.footer a:hover {
|
|
621
|
-
text-decoration: underline;
|
|
559
|
+
.empty-state .icon {
|
|
560
|
+
font-size: 48px;
|
|
561
|
+
margin-bottom: 16px;
|
|
622
562
|
}
|
|
623
563
|
|
|
624
|
-
/* Mobile
|
|
625
|
-
@media (max-width:
|
|
626
|
-
.
|
|
564
|
+
/* Mobile */
|
|
565
|
+
@media (max-width: 1000px) {
|
|
566
|
+
.split-container {
|
|
627
567
|
grid-template-columns: 1fr;
|
|
628
|
-
height: auto;
|
|
629
568
|
}
|
|
630
|
-
.
|
|
631
|
-
|
|
569
|
+
.claude-panel {
|
|
570
|
+
display: none;
|
|
632
571
|
}
|
|
633
|
-
.
|
|
634
|
-
|
|
572
|
+
.dashboard-content {
|
|
573
|
+
grid-template-columns: 1fr;
|
|
635
574
|
}
|
|
636
|
-
.
|
|
637
|
-
|
|
575
|
+
.sidebar {
|
|
576
|
+
display: none;
|
|
638
577
|
}
|
|
639
578
|
}
|
|
640
579
|
</style>
|
|
641
580
|
</head>
|
|
642
581
|
<body>
|
|
643
|
-
|
|
582
|
+
<!-- Preview Banner -->
|
|
583
|
+
<div class="preview-banner">
|
|
584
|
+
STATIC PREVIEW - No real data. Run <code>npm run web</code> for live dashboard.
|
|
585
|
+
<a href="https://github.com/jtalk22/slack-mcp-server">View on GitHub</a>
|
|
586
|
+
</div>
|
|
644
587
|
|
|
645
|
-
<div class="container">
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
588
|
+
<div class="split-container">
|
|
589
|
+
<!-- LEFT: Claude Chat Panel -->
|
|
590
|
+
<div class="claude-panel">
|
|
591
|
+
<div class="claude-header">
|
|
592
|
+
<div class="claude-logo">C</div>
|
|
649
593
|
<div>
|
|
650
|
-
<
|
|
651
|
-
<div class="subtitle">
|
|
594
|
+
<h2>Claude</h2>
|
|
595
|
+
<div class="subtitle">with Slack MCP tools</div>
|
|
652
596
|
</div>
|
|
597
|
+
<button class="reset-btn" onclick="resetDemo()">Reset Demo</button>
|
|
653
598
|
</div>
|
|
654
|
-
<div class="demo-badge">Interactive Demo</div>
|
|
655
|
-
</header>
|
|
656
599
|
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
600
|
+
<div class="claude-chat" id="claudeChat">
|
|
601
|
+
<div class="chat-message claude">
|
|
602
|
+
<div class="bubble">
|
|
603
|
+
Hi! I have access to your Slack workspace through MCP tools. I can search messages, list conversations, look up users, and more.
|
|
604
|
+
<br><br>
|
|
605
|
+
Try one of the scenarios below to see how it works!
|
|
606
|
+
</div>
|
|
607
|
+
</div>
|
|
661
608
|
</div>
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
<
|
|
665
|
-
<
|
|
609
|
+
|
|
610
|
+
<div class="try-buttons">
|
|
611
|
+
<h4>Try a Scenario</h4>
|
|
612
|
+
<div class="scenarios">
|
|
613
|
+
<button class="scenario-btn" onclick="runScenario('findKey')" id="btn-findKey">
|
|
614
|
+
<span class="icon">🔑</span>
|
|
615
|
+
<div class="text">
|
|
616
|
+
<div class="title">Find the API Key</div>
|
|
617
|
+
<div class="desc">Search DMs for sensitive information</div>
|
|
618
|
+
</div>
|
|
619
|
+
</button>
|
|
620
|
+
<button class="scenario-btn" onclick="runScenario('listChannels')" id="btn-listChannels">
|
|
621
|
+
<span class="icon">📋</span>
|
|
622
|
+
<div class="text">
|
|
623
|
+
<div class="title">List Channels</div>
|
|
624
|
+
<div class="desc">Get all workspace channels</div>
|
|
625
|
+
</div>
|
|
626
|
+
</button>
|
|
627
|
+
<button class="scenario-btn" onclick="runScenario('whoIsAlex')" id="btn-whoIsAlex">
|
|
628
|
+
<span class="icon">👤</span>
|
|
629
|
+
<div class="text">
|
|
630
|
+
<div class="title">Who is Alex?</div>
|
|
631
|
+
<div class="desc">Look up user profile and activity</div>
|
|
632
|
+
</div>
|
|
633
|
+
</button>
|
|
634
|
+
</div>
|
|
666
635
|
</div>
|
|
667
636
|
</div>
|
|
668
637
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
<
|
|
674
|
-
|
|
675
|
-
<button onclick="showChannels()">Channels</button>
|
|
676
|
-
</div>
|
|
677
|
-
</div>
|
|
678
|
-
<ul id="conversationList" class="conversation-list">
|
|
679
|
-
<!-- Populated by JS -->
|
|
680
|
-
</ul>
|
|
681
|
-
</aside>
|
|
682
|
-
|
|
683
|
-
<main class="main-panel">
|
|
684
|
-
<div class="panel-header">
|
|
685
|
-
<div class="channel-title">
|
|
686
|
-
<h2 id="channelName">Sarah Johnson</h2>
|
|
687
|
-
<div class="online-status"></div>
|
|
688
|
-
</div>
|
|
689
|
-
<div class="search-box">
|
|
690
|
-
<input type="text" placeholder="Search messages..." id="searchQuery">
|
|
691
|
-
<button onclick="searchDemo()">Search</button>
|
|
692
|
-
</div>
|
|
638
|
+
<!-- RIGHT: Slack Dashboard -->
|
|
639
|
+
<div class="dashboard-panel">
|
|
640
|
+
<div class="dashboard-header">
|
|
641
|
+
<div class="dashboard-title">
|
|
642
|
+
<h2>Slack Dashboard</h2>
|
|
643
|
+
<span class="status-badge">Connected</span>
|
|
693
644
|
</div>
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
<!-- Populated by JS -->
|
|
645
|
+
<div style="color: var(--text-muted); font-size: 13px;">
|
|
646
|
+
alex.chen @ Acme Corp
|
|
697
647
|
</div>
|
|
648
|
+
</div>
|
|
698
649
|
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
<
|
|
702
|
-
|
|
703
|
-
|
|
650
|
+
<div class="dashboard-content">
|
|
651
|
+
<aside class="sidebar">
|
|
652
|
+
<div class="sidebar-section">
|
|
653
|
+
<h3>Conversations</h3>
|
|
654
|
+
</div>
|
|
655
|
+
<ul class="conversation-list" id="conversationList">
|
|
656
|
+
<!-- Populated by JS -->
|
|
657
|
+
</ul>
|
|
658
|
+
</aside>
|
|
659
|
+
|
|
660
|
+
<main class="main-area">
|
|
661
|
+
<div class="main-header">
|
|
662
|
+
<h3 id="mainTitle"><span class="online-dot"></span> Select a conversation</h3>
|
|
663
|
+
</div>
|
|
664
|
+
<div class="messages-container" id="messagesContainer">
|
|
665
|
+
<div class="empty-state">
|
|
666
|
+
<div class="icon">💬</div>
|
|
667
|
+
<div>Click a scenario to see Claude interact with your Slack data</div>
|
|
668
|
+
</div>
|
|
669
|
+
</div>
|
|
670
|
+
</main>
|
|
671
|
+
</div>
|
|
704
672
|
</div>
|
|
705
|
-
|
|
706
|
-
<footer class="footer">
|
|
707
|
-
This is an interactive demo with mock data. <a href="https://github.com/jtalk22/slack-mcp-server">View on GitHub</a> to set up your own instance.
|
|
708
|
-
</footer>
|
|
709
673
|
</div>
|
|
710
674
|
|
|
711
675
|
<script>
|
|
712
|
-
//
|
|
713
|
-
const
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
];
|
|
720
|
-
|
|
721
|
-
const mockChannels = [
|
|
722
|
-
{ id: 'C001', name: '#engineering', type: 'channel', unread: 12, initials: '#', avatarClass: 'channel' },
|
|
723
|
-
{ id: 'C002', name: '#product', type: 'channel', unread: 0, initials: '#', avatarClass: 'channel' },
|
|
724
|
-
{ id: 'C003', name: '#random', type: 'channel', unread: 5, initials: '#', avatarClass: 'channel' },
|
|
725
|
-
{ id: 'C004', name: '#announcements', type: 'channel', unread: 0, initials: '#', avatarClass: 'channel' },
|
|
726
|
-
];
|
|
727
|
-
|
|
728
|
-
const mockMessages = {
|
|
729
|
-
'D001': [
|
|
730
|
-
{ user: 'Sarah Johnson', time: '10:32 AM', text: 'Hey! Did you get a chance to review the PR I submitted yesterday?', initials: 'SJ', reactions: [{ emoji: '1', count: 1 }] },
|
|
731
|
-
{ user: 'You', time: '10:35 AM', text: 'Yes! Just finished reviewing it. Left a few comments but overall looks great. The new caching layer should really help with performance.', initials: 'AC', reactions: [] },
|
|
732
|
-
{ user: 'Sarah Johnson', time: '10:38 AM', text: 'Awesome, thanks for the quick turnaround! I\'ll address those comments now.', initials: 'SJ', reactions: [{ emoji: '+1', count: 1 }] },
|
|
733
|
-
{ user: 'Sarah Johnson', time: '10:42 AM', text: 'Quick question - for the `fetchUserData` function, should I use `async/await` or stick with promises?', initials: 'SJ', reactions: [], hasThread: true, threadCount: 4 },
|
|
734
|
-
{ user: 'You', time: '10:45 AM', text: 'I\'d go with async/await - it\'s more readable and matches the rest of our codebase. Here\'s an example:\n\n```javascript\nasync function fetchUserData(userId) {\n const response = await api.get(`/users/${userId}`);\n return response.data;\n}\n```', initials: 'AC', reactions: [{ emoji: 'heart', count: 2 }] },
|
|
735
|
-
{ user: 'Sarah Johnson', time: '10:48 AM', text: 'Perfect, that makes sense. I\'ll update the PR with these changes. Should be ready for another review in about an hour.', initials: 'SJ', reactions: [] },
|
|
676
|
+
// ========== MOCK DATA ==========
|
|
677
|
+
const mockData = {
|
|
678
|
+
dms: [
|
|
679
|
+
{ id: 'D001', name: 'Sarah Johnson', initials: 'SJ', preview: 'The API key is sk-abc123...', type: 'dm' },
|
|
680
|
+
{ id: 'D002', name: 'Mike Chen', initials: 'MC', preview: 'Are we still on for 2pm?', type: 'dm' },
|
|
681
|
+
{ id: 'D003', name: 'Alex Chen', initials: 'AC', preview: 'I pushed the fix to main', type: 'dm' },
|
|
682
|
+
{ id: 'D004', name: 'Emily Davis', initials: 'ED', preview: 'Thanks for the review!', type: 'dm' },
|
|
736
683
|
],
|
|
737
|
-
|
|
738
|
-
{
|
|
739
|
-
{
|
|
740
|
-
{
|
|
684
|
+
channels: [
|
|
685
|
+
{ id: 'C001', name: '#engineering', initials: '#', preview: 'Deploy complete', type: 'channel' },
|
|
686
|
+
{ id: 'C002', name: '#product', initials: '#', preview: 'Q4 roadmap finalized', type: 'channel' },
|
|
687
|
+
{ id: 'C003', name: '#random', initials: '#', preview: 'Anyone up for lunch?', type: 'channel' },
|
|
688
|
+
{ id: 'C004', name: '#incidents', initials: '#', preview: 'All clear', type: 'channel' },
|
|
689
|
+
{ id: 'C005', name: '#design', initials: '#', preview: 'New mockups ready', type: 'channel' },
|
|
741
690
|
],
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
691
|
+
messages: {
|
|
692
|
+
'D001': [
|
|
693
|
+
{ user: 'Sarah Johnson', initials: 'SJ', time: '2:32 PM', text: 'Hey, can you send me the API key for the staging environment?' },
|
|
694
|
+
{ user: 'You', initials: 'AC', time: '2:35 PM', text: 'Sure, one sec...' },
|
|
695
|
+
{ user: 'You', initials: 'AC', time: '2:36 PM', text: 'Here it is: <code>sk-abc123-staging-key-xyz789</code>', highlight: true },
|
|
696
|
+
{ user: 'Sarah Johnson', initials: 'SJ', time: '2:37 PM', text: 'Got it, thanks!' },
|
|
697
|
+
],
|
|
698
|
+
'D003': [
|
|
699
|
+
{ user: 'Alex Chen', initials: 'AC', time: '11:20 AM', text: 'I pushed the fix to main' },
|
|
700
|
+
{ user: 'You', initials: 'YO', time: '11:22 AM', text: 'Nice! I\'ll review it after lunch' },
|
|
701
|
+
{ user: 'Alex Chen', initials: 'AC', time: '11:23 AM', text: 'Sounds good. Let me know if you have questions' },
|
|
702
|
+
]
|
|
703
|
+
},
|
|
704
|
+
users: {
|
|
705
|
+
'alex': {
|
|
706
|
+
name: 'Alex Chen',
|
|
707
|
+
initials: 'AC',
|
|
708
|
+
title: 'Senior Engineer',
|
|
709
|
+
messages: 847,
|
|
710
|
+
channels: 12
|
|
711
|
+
}
|
|
712
|
+
}
|
|
749
713
|
};
|
|
750
714
|
|
|
751
|
-
let
|
|
752
|
-
let currentChannel = 'D001';
|
|
715
|
+
let isRunning = false;
|
|
753
716
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
717
|
+
// ========== RENDERING ==========
|
|
718
|
+
function renderConversations(list, highlightId = null) {
|
|
719
|
+
const container = document.getElementById('conversationList');
|
|
720
|
+
container.innerHTML = list.map(c => `
|
|
721
|
+
<li class="conversation-item ${c.id === highlightId ? 'highlight active' : ''}" data-id="${c.id}">
|
|
722
|
+
<div class="avatar ${c.type}">${c.initials}</div>
|
|
759
723
|
<div class="conv-info">
|
|
760
724
|
<div class="conv-name">${c.name}</div>
|
|
761
|
-
<div class="conv-
|
|
725
|
+
<div class="conv-preview">${c.preview}</div>
|
|
762
726
|
</div>
|
|
763
|
-
${c.unread > 0 ? `<div class="unread-badge">${c.unread}</div>` : ''}
|
|
764
727
|
</li>
|
|
765
728
|
`).join('');
|
|
766
729
|
}
|
|
767
730
|
|
|
768
|
-
function renderMessages(channelId) {
|
|
769
|
-
const container = document.getElementById('
|
|
770
|
-
const messages =
|
|
731
|
+
function renderMessages(channelId, highlightIndex = -1) {
|
|
732
|
+
const container = document.getElementById('messagesContainer');
|
|
733
|
+
const messages = mockData.messages[channelId] || [];
|
|
771
734
|
|
|
772
735
|
if (messages.length === 0) {
|
|
773
|
-
container.innerHTML = '<div
|
|
736
|
+
container.innerHTML = '<div class="empty-state"><div class="icon">💬</div><div>No messages</div></div>';
|
|
774
737
|
return;
|
|
775
738
|
}
|
|
776
739
|
|
|
777
740
|
container.innerHTML = messages.map((m, i) => `
|
|
778
|
-
<div class="message
|
|
779
|
-
<div class="message-avatar" style="background: linear-gradient(135deg, ${
|
|
741
|
+
<div class="message ${m.highlight || i === highlightIndex ? 'highlight' : ''}">
|
|
742
|
+
<div class="message-avatar" style="background: linear-gradient(135deg, ${getColor(m.initials)})">${m.initials}</div>
|
|
780
743
|
<div class="message-content">
|
|
781
744
|
<div class="message-header">
|
|
782
745
|
<span class="message-user">${m.user}</span>
|
|
783
746
|
<span class="message-time">${m.time}</span>
|
|
784
747
|
</div>
|
|
785
|
-
<div class="message-text">${
|
|
786
|
-
${m.reactions && m.reactions.length > 0 ? `
|
|
787
|
-
<div class="message-reactions">
|
|
788
|
-
${m.reactions.map(r => `<div class="reaction">${getEmoji(r.emoji)} <span class="reaction-count">${r.count}</span></div>`).join('')}
|
|
789
|
-
</div>
|
|
790
|
-
` : ''}
|
|
791
|
-
${m.hasThread ? `
|
|
792
|
-
<div class="thread-indicator">
|
|
793
|
-
<span>View thread</span>
|
|
794
|
-
<span style="opacity: 0.7">${m.threadCount} replies</span>
|
|
795
|
-
</div>
|
|
796
|
-
` : ''}
|
|
748
|
+
<div class="message-text">${m.text}</div>
|
|
797
749
|
</div>
|
|
798
750
|
</div>
|
|
799
751
|
`).join('');
|
|
752
|
+
}
|
|
800
753
|
|
|
801
|
-
|
|
754
|
+
function showUserCard(userId) {
|
|
755
|
+
const user = mockData.users[userId];
|
|
756
|
+
if (!user) return;
|
|
757
|
+
|
|
758
|
+
// Render the user card directly into the container
|
|
759
|
+
document.getElementById('messagesContainer').innerHTML = `
|
|
760
|
+
<div class="user-card visible">
|
|
761
|
+
<div class="profile-avatar">${user.initials}</div>
|
|
762
|
+
<h4>${user.name}</h4>
|
|
763
|
+
<div class="title">${user.title}</div>
|
|
764
|
+
<div class="stats">
|
|
765
|
+
<div class="stat">
|
|
766
|
+
<div class="stat-value">${user.messages}</div>
|
|
767
|
+
<div class="stat-label">Messages</div>
|
|
768
|
+
</div>
|
|
769
|
+
<div class="stat">
|
|
770
|
+
<div class="stat-value">${user.channels}</div>
|
|
771
|
+
<div class="stat-label">Channels</div>
|
|
772
|
+
</div>
|
|
773
|
+
</div>
|
|
774
|
+
</div>
|
|
775
|
+
`;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
function getColor(initials) {
|
|
779
|
+
const colors = [
|
|
780
|
+
'#8b5cf6, #ec4899',
|
|
781
|
+
'#3b82f6, #06b6d4',
|
|
782
|
+
'#f59e0b, #ef4444',
|
|
783
|
+
'#10b981, #3b82f6'
|
|
784
|
+
];
|
|
785
|
+
return colors[initials.charCodeAt(0) % colors.length];
|
|
802
786
|
}
|
|
803
787
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
788
|
+
// ========== CLAUDE CHAT ==========
|
|
789
|
+
function addUserMessage(text) {
|
|
790
|
+
const chat = document.getElementById('claudeChat');
|
|
791
|
+
chat.innerHTML += `
|
|
792
|
+
<div class="chat-message user">
|
|
793
|
+
<div class="bubble">${text}</div>
|
|
794
|
+
</div>
|
|
795
|
+
`;
|
|
796
|
+
chat.scrollTop = chat.scrollHeight;
|
|
810
797
|
}
|
|
811
798
|
|
|
812
|
-
function
|
|
813
|
-
const
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
'tada': '🎉',
|
|
821
|
-
'thinking': '🤔'
|
|
822
|
-
};
|
|
823
|
-
return emojis[name] || name;
|
|
799
|
+
function addClaudeMessage(html) {
|
|
800
|
+
const chat = document.getElementById('claudeChat');
|
|
801
|
+
chat.innerHTML += `
|
|
802
|
+
<div class="chat-message claude">
|
|
803
|
+
<div class="bubble">${html}</div>
|
|
804
|
+
</div>
|
|
805
|
+
`;
|
|
806
|
+
chat.scrollTop = chat.scrollHeight;
|
|
824
807
|
}
|
|
825
808
|
|
|
826
|
-
function
|
|
827
|
-
const
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
809
|
+
function addToolCall(toolName, params) {
|
|
810
|
+
const chat = document.getElementById('claudeChat');
|
|
811
|
+
chat.innerHTML += `
|
|
812
|
+
<div class="chat-message claude">
|
|
813
|
+
<div class="bubble">
|
|
814
|
+
<div class="tool-call">
|
|
815
|
+
<div class="tool-name">${toolName}</div>
|
|
816
|
+
<div class="tool-params">${params}</div>
|
|
817
|
+
</div>
|
|
818
|
+
</div>
|
|
819
|
+
</div>
|
|
820
|
+
`;
|
|
821
|
+
chat.scrollTop = chat.scrollHeight;
|
|
836
822
|
}
|
|
837
823
|
|
|
838
|
-
function
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
824
|
+
function showTyping() {
|
|
825
|
+
const chat = document.getElementById('claudeChat');
|
|
826
|
+
const id = 'typing-' + Date.now();
|
|
827
|
+
chat.innerHTML += `
|
|
828
|
+
<div class="chat-message claude" id="${id}">
|
|
829
|
+
<div class="bubble">
|
|
830
|
+
<div class="typing-indicator">
|
|
831
|
+
<span></span><span></span><span></span>
|
|
832
|
+
</div>
|
|
833
|
+
</div>
|
|
834
|
+
</div>
|
|
835
|
+
`;
|
|
836
|
+
chat.scrollTop = chat.scrollHeight;
|
|
837
|
+
return id;
|
|
843
838
|
}
|
|
844
839
|
|
|
845
|
-
function
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
event.target.classList.add('active');
|
|
849
|
-
renderConversations(mockChannels);
|
|
840
|
+
function removeTyping(id) {
|
|
841
|
+
const el = document.getElementById(id);
|
|
842
|
+
if (el) el.remove();
|
|
850
843
|
}
|
|
851
844
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
845
|
+
// ========== SCENARIOS ==========
|
|
846
|
+
async function runScenario(scenario) {
|
|
847
|
+
if (isRunning) return;
|
|
848
|
+
isRunning = true;
|
|
855
849
|
|
|
856
|
-
//
|
|
857
|
-
document.querySelectorAll('.
|
|
858
|
-
event.target.closest('.conversation-item').classList.add('active');
|
|
850
|
+
// Disable all buttons
|
|
851
|
+
document.querySelectorAll('.scenario-btn').forEach(btn => btn.disabled = true);
|
|
859
852
|
|
|
860
|
-
|
|
853
|
+
switch (scenario) {
|
|
854
|
+
case 'findKey':
|
|
855
|
+
await scenarioFindKey();
|
|
856
|
+
break;
|
|
857
|
+
case 'listChannels':
|
|
858
|
+
await scenarioListChannels();
|
|
859
|
+
break;
|
|
860
|
+
case 'whoIsAlex':
|
|
861
|
+
await scenarioWhoIsAlex();
|
|
862
|
+
break;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Re-enable buttons
|
|
866
|
+
document.querySelectorAll('.scenario-btn').forEach(btn => btn.disabled = false);
|
|
867
|
+
isRunning = false;
|
|
861
868
|
}
|
|
862
869
|
|
|
863
|
-
function
|
|
864
|
-
|
|
865
|
-
|
|
870
|
+
async function scenarioFindKey() {
|
|
871
|
+
// User asks
|
|
872
|
+
addUserMessage("Can you find the API key that Sarah sent me?");
|
|
873
|
+
await delay(500);
|
|
866
874
|
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
875
|
+
// Claude thinks
|
|
876
|
+
const typing1 = showTyping();
|
|
877
|
+
await delay(600);
|
|
878
|
+
removeTyping(typing1);
|
|
879
|
+
|
|
880
|
+
// Tool call
|
|
881
|
+
addToolCall('slack_search_messages', '{ query: "API key", count: 10 }');
|
|
882
|
+
await delay(900);
|
|
883
|
+
|
|
884
|
+
// Dashboard updates - show DMs with Sarah highlighted
|
|
885
|
+
renderConversations(mockData.dms, 'D001');
|
|
886
|
+
document.getElementById('mainTitle').innerHTML = '<span class="online-dot"></span> Sarah Johnson';
|
|
887
|
+
await delay(300);
|
|
888
|
+
|
|
889
|
+
// Show messages with the key highlighted
|
|
890
|
+
renderMessages('D001');
|
|
891
|
+
await delay(600);
|
|
892
|
+
|
|
893
|
+
// Claude responds
|
|
894
|
+
const typing2 = showTyping();
|
|
895
|
+
await delay(500);
|
|
896
|
+
removeTyping(typing2);
|
|
897
|
+
|
|
898
|
+
addClaudeMessage(`Found it! Sarah asked for the staging API key on your DM. You sent her:<br><br><code>sk-abc123-staging-key-xyz789</code><br><br>This was shared at 2:36 PM today.`);
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
async function scenarioListChannels() {
|
|
902
|
+
addUserMessage("What channels am I in?");
|
|
903
|
+
await delay(500);
|
|
904
|
+
|
|
905
|
+
const typing1 = showTyping();
|
|
906
|
+
await delay(600);
|
|
907
|
+
removeTyping(typing1);
|
|
908
|
+
|
|
909
|
+
addToolCall('slack_list_conversations', '{ types: "public_channel,private_channel" }');
|
|
910
|
+
await delay(900);
|
|
911
|
+
|
|
912
|
+
// Dashboard updates to show channels
|
|
913
|
+
renderConversations(mockData.channels);
|
|
914
|
+
document.getElementById('mainTitle').innerHTML = 'Channels';
|
|
915
|
+
document.getElementById('messagesContainer').innerHTML = `
|
|
916
|
+
<div class="empty-state">
|
|
917
|
+
<div class="icon">📋</div>
|
|
918
|
+
<div>5 channels loaded</div>
|
|
878
919
|
</div>
|
|
879
920
|
`;
|
|
921
|
+
await delay(500);
|
|
922
|
+
|
|
923
|
+
const typing2 = showTyping();
|
|
924
|
+
await delay(600);
|
|
925
|
+
removeTyping(typing2);
|
|
926
|
+
|
|
927
|
+
addClaudeMessage(`You're a member of <strong>5 channels</strong>:<br><br>
|
|
928
|
+
• <strong>#engineering</strong> - Latest: "Deploy complete"<br>
|
|
929
|
+
• <strong>#product</strong> - Q4 roadmap discussions<br>
|
|
930
|
+
• <strong>#random</strong> - Social chat<br>
|
|
931
|
+
• <strong>#incidents</strong> - On-call alerts<br>
|
|
932
|
+
• <strong>#design</strong> - Design team updates<br><br>
|
|
933
|
+
The most active appears to be #engineering.`);
|
|
880
934
|
}
|
|
881
935
|
|
|
882
|
-
function
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (!text) return;
|
|
936
|
+
async function scenarioWhoIsAlex() {
|
|
937
|
+
addUserMessage("Who is Alex? What does he do here?");
|
|
938
|
+
await delay(500);
|
|
886
939
|
|
|
887
|
-
const
|
|
888
|
-
|
|
940
|
+
const typing1 = showTyping();
|
|
941
|
+
await delay(600);
|
|
942
|
+
removeTyping(typing1);
|
|
889
943
|
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
944
|
+
addToolCall('slack_users_info', '{ user_id: "U_ALEX" }');
|
|
945
|
+
await delay(600);
|
|
946
|
+
|
|
947
|
+
// Highlight Alex in DMs
|
|
948
|
+
renderConversations(mockData.dms, 'D003');
|
|
949
|
+
await delay(300);
|
|
950
|
+
|
|
951
|
+
addToolCall('slack_search_messages', '{ query: "from:alex", count: 50 }');
|
|
952
|
+
await delay(900);
|
|
953
|
+
|
|
954
|
+
// Show user profile card
|
|
955
|
+
document.getElementById('mainTitle').innerHTML = '<span class="online-dot"></span> User Profile';
|
|
956
|
+
showUserCard('alex');
|
|
957
|
+
await delay(500);
|
|
958
|
+
|
|
959
|
+
const typing2 = showTyping();
|
|
960
|
+
await delay(700);
|
|
961
|
+
removeTyping(typing2);
|
|
962
|
+
|
|
963
|
+
addClaudeMessage(`<strong>Alex Chen</strong> is a Senior Engineer on your team.<br><br>
|
|
964
|
+
📊 <strong>Activity:</strong> 847 messages across 12 channels<br>
|
|
965
|
+
💬 <strong>Most active in:</strong> #engineering, #incidents<br>
|
|
966
|
+
🕐 <strong>Recent:</strong> Pushed a fix to main branch today<br><br>
|
|
967
|
+
Based on his messages, he focuses on backend infrastructure and is often involved in incident response.`);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
function delay(ms) {
|
|
971
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
function resetDemo() {
|
|
975
|
+
// Reset chat to initial state
|
|
976
|
+
document.getElementById('claudeChat').innerHTML = `
|
|
977
|
+
<div class="chat-message claude">
|
|
978
|
+
<div class="bubble">
|
|
979
|
+
Hi! I have access to your Slack workspace through MCP tools. I can search messages, list conversations, look up users, and more.
|
|
980
|
+
<br><br>
|
|
981
|
+
Try one of the scenarios below to see how it works!
|
|
899
982
|
</div>
|
|
900
983
|
</div>
|
|
901
984
|
`;
|
|
902
985
|
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
986
|
+
// Reset dashboard
|
|
987
|
+
renderConversations(mockData.dms);
|
|
988
|
+
document.getElementById('mainTitle').innerHTML = '<span class="online-dot"></span> Select a conversation';
|
|
989
|
+
document.getElementById('messagesContainer').innerHTML = `
|
|
990
|
+
<div class="empty-state">
|
|
991
|
+
<div class="icon">💬</div>
|
|
992
|
+
<div>Click a scenario to see Claude interact with your Slack data</div>
|
|
993
|
+
</div>
|
|
994
|
+
`;
|
|
906
995
|
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
renderMessages('D001');
|
|
996
|
+
isRunning = false;
|
|
997
|
+
}
|
|
910
998
|
|
|
911
|
-
//
|
|
912
|
-
|
|
913
|
-
if (e.key === 'Enter') sendDemo();
|
|
914
|
-
});
|
|
915
|
-
document.getElementById('searchQuery').addEventListener('keypress', (e) => {
|
|
916
|
-
if (e.key === 'Enter') searchDemo();
|
|
917
|
-
});
|
|
999
|
+
// ========== INIT ==========
|
|
1000
|
+
renderConversations(mockData.dms);
|
|
918
1001
|
</script>
|
|
919
1002
|
</body>
|
|
920
1003
|
</html>
|