@mandujs/core 0.18.14 β 0.18.16
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/package.json
CHANGED
|
@@ -43,6 +43,19 @@ const baseStyles = `
|
|
|
43
43
|
line-height: 1.5;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
button {
|
|
47
|
+
background: none;
|
|
48
|
+
border: none;
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
font-family: inherit;
|
|
51
|
+
color: inherit;
|
|
52
|
+
font-size: inherit;
|
|
53
|
+
-webkit-appearance: none;
|
|
54
|
+
appearance: none;
|
|
55
|
+
padding: 0;
|
|
56
|
+
margin: 0;
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
.mk-badge-container {
|
|
47
60
|
position: fixed;
|
|
48
61
|
z-index: ${zIndex.devtools};
|
|
@@ -72,6 +85,25 @@ const baseStyles = `
|
|
|
72
85
|
.mk-badge-container.panel-open {
|
|
73
86
|
opacity: 0;
|
|
74
87
|
pointer-events: none;
|
|
88
|
+
transform: scale(0.8);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes mk-badge-breathe {
|
|
92
|
+
0%, 100% { transform: scale(1) translateY(0px); }
|
|
93
|
+
50% { transform: scale(1.04) translateY(0px); }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@keyframes mk-badge-attention {
|
|
97
|
+
0%, 100% { transform: scale(1) translateY(0px); }
|
|
98
|
+
15% { transform: scale(1.08) translateY(0px); }
|
|
99
|
+
30% { transform: scale(0.98) translateY(0px); }
|
|
100
|
+
45% { transform: scale(1.04) translateY(0px); }
|
|
101
|
+
60% { transform: scale(1) translateY(0px); }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@keyframes mk-badge-float {
|
|
105
|
+
0%, 100% { transform: scale(1) translateY(0px); }
|
|
106
|
+
50% { transform: scale(1) translateY(-3px); }
|
|
75
107
|
}
|
|
76
108
|
`;
|
|
77
109
|
|
|
@@ -203,37 +203,78 @@ export function ManduBadge({
|
|
|
203
203
|
const character = MANDU_CHARACTERS[state];
|
|
204
204
|
const stateColor = stateColors[state];
|
|
205
205
|
const [isHovered, setIsHovered] = React.useState(false);
|
|
206
|
+
const [isPressed, setIsPressed] = React.useState(false);
|
|
206
207
|
|
|
207
208
|
const badgeStyle: React.CSSProperties = {
|
|
209
|
+
position: 'relative',
|
|
208
210
|
display: 'flex',
|
|
209
211
|
alignItems: 'center',
|
|
210
212
|
justifyContent: 'center',
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
height: '48px',
|
|
213
|
+
width: '52px',
|
|
214
|
+
height: '52px',
|
|
215
|
+
padding: 0,
|
|
215
216
|
borderRadius: '9999px',
|
|
216
|
-
backgroundColor:
|
|
217
|
-
|
|
217
|
+
backgroundColor: isPressed
|
|
218
|
+
? colors.background.light
|
|
219
|
+
: isHovered
|
|
220
|
+
? colors.background.medium
|
|
221
|
+
: colors.background.dark,
|
|
222
|
+
border: `2px solid ${isPressed ? stateColor : isHovered ? colors.brand.accent : stateColor + '70'}`,
|
|
218
223
|
cursor: 'pointer',
|
|
219
|
-
transition: `all
|
|
220
|
-
boxShadow:
|
|
221
|
-
? `0 8px
|
|
222
|
-
:
|
|
223
|
-
|
|
224
|
+
transition: `all 200ms ${animation.easing.spring}`,
|
|
225
|
+
boxShadow: isPressed
|
|
226
|
+
? `0 2px 8px rgba(8, 6, 18, 0.4), inset 0 2px 4px rgba(0, 0, 0, 0.15)`
|
|
227
|
+
: isHovered
|
|
228
|
+
? `0 8px 32px rgba(8, 6, 18, 0.45), 0 0 20px ${stateColor}55, 0 0 0 3px ${stateColor}20`
|
|
229
|
+
: `0 4px 16px rgba(8, 6, 18, 0.35), 0 0 10px ${stateColor}30`,
|
|
224
230
|
userSelect: 'none',
|
|
225
|
-
transform:
|
|
231
|
+
transform: isPressed
|
|
232
|
+
? 'scale(0.92) translateY(1px)'
|
|
233
|
+
: isHovered
|
|
234
|
+
? 'scale(1.1) translateY(-2px)'
|
|
235
|
+
: 'scale(1) translateY(0px)',
|
|
226
236
|
outline: 'none',
|
|
227
237
|
lineHeight: 1,
|
|
238
|
+
animation: isHovered || isPressed
|
|
239
|
+
? 'none'
|
|
240
|
+
: state === 'normal'
|
|
241
|
+
? 'mk-badge-breathe 3s ease-in-out infinite'
|
|
242
|
+
: state === 'error' && count > 0
|
|
243
|
+
? 'mk-badge-attention 2s ease-in-out infinite'
|
|
244
|
+
: state === 'loading'
|
|
245
|
+
? 'mk-badge-float 2s ease-in-out infinite'
|
|
246
|
+
: 'none',
|
|
228
247
|
};
|
|
229
248
|
|
|
230
|
-
const
|
|
231
|
-
|
|
249
|
+
const emojiStyle: React.CSSProperties = {
|
|
250
|
+
fontFamily: "'Segoe UI Emoji', 'Apple Color Emoji', 'Noto Color Emoji', sans-serif",
|
|
251
|
+
color: colors.text.primary,
|
|
252
|
+
fontSize: '24px',
|
|
253
|
+
lineHeight: 1,
|
|
254
|
+
transition: `transform 200ms ${animation.easing.spring}`,
|
|
255
|
+
transform: isHovered ? 'rotate(-8deg)' : 'rotate(0deg)',
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
const countBubbleStyle: React.CSSProperties = {
|
|
259
|
+
position: 'absolute',
|
|
260
|
+
top: '-4px',
|
|
261
|
+
right: '-4px',
|
|
262
|
+
minWidth: '20px',
|
|
263
|
+
height: '20px',
|
|
264
|
+
padding: '0 5px',
|
|
265
|
+
borderRadius: '9999px',
|
|
266
|
+
backgroundColor: stateColor,
|
|
267
|
+
color: colors.background.dark,
|
|
268
|
+
fontSize: '11px',
|
|
232
269
|
fontWeight: 700,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
270
|
+
display: 'flex',
|
|
271
|
+
alignItems: 'center',
|
|
272
|
+
justifyContent: 'center',
|
|
236
273
|
lineHeight: 1,
|
|
274
|
+
boxShadow: `0 2px 8px ${stateColor}66`,
|
|
275
|
+
border: `2px solid ${colors.background.dark}`,
|
|
276
|
+
transition: `all 200ms ${animation.easing.spring}`,
|
|
277
|
+
transform: isHovered ? 'scale(1.15)' : 'scale(1)',
|
|
237
278
|
};
|
|
238
279
|
|
|
239
280
|
return (
|
|
@@ -242,13 +283,19 @@ export function ManduBadge({
|
|
|
242
283
|
style={badgeStyle}
|
|
243
284
|
onClick={onClick}
|
|
244
285
|
onMouseEnter={() => setIsHovered(true)}
|
|
245
|
-
onMouseLeave={() => setIsHovered(false)}
|
|
286
|
+
onMouseLeave={() => { setIsHovered(false); setIsPressed(false); }}
|
|
287
|
+
onMouseDown={() => setIsPressed(true)}
|
|
288
|
+
onMouseUp={() => setIsPressed(false)}
|
|
246
289
|
onFocus={() => setIsHovered(true)}
|
|
247
|
-
onBlur={() => setIsHovered(false)}
|
|
290
|
+
onBlur={() => { setIsHovered(false); setIsPressed(false); }}
|
|
248
291
|
aria-label={`Mandu Kitchen: ${character.message}${count > 0 ? `, ${count} issues` : ''}`}
|
|
249
292
|
>
|
|
250
|
-
<span aria-hidden="true">π₯</span>
|
|
251
|
-
{count > 0 &&
|
|
293
|
+
<span aria-hidden="true" style={emojiStyle}>π₯</span>
|
|
294
|
+
{count > 0 && (
|
|
295
|
+
<span style={countBubbleStyle}>
|
|
296
|
+
{count > 99 ? '99+' : count}
|
|
297
|
+
</span>
|
|
298
|
+
)}
|
|
252
299
|
</button>
|
|
253
300
|
);
|
|
254
301
|
}
|
|
@@ -112,7 +112,7 @@ const styles = {
|
|
|
112
112
|
tabActive: {
|
|
113
113
|
color: colors.brand.accent,
|
|
114
114
|
borderBottomColor: colors.brand.accent,
|
|
115
|
-
backgroundColor:
|
|
115
|
+
backgroundColor: 'rgba(232, 150, 122, 0.12)',
|
|
116
116
|
},
|
|
117
117
|
tabIcon: {
|
|
118
118
|
fontSize: typography.fontSize.md,
|
|
@@ -166,6 +166,8 @@ export function PanelContainer({
|
|
|
166
166
|
}: PanelContainerProps): React.ReactElement {
|
|
167
167
|
const [isResizing, setIsResizing] = useState(false);
|
|
168
168
|
const [height, setHeight] = useState(400);
|
|
169
|
+
const [hoveredTab, setHoveredTab] = useState<TabId | null>(null);
|
|
170
|
+
const [isCloseHovered, setIsCloseHovered] = useState(false);
|
|
169
171
|
|
|
170
172
|
const getTabBadgeCount = useCallback((tabId: TabId): number => {
|
|
171
173
|
switch (tabId) {
|
|
@@ -206,8 +208,13 @@ export function PanelContainer({
|
|
|
206
208
|
<span>Mandu Kitchen</span>
|
|
207
209
|
</div>
|
|
208
210
|
<button
|
|
209
|
-
style={
|
|
211
|
+
style={{
|
|
212
|
+
...styles.closeButton,
|
|
213
|
+
...(isCloseHovered ? { color: colors.text.primary, backgroundColor: 'rgba(255, 255, 255, 0.08)' } : {}),
|
|
214
|
+
}}
|
|
210
215
|
onClick={onClose}
|
|
216
|
+
onMouseEnter={() => setIsCloseHovered(true)}
|
|
217
|
+
onMouseLeave={() => setIsCloseHovered(false)}
|
|
211
218
|
aria-label="ν¨λ λ«κΈ°"
|
|
212
219
|
>
|
|
213
220
|
Γ
|
|
@@ -229,8 +236,14 @@ export function PanelContainer({
|
|
|
229
236
|
style={{
|
|
230
237
|
...styles.tab,
|
|
231
238
|
...(isActive ? styles.tabActive : {}),
|
|
239
|
+
...(!isActive && hoveredTab === tab.id ? {
|
|
240
|
+
color: colors.text.primary,
|
|
241
|
+
backgroundColor: 'rgba(255, 255, 255, 0.05)',
|
|
242
|
+
} : {}),
|
|
232
243
|
}}
|
|
233
244
|
onClick={() => onTabChange(tab.id)}
|
|
245
|
+
onMouseEnter={() => setHoveredTab(tab.id)}
|
|
246
|
+
onMouseLeave={() => setHoveredTab(null)}
|
|
234
247
|
>
|
|
235
248
|
<span style={styles.tabIcon}>{tab.icon}</span>
|
|
236
249
|
<span>{tab.label}</span>
|