@thehoneyjar/sigil-hud 0.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.
- package/LICENSE.md +660 -0
- package/README.md +146 -0
- package/dist/index.d.ts +911 -0
- package/dist/index.js +3079 -0
- package/package.json +68 -0
- package/src/components/DataSourceIndicator.tsx +185 -0
- package/src/components/DiagnosticsPanel.tsx +444 -0
- package/src/components/FeedbackPrompt.tsx +348 -0
- package/src/components/HudPanel.tsx +179 -0
- package/src/components/HudTrigger.tsx +81 -0
- package/src/components/IssueList.tsx +228 -0
- package/src/components/LensPanel.tsx +286 -0
- package/src/components/ObservationCaptureModal.tsx +502 -0
- package/src/components/PhysicsAnalysis.tsx +273 -0
- package/src/components/SimulationPanel.tsx +173 -0
- package/src/components/StateComparison.tsx +238 -0
- package/src/hooks/useDataSource.ts +324 -0
- package/src/hooks/useKeyboardShortcuts.ts +125 -0
- package/src/hooks/useObservationCapture.ts +154 -0
- package/src/hooks/useSignalCapture.ts +138 -0
- package/src/index.ts +112 -0
- package/src/providers/HudProvider.tsx +115 -0
- package/src/store.ts +60 -0
- package/src/styles/theme.ts +256 -0
- package/src/types.ts +276 -0
|
@@ -0,0 +1,502 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Observation Capture Modal Component
|
|
3
|
+
*
|
|
4
|
+
* Modal for capturing user observations and insights.
|
|
5
|
+
* Triggered by Cmd+Shift+O keyboard shortcut.
|
|
6
|
+
* Implements TASK-203 requirements.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useState, useCallback, useEffect, useRef } from 'react'
|
|
10
|
+
import { useObservationCapture } from '../hooks/useObservationCapture'
|
|
11
|
+
import type { Observation } from '../types'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Observation type for display
|
|
15
|
+
*/
|
|
16
|
+
type ObservationType = Observation['type']
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Props for ObservationCaptureModal
|
|
20
|
+
*/
|
|
21
|
+
export interface ObservationCaptureModalProps {
|
|
22
|
+
/** Whether the modal is visible */
|
|
23
|
+
isOpen: boolean
|
|
24
|
+
/** Callback to close the modal */
|
|
25
|
+
onClose: () => void
|
|
26
|
+
/** Callback when observation is captured */
|
|
27
|
+
onCapture?: (observation: Observation) => void
|
|
28
|
+
/** Current component context */
|
|
29
|
+
componentContext?: {
|
|
30
|
+
name?: string
|
|
31
|
+
effect?: string
|
|
32
|
+
lensAddress?: string
|
|
33
|
+
}
|
|
34
|
+
/** Custom class name */
|
|
35
|
+
className?: string
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Type labels and colors
|
|
40
|
+
*/
|
|
41
|
+
const typeConfig: Record<ObservationType, { label: string; color: string; bgColor: string; description: string }> = {
|
|
42
|
+
'user-truth': {
|
|
43
|
+
label: 'User Truth',
|
|
44
|
+
color: '#22c55e',
|
|
45
|
+
bgColor: 'rgba(34, 197, 94, 0.1)',
|
|
46
|
+
description: 'What users actually do vs. what we assumed',
|
|
47
|
+
},
|
|
48
|
+
issue: {
|
|
49
|
+
label: 'Issue',
|
|
50
|
+
color: '#ef4444',
|
|
51
|
+
bgColor: 'rgba(239, 68, 68, 0.1)',
|
|
52
|
+
description: 'Problems, bugs, or friction points',
|
|
53
|
+
},
|
|
54
|
+
insight: {
|
|
55
|
+
label: 'Insight',
|
|
56
|
+
color: '#3b82f6',
|
|
57
|
+
bgColor: 'rgba(59, 130, 246, 0.1)',
|
|
58
|
+
description: 'Patterns, discoveries, or aha moments',
|
|
59
|
+
},
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Suggested tags by type
|
|
64
|
+
*/
|
|
65
|
+
const suggestedTags: Record<ObservationType, string[]> = {
|
|
66
|
+
'user-truth': ['assumption-violated', 'behavior-change', 'feedback', 'preference'],
|
|
67
|
+
issue: ['ux', 'performance', 'physics-violation', 'accessibility', 'mobile'],
|
|
68
|
+
insight: ['pattern', 'optimization', 'physics', 'taste', 'workflow'],
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Observation Capture Modal
|
|
73
|
+
*/
|
|
74
|
+
export function ObservationCaptureModal({
|
|
75
|
+
isOpen,
|
|
76
|
+
onClose,
|
|
77
|
+
onCapture,
|
|
78
|
+
componentContext,
|
|
79
|
+
className = '',
|
|
80
|
+
}: ObservationCaptureModalProps) {
|
|
81
|
+
const [type, setType] = useState<ObservationType>('insight')
|
|
82
|
+
const [content, setContent] = useState('')
|
|
83
|
+
const [tags, setTags] = useState<string[]>([])
|
|
84
|
+
const [customTag, setCustomTag] = useState('')
|
|
85
|
+
const contentRef = useRef<HTMLTextAreaElement>(null)
|
|
86
|
+
|
|
87
|
+
const { capture } = useObservationCapture({
|
|
88
|
+
enabled: true,
|
|
89
|
+
onObservation: onCapture,
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
// Focus textarea when modal opens
|
|
93
|
+
useEffect(() => {
|
|
94
|
+
if (isOpen && contentRef.current) {
|
|
95
|
+
contentRef.current.focus()
|
|
96
|
+
}
|
|
97
|
+
}, [isOpen])
|
|
98
|
+
|
|
99
|
+
// Reset form when modal closes
|
|
100
|
+
useEffect(() => {
|
|
101
|
+
if (!isOpen) {
|
|
102
|
+
setType('insight')
|
|
103
|
+
setContent('')
|
|
104
|
+
setTags([])
|
|
105
|
+
setCustomTag('')
|
|
106
|
+
}
|
|
107
|
+
}, [isOpen])
|
|
108
|
+
|
|
109
|
+
// Handle escape key
|
|
110
|
+
useEffect(() => {
|
|
111
|
+
if (!isOpen) return
|
|
112
|
+
|
|
113
|
+
const handleKeyDown = (e: KeyboardEvent) => {
|
|
114
|
+
if (e.key === 'Escape') {
|
|
115
|
+
onClose()
|
|
116
|
+
}
|
|
117
|
+
if (e.key === 'Enter' && e.metaKey) {
|
|
118
|
+
handleSubmit()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
window.addEventListener('keydown', handleKeyDown)
|
|
123
|
+
return () => window.removeEventListener('keydown', handleKeyDown)
|
|
124
|
+
}, [isOpen, onClose, content])
|
|
125
|
+
|
|
126
|
+
// Toggle a tag
|
|
127
|
+
const toggleTag = useCallback((tag: string) => {
|
|
128
|
+
setTags((prev) =>
|
|
129
|
+
prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
|
|
130
|
+
)
|
|
131
|
+
}, [])
|
|
132
|
+
|
|
133
|
+
// Add custom tag
|
|
134
|
+
const addCustomTag = useCallback(() => {
|
|
135
|
+
if (customTag && !tags.includes(customTag)) {
|
|
136
|
+
setTags((prev) => [...prev, customTag])
|
|
137
|
+
setCustomTag('')
|
|
138
|
+
}
|
|
139
|
+
}, [customTag, tags])
|
|
140
|
+
|
|
141
|
+
// Handle submit
|
|
142
|
+
const handleSubmit = useCallback(async () => {
|
|
143
|
+
if (!content.trim()) return
|
|
144
|
+
|
|
145
|
+
await capture(
|
|
146
|
+
content.trim(),
|
|
147
|
+
type,
|
|
148
|
+
componentContext,
|
|
149
|
+
tags
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
onClose()
|
|
153
|
+
}, [content, type, componentContext, tags, capture, onClose])
|
|
154
|
+
|
|
155
|
+
if (!isOpen) return null
|
|
156
|
+
|
|
157
|
+
const config = typeConfig[type]
|
|
158
|
+
const suggested = suggestedTags[type]
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<div className={className} style={styles.overlay}>
|
|
162
|
+
<div style={styles.modal}>
|
|
163
|
+
{/* Header */}
|
|
164
|
+
<div style={styles.header}>
|
|
165
|
+
<h2 style={styles.title}>Capture Observation</h2>
|
|
166
|
+
<button onClick={onClose} style={styles.closeButton}>
|
|
167
|
+
×
|
|
168
|
+
</button>
|
|
169
|
+
</div>
|
|
170
|
+
|
|
171
|
+
{/* Type Selection */}
|
|
172
|
+
<div style={styles.section}>
|
|
173
|
+
<label style={styles.label}>Type</label>
|
|
174
|
+
<div style={styles.typeButtons}>
|
|
175
|
+
{(Object.keys(typeConfig) as ObservationType[]).map((t) => {
|
|
176
|
+
const c = typeConfig[t]
|
|
177
|
+
const isSelected = type === t
|
|
178
|
+
return (
|
|
179
|
+
<button
|
|
180
|
+
key={t}
|
|
181
|
+
onClick={() => setType(t)}
|
|
182
|
+
style={{
|
|
183
|
+
...styles.typeButton,
|
|
184
|
+
backgroundColor: isSelected ? c.bgColor : 'rgba(255, 255, 255, 0.02)',
|
|
185
|
+
borderColor: isSelected ? c.color : 'rgba(255, 255, 255, 0.1)',
|
|
186
|
+
color: isSelected ? c.color : '#888',
|
|
187
|
+
}}
|
|
188
|
+
>
|
|
189
|
+
{c.label}
|
|
190
|
+
</button>
|
|
191
|
+
)
|
|
192
|
+
})}
|
|
193
|
+
</div>
|
|
194
|
+
<p style={styles.typeDescription}>{config.description}</p>
|
|
195
|
+
</div>
|
|
196
|
+
|
|
197
|
+
{/* Content */}
|
|
198
|
+
<div style={styles.section}>
|
|
199
|
+
<label style={styles.label}>What did you observe?</label>
|
|
200
|
+
<textarea
|
|
201
|
+
ref={contentRef}
|
|
202
|
+
value={content}
|
|
203
|
+
onChange={(e) => setContent(e.target.value)}
|
|
204
|
+
placeholder={
|
|
205
|
+
type === 'user-truth'
|
|
206
|
+
? 'e.g., "Users expected the claim button to show pending state, but it shows stale balance..."'
|
|
207
|
+
: type === 'issue'
|
|
208
|
+
? 'e.g., "Dialog animation causes layout shift on mobile Safari..."'
|
|
209
|
+
: 'e.g., "Power users prefer 500ms timing over 800ms for financial operations..."'
|
|
210
|
+
}
|
|
211
|
+
rows={4}
|
|
212
|
+
style={styles.textarea}
|
|
213
|
+
/>
|
|
214
|
+
</div>
|
|
215
|
+
|
|
216
|
+
{/* Tags */}
|
|
217
|
+
<div style={styles.section}>
|
|
218
|
+
<label style={styles.label}>Tags</label>
|
|
219
|
+
<div style={styles.tagContainer}>
|
|
220
|
+
{/* Suggested tags */}
|
|
221
|
+
{suggested.map((tag) => (
|
|
222
|
+
<button
|
|
223
|
+
key={tag}
|
|
224
|
+
onClick={() => toggleTag(tag)}
|
|
225
|
+
style={{
|
|
226
|
+
...styles.tag,
|
|
227
|
+
backgroundColor: tags.includes(tag)
|
|
228
|
+
? config.bgColor
|
|
229
|
+
: 'rgba(255, 255, 255, 0.02)',
|
|
230
|
+
borderColor: tags.includes(tag)
|
|
231
|
+
? config.color
|
|
232
|
+
: 'rgba(255, 255, 255, 0.1)',
|
|
233
|
+
color: tags.includes(tag) ? config.color : '#888',
|
|
234
|
+
}}
|
|
235
|
+
>
|
|
236
|
+
{tag}
|
|
237
|
+
</button>
|
|
238
|
+
))}
|
|
239
|
+
{/* Custom tags */}
|
|
240
|
+
{tags
|
|
241
|
+
.filter((t) => !suggested.includes(t))
|
|
242
|
+
.map((tag) => (
|
|
243
|
+
<button
|
|
244
|
+
key={tag}
|
|
245
|
+
onClick={() => toggleTag(tag)}
|
|
246
|
+
style={{
|
|
247
|
+
...styles.tag,
|
|
248
|
+
backgroundColor: config.bgColor,
|
|
249
|
+
borderColor: config.color,
|
|
250
|
+
color: config.color,
|
|
251
|
+
}}
|
|
252
|
+
>
|
|
253
|
+
{tag} ×
|
|
254
|
+
</button>
|
|
255
|
+
))}
|
|
256
|
+
</div>
|
|
257
|
+
{/* Custom tag input */}
|
|
258
|
+
<div style={styles.customTagRow}>
|
|
259
|
+
<input
|
|
260
|
+
type="text"
|
|
261
|
+
value={customTag}
|
|
262
|
+
onChange={(e) => setCustomTag(e.target.value)}
|
|
263
|
+
onKeyDown={(e) => e.key === 'Enter' && addCustomTag()}
|
|
264
|
+
placeholder="Add custom tag..."
|
|
265
|
+
style={styles.customTagInput}
|
|
266
|
+
/>
|
|
267
|
+
<button
|
|
268
|
+
onClick={addCustomTag}
|
|
269
|
+
disabled={!customTag}
|
|
270
|
+
style={{
|
|
271
|
+
...styles.addTagButton,
|
|
272
|
+
opacity: customTag ? 1 : 0.5,
|
|
273
|
+
}}
|
|
274
|
+
>
|
|
275
|
+
+
|
|
276
|
+
</button>
|
|
277
|
+
</div>
|
|
278
|
+
</div>
|
|
279
|
+
|
|
280
|
+
{/* Context (if available) */}
|
|
281
|
+
{componentContext && (
|
|
282
|
+
<div style={styles.section}>
|
|
283
|
+
<label style={styles.label}>Context</label>
|
|
284
|
+
<div style={styles.contextRow}>
|
|
285
|
+
{componentContext.name && (
|
|
286
|
+
<span style={styles.contextBadge}>
|
|
287
|
+
Component: {componentContext.name}
|
|
288
|
+
</span>
|
|
289
|
+
)}
|
|
290
|
+
{componentContext.effect && (
|
|
291
|
+
<span style={styles.contextBadge}>
|
|
292
|
+
Effect: {componentContext.effect}
|
|
293
|
+
</span>
|
|
294
|
+
)}
|
|
295
|
+
{componentContext.lensAddress && (
|
|
296
|
+
<span style={styles.contextBadge}>
|
|
297
|
+
Lens: {componentContext.lensAddress.slice(0, 6)}...
|
|
298
|
+
</span>
|
|
299
|
+
)}
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
)}
|
|
303
|
+
|
|
304
|
+
{/* Actions */}
|
|
305
|
+
<div style={styles.actions}>
|
|
306
|
+
<button onClick={onClose} style={styles.cancelButton}>
|
|
307
|
+
Cancel
|
|
308
|
+
</button>
|
|
309
|
+
<button
|
|
310
|
+
onClick={handleSubmit}
|
|
311
|
+
disabled={!content.trim()}
|
|
312
|
+
style={{
|
|
313
|
+
...styles.submitButton,
|
|
314
|
+
backgroundColor: content.trim() ? config.bgColor : 'rgba(255, 255, 255, 0.02)',
|
|
315
|
+
borderColor: content.trim() ? config.color : 'rgba(255, 255, 255, 0.1)',
|
|
316
|
+
color: content.trim() ? config.color : '#666',
|
|
317
|
+
cursor: content.trim() ? 'pointer' : 'not-allowed',
|
|
318
|
+
}}
|
|
319
|
+
>
|
|
320
|
+
Capture (⌘+Enter)
|
|
321
|
+
</button>
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Styles
|
|
330
|
+
*/
|
|
331
|
+
const styles: Record<string, React.CSSProperties> = {
|
|
332
|
+
overlay: {
|
|
333
|
+
position: 'fixed',
|
|
334
|
+
top: 0,
|
|
335
|
+
left: 0,
|
|
336
|
+
right: 0,
|
|
337
|
+
bottom: 0,
|
|
338
|
+
backgroundColor: 'rgba(0, 0, 0, 0.6)',
|
|
339
|
+
backdropFilter: 'blur(4px)',
|
|
340
|
+
display: 'flex',
|
|
341
|
+
alignItems: 'center',
|
|
342
|
+
justifyContent: 'center',
|
|
343
|
+
zIndex: 10000,
|
|
344
|
+
},
|
|
345
|
+
modal: {
|
|
346
|
+
width: '100%',
|
|
347
|
+
maxWidth: '480px',
|
|
348
|
+
backgroundColor: '#1a1a1a',
|
|
349
|
+
borderRadius: '12px',
|
|
350
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
351
|
+
boxShadow: '0 20px 40px rgba(0, 0, 0, 0.4)',
|
|
352
|
+
overflow: 'hidden',
|
|
353
|
+
},
|
|
354
|
+
header: {
|
|
355
|
+
display: 'flex',
|
|
356
|
+
justifyContent: 'space-between',
|
|
357
|
+
alignItems: 'center',
|
|
358
|
+
padding: '16px 20px',
|
|
359
|
+
borderBottom: '1px solid rgba(255, 255, 255, 0.05)',
|
|
360
|
+
},
|
|
361
|
+
title: {
|
|
362
|
+
margin: 0,
|
|
363
|
+
fontSize: '14px',
|
|
364
|
+
fontWeight: 600,
|
|
365
|
+
color: '#fff',
|
|
366
|
+
},
|
|
367
|
+
closeButton: {
|
|
368
|
+
width: '28px',
|
|
369
|
+
height: '28px',
|
|
370
|
+
display: 'flex',
|
|
371
|
+
alignItems: 'center',
|
|
372
|
+
justifyContent: 'center',
|
|
373
|
+
backgroundColor: 'transparent',
|
|
374
|
+
border: 'none',
|
|
375
|
+
borderRadius: '4px',
|
|
376
|
+
color: '#888',
|
|
377
|
+
fontSize: '20px',
|
|
378
|
+
cursor: 'pointer',
|
|
379
|
+
},
|
|
380
|
+
section: {
|
|
381
|
+
padding: '16px 20px',
|
|
382
|
+
},
|
|
383
|
+
label: {
|
|
384
|
+
display: 'block',
|
|
385
|
+
fontSize: '11px',
|
|
386
|
+
fontWeight: 600,
|
|
387
|
+
color: '#888',
|
|
388
|
+
textTransform: 'uppercase',
|
|
389
|
+
letterSpacing: '0.5px',
|
|
390
|
+
marginBottom: '8px',
|
|
391
|
+
},
|
|
392
|
+
typeButtons: {
|
|
393
|
+
display: 'flex',
|
|
394
|
+
gap: '8px',
|
|
395
|
+
},
|
|
396
|
+
typeButton: {
|
|
397
|
+
flex: 1,
|
|
398
|
+
padding: '8px 12px',
|
|
399
|
+
borderRadius: '6px',
|
|
400
|
+
border: '1px solid',
|
|
401
|
+
fontSize: '12px',
|
|
402
|
+
fontWeight: 500,
|
|
403
|
+
cursor: 'pointer',
|
|
404
|
+
transition: 'all 0.15s ease-out',
|
|
405
|
+
},
|
|
406
|
+
typeDescription: {
|
|
407
|
+
margin: '8px 0 0 0',
|
|
408
|
+
fontSize: '11px',
|
|
409
|
+
color: '#666',
|
|
410
|
+
fontStyle: 'italic',
|
|
411
|
+
},
|
|
412
|
+
textarea: {
|
|
413
|
+
width: '100%',
|
|
414
|
+
padding: '12px',
|
|
415
|
+
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
416
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
417
|
+
borderRadius: '6px',
|
|
418
|
+
color: '#fff',
|
|
419
|
+
fontSize: '13px',
|
|
420
|
+
fontFamily: 'inherit',
|
|
421
|
+
resize: 'vertical',
|
|
422
|
+
lineHeight: 1.5,
|
|
423
|
+
},
|
|
424
|
+
tagContainer: {
|
|
425
|
+
display: 'flex',
|
|
426
|
+
flexWrap: 'wrap',
|
|
427
|
+
gap: '6px',
|
|
428
|
+
},
|
|
429
|
+
tag: {
|
|
430
|
+
padding: '4px 8px',
|
|
431
|
+
borderRadius: '4px',
|
|
432
|
+
border: '1px solid',
|
|
433
|
+
fontSize: '11px',
|
|
434
|
+
cursor: 'pointer',
|
|
435
|
+
transition: 'all 0.15s ease-out',
|
|
436
|
+
},
|
|
437
|
+
customTagRow: {
|
|
438
|
+
display: 'flex',
|
|
439
|
+
gap: '8px',
|
|
440
|
+
marginTop: '8px',
|
|
441
|
+
},
|
|
442
|
+
customTagInput: {
|
|
443
|
+
flex: 1,
|
|
444
|
+
padding: '6px 10px',
|
|
445
|
+
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
446
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
447
|
+
borderRadius: '4px',
|
|
448
|
+
color: '#fff',
|
|
449
|
+
fontSize: '11px',
|
|
450
|
+
fontFamily: 'inherit',
|
|
451
|
+
},
|
|
452
|
+
addTagButton: {
|
|
453
|
+
width: '28px',
|
|
454
|
+
height: '28px',
|
|
455
|
+
display: 'flex',
|
|
456
|
+
alignItems: 'center',
|
|
457
|
+
justifyContent: 'center',
|
|
458
|
+
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
459
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
460
|
+
borderRadius: '4px',
|
|
461
|
+
color: '#888',
|
|
462
|
+
fontSize: '16px',
|
|
463
|
+
cursor: 'pointer',
|
|
464
|
+
},
|
|
465
|
+
contextRow: {
|
|
466
|
+
display: 'flex',
|
|
467
|
+
flexWrap: 'wrap',
|
|
468
|
+
gap: '6px',
|
|
469
|
+
},
|
|
470
|
+
contextBadge: {
|
|
471
|
+
padding: '4px 8px',
|
|
472
|
+
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
473
|
+
border: '1px solid rgba(255, 255, 255, 0.05)',
|
|
474
|
+
borderRadius: '4px',
|
|
475
|
+
fontSize: '10px',
|
|
476
|
+
color: '#888',
|
|
477
|
+
},
|
|
478
|
+
actions: {
|
|
479
|
+
display: 'flex',
|
|
480
|
+
justifyContent: 'flex-end',
|
|
481
|
+
gap: '8px',
|
|
482
|
+
padding: '16px 20px',
|
|
483
|
+
borderTop: '1px solid rgba(255, 255, 255, 0.05)',
|
|
484
|
+
},
|
|
485
|
+
cancelButton: {
|
|
486
|
+
padding: '8px 16px',
|
|
487
|
+
backgroundColor: 'rgba(255, 255, 255, 0.02)',
|
|
488
|
+
border: '1px solid rgba(255, 255, 255, 0.1)',
|
|
489
|
+
borderRadius: '6px',
|
|
490
|
+
color: '#888',
|
|
491
|
+
fontSize: '12px',
|
|
492
|
+
cursor: 'pointer',
|
|
493
|
+
},
|
|
494
|
+
submitButton: {
|
|
495
|
+
padding: '8px 16px',
|
|
496
|
+
borderRadius: '6px',
|
|
497
|
+
border: '1px solid',
|
|
498
|
+
fontSize: '12px',
|
|
499
|
+
fontWeight: 500,
|
|
500
|
+
transition: 'all 0.15s ease-out',
|
|
501
|
+
},
|
|
502
|
+
}
|