lynx-console 0.0.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/dist/assets/src/components/BottomSheet.css.ts.vanilla-D-1A77Ik.css +83 -0
- package/dist/assets/src/components/ConsolePanel.css.ts.vanilla-B3avfSlI.css +246 -0
- package/dist/assets/src/components/FloatingButton.css.ts.vanilla-rPj35oLW.css +55 -0
- package/dist/assets/src/components/NetworkPanel.css.ts.vanilla-DFMduT0T.css +247 -0
- package/dist/assets/src/components/PerformancePanel.css.ts.vanilla-D35LuXlW.css +216 -0
- package/dist/assets/src/components/Tabs.css.ts.vanilla-DD7L2oXt.css +50 -0
- package/dist/index.cjs +1058 -0
- package/dist/index.css +466 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +17 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +17 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +1059 -0
- package/dist/index.mjs.map +1 -0
- package/dist/setup.cjs +377 -0
- package/dist/setup.d.cts +15 -0
- package/dist/setup.d.cts.map +1 -0
- package/dist/setup.d.mts +15 -0
- package/dist/setup.d.mts.map +1 -0
- package/dist/setup.mjs +374 -0
- package/dist/setup.mjs.map +1 -0
- package/package.json +51 -0
- package/src/components/BottomSheet.css.ts +93 -0
- package/src/components/BottomSheet.tsx +142 -0
- package/src/components/ConsolePanel.css.ts +261 -0
- package/src/components/ConsolePanel.tsx +41 -0
- package/src/components/FloatingButton.css.ts +62 -0
- package/src/components/FloatingButton.tsx +37 -0
- package/src/components/LogPanel.tsx +241 -0
- package/src/components/NetworkDetailSection.tsx +42 -0
- package/src/components/NetworkPanel.css.ts +280 -0
- package/src/components/NetworkPanel.tsx +222 -0
- package/src/components/PerformancePanel.css.ts +224 -0
- package/src/components/PerformancePanel.tsx +209 -0
- package/src/components/Tabs.css.ts +66 -0
- package/src/components/Tabs.tsx +81 -0
- package/src/globals.d.ts +9 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/useConsole.ts +35 -0
- package/src/hooks/useNetwork.ts +36 -0
- package/src/hooks/usePerformance.ts +39 -0
- package/src/index.tsx +110 -0
- package/src/setup/_setupMainThreadConsole.ts +80 -0
- package/src/setup/index.ts +4 -0
- package/src/setup/setupLogMonitor.ts +78 -0
- package/src/setup/setupMainThreadConsole.ts +34 -0
- package/src/setup/setupNetworkMonitor.ts +247 -0
- package/src/setup/setupPerformanceMonitor.ts +70 -0
- package/src/shared/ensureConsoleStructure.ts +20 -0
- package/src/styles/getDimensionValue.ts +7 -0
- package/src/styles/global.css.ts +10 -0
- package/src/styles/tokens.json +80 -0
- package/src/styles/typography.ts +25 -0
- package/src/styles/vars/color.ts +228 -0
- package/src/styles/vars/dimension.ts +79 -0
- package/src/styles/vars/index.css +463 -0
- package/src/styles/vars/index.ts +22 -0
- package/src/styles/vars/radius.ts +12 -0
- package/src/types.ts +96 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { type ReactNode, useEffect, useState } from "@lynx-js/react";
|
|
2
|
+
import type { BaseTouchEvent, Target } from "@lynx-js/types";
|
|
3
|
+
import * as css from "./BottomSheet.css";
|
|
4
|
+
|
|
5
|
+
interface BottomSheetProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
title?: string;
|
|
8
|
+
footer?: ReactNode;
|
|
9
|
+
onClose: () => void;
|
|
10
|
+
isOpen: boolean;
|
|
11
|
+
shouldClose?: boolean;
|
|
12
|
+
safeAreaInsetBottom?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const MIN_HEIGHT = 200;
|
|
16
|
+
const MAX_HEIGHT = 700;
|
|
17
|
+
const DEFAULT_HEIGHT = 500;
|
|
18
|
+
const CLOSE_DRAG_THRESHOLD = 30; // 30px 이상 아래로 드래그하면 닫힘
|
|
19
|
+
|
|
20
|
+
// 마지막 높이 저장
|
|
21
|
+
let savedHeight: number | null = null;
|
|
22
|
+
|
|
23
|
+
export default function BottomSheet({
|
|
24
|
+
children,
|
|
25
|
+
title,
|
|
26
|
+
footer,
|
|
27
|
+
onClose,
|
|
28
|
+
isOpen,
|
|
29
|
+
shouldClose = false,
|
|
30
|
+
safeAreaInsetBottom = "25px",
|
|
31
|
+
}: BottomSheetProps) {
|
|
32
|
+
const [sheetHeight, setSheetHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);
|
|
33
|
+
const [tempHeight, setTempHeight] = useState(savedHeight ?? DEFAULT_HEIGHT);
|
|
34
|
+
const [isDragging, setIsDragging] = useState(false);
|
|
35
|
+
const [dragStartY, setDragStartY] = useState(0);
|
|
36
|
+
const [dragStartHeight, setDragStartHeight] = useState(
|
|
37
|
+
savedHeight ?? DEFAULT_HEIGHT,
|
|
38
|
+
);
|
|
39
|
+
const [isOpening, setIsOpening] = useState(true);
|
|
40
|
+
const [isClosing, setIsClosing] = useState(false);
|
|
41
|
+
|
|
42
|
+
// 닫기 애니메이션 처리
|
|
43
|
+
const handleClose = () => {
|
|
44
|
+
setIsClosing(true);
|
|
45
|
+
setTimeout(() => {
|
|
46
|
+
onClose();
|
|
47
|
+
}, 300);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// 아래에서 올라오는 애니메이션
|
|
51
|
+
useEffect(() => {
|
|
52
|
+
requestAnimationFrame(() => {
|
|
53
|
+
setIsOpening(false);
|
|
54
|
+
});
|
|
55
|
+
}, []);
|
|
56
|
+
|
|
57
|
+
// 외부에서 닫기 요청 시 애니메이션 처리
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
if (shouldClose && !isClosing) {
|
|
60
|
+
handleClose();
|
|
61
|
+
}
|
|
62
|
+
}, [shouldClose, isClosing]);
|
|
63
|
+
|
|
64
|
+
// 높이 변경 시 저장
|
|
65
|
+
useEffect(() => {
|
|
66
|
+
savedHeight = sheetHeight;
|
|
67
|
+
}, [sheetHeight]);
|
|
68
|
+
|
|
69
|
+
if (!isOpen) return null;
|
|
70
|
+
|
|
71
|
+
const handleTouchStart = (e: BaseTouchEvent<Target>) => {
|
|
72
|
+
setIsDragging(true);
|
|
73
|
+
setDragStartY(e.detail.y);
|
|
74
|
+
setDragStartHeight(sheetHeight);
|
|
75
|
+
setTempHeight(sheetHeight);
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const handleTouchMove = (e: BaseTouchEvent<Target>) => {
|
|
79
|
+
if (!isDragging) return;
|
|
80
|
+
const deltaY = dragStartY - e.detail.y;
|
|
81
|
+
const newHeight = Math.min(
|
|
82
|
+
Math.max(dragStartHeight + deltaY, MIN_HEIGHT),
|
|
83
|
+
MAX_HEIGHT,
|
|
84
|
+
);
|
|
85
|
+
setTempHeight(newHeight);
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const handleTouchEnd = () => {
|
|
89
|
+
setIsDragging(false);
|
|
90
|
+
|
|
91
|
+
// 아래로 일정 30px 이상 드래그하면 닫기
|
|
92
|
+
const dragDistance = dragStartHeight - tempHeight;
|
|
93
|
+
setSheetHeight(tempHeight);
|
|
94
|
+
if (dragDistance > CLOSE_DRAG_THRESHOLD) {
|
|
95
|
+
handleClose();
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
return (
|
|
100
|
+
<scroll-view
|
|
101
|
+
className={css.backdrop}
|
|
102
|
+
style={{
|
|
103
|
+
opacity: isOpening || isClosing ? 0 : 1,
|
|
104
|
+
}}
|
|
105
|
+
>
|
|
106
|
+
<view className={css.overlay} bindtap={handleClose}>
|
|
107
|
+
<view
|
|
108
|
+
className={css.content}
|
|
109
|
+
catchtap={() => {}}
|
|
110
|
+
style={{
|
|
111
|
+
height: `${isDragging ? tempHeight : sheetHeight}px`,
|
|
112
|
+
transform:
|
|
113
|
+
isOpening || isClosing ? "translateY(100%)" : "translateY(0)",
|
|
114
|
+
transition: isDragging ? "none" : undefined,
|
|
115
|
+
}}
|
|
116
|
+
>
|
|
117
|
+
{/* catchtap: 이벤트 버블링 차단 */}
|
|
118
|
+
<view
|
|
119
|
+
className={css.handleContainer}
|
|
120
|
+
bindtouchstart={handleTouchStart}
|
|
121
|
+
bindtouchmove={handleTouchMove}
|
|
122
|
+
bindtouchend={handleTouchEnd}
|
|
123
|
+
>
|
|
124
|
+
<view className={css.handle} />
|
|
125
|
+
</view>
|
|
126
|
+
<view className={css.header}>
|
|
127
|
+
{title && <text className={css.title}>{title}</text>}
|
|
128
|
+
</view>
|
|
129
|
+
<view
|
|
130
|
+
className={css.body}
|
|
131
|
+
style={{
|
|
132
|
+
paddingBottom: safeAreaInsetBottom,
|
|
133
|
+
}}
|
|
134
|
+
>
|
|
135
|
+
{children}
|
|
136
|
+
</view>
|
|
137
|
+
{footer && <view className={css.footer}>{footer}</view>}
|
|
138
|
+
</view>
|
|
139
|
+
</view>
|
|
140
|
+
</scroll-view>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { style } from "@vanilla-extract/css";
|
|
2
|
+
import { recipe } from "@vanilla-extract/recipes";
|
|
3
|
+
import { typography } from "../styles/typography";
|
|
4
|
+
import { vars } from "../styles/vars";
|
|
5
|
+
|
|
6
|
+
export const container = style({
|
|
7
|
+
display: "flex",
|
|
8
|
+
flexDirection: "column",
|
|
9
|
+
height: "100%",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
export const placeholder = style({
|
|
13
|
+
display: "flex",
|
|
14
|
+
alignItems: "center",
|
|
15
|
+
justifyContent: "center",
|
|
16
|
+
height: "100%",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
export const placeholderText = style({
|
|
20
|
+
...typography("t4", "regular"),
|
|
21
|
+
color: vars.$color.fg.disabled,
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
export const logContainer = style({
|
|
25
|
+
display: "flex",
|
|
26
|
+
flexDirection: "column",
|
|
27
|
+
flex: 1,
|
|
28
|
+
paddingTop: 4,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export const logHeader = style({
|
|
32
|
+
display: "flex",
|
|
33
|
+
flexDirection: "row",
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
justifyContent: "space-between",
|
|
36
|
+
marginBottom: 8,
|
|
37
|
+
paddingBottom: 4,
|
|
38
|
+
borderBottomWidth: 1,
|
|
39
|
+
borderBottomColor: vars.$color.stroke.neutralSubtle,
|
|
40
|
+
borderBottomStyle: "solid",
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const logCount = style({
|
|
44
|
+
...typography("t3", "regular"),
|
|
45
|
+
color: vars.$color.fg.neutralSubtle,
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
export const clearButton = style({
|
|
49
|
+
padding: "6px 12px",
|
|
50
|
+
backgroundColor: vars.$color.bg.neutralWeak,
|
|
51
|
+
borderRadius: 4,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
export const clearButtonText = style({
|
|
55
|
+
...typography("t3", "medium"),
|
|
56
|
+
color: vars.$color.fg.neutral,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
export const logList = style({
|
|
60
|
+
flex: 1,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
export const logItem = recipe({
|
|
64
|
+
base: {
|
|
65
|
+
padding: "8px",
|
|
66
|
+
borderBottomWidth: 1,
|
|
67
|
+
borderBottomColor: vars.$color.stroke.neutralWeak,
|
|
68
|
+
borderBottomStyle: "solid",
|
|
69
|
+
},
|
|
70
|
+
variants: {
|
|
71
|
+
level: {
|
|
72
|
+
log: {},
|
|
73
|
+
info: {},
|
|
74
|
+
warn: {
|
|
75
|
+
backgroundColor: vars.$color.palette.yellow100,
|
|
76
|
+
},
|
|
77
|
+
error: {
|
|
78
|
+
backgroundColor: vars.$color.palette.red100,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
export const logItemHeader = style({
|
|
85
|
+
display: "flex",
|
|
86
|
+
flexDirection: "row",
|
|
87
|
+
alignItems: "center",
|
|
88
|
+
marginBottom: 4,
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
export const logLevel = recipe({
|
|
92
|
+
base: {
|
|
93
|
+
...typography("t2", "bold"),
|
|
94
|
+
marginRight: 8,
|
|
95
|
+
},
|
|
96
|
+
variants: {
|
|
97
|
+
level: {
|
|
98
|
+
log: {
|
|
99
|
+
color: vars.$color.palette.green600,
|
|
100
|
+
},
|
|
101
|
+
info: {
|
|
102
|
+
color: vars.$color.palette.blue600,
|
|
103
|
+
},
|
|
104
|
+
warn: {
|
|
105
|
+
color: vars.$color.palette.yellow600,
|
|
106
|
+
},
|
|
107
|
+
error: {
|
|
108
|
+
color: vars.$color.palette.red600,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
export const logTime = style({
|
|
115
|
+
...typography("t2", "regular"),
|
|
116
|
+
color: vars.$color.fg.neutralSubtle,
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
export const toggleIndicator = style({
|
|
120
|
+
...typography("t2", "regular"),
|
|
121
|
+
color: vars.$color.fg.neutralSubtle,
|
|
122
|
+
marginLeft: 4,
|
|
123
|
+
alignSelf: "flex-start",
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
export const logMessage = style({
|
|
127
|
+
...typography("t3", "regular"),
|
|
128
|
+
color: vars.$color.fg.neutral,
|
|
129
|
+
wordBreak: "break-all",
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
export const logArgsContainer = style({
|
|
133
|
+
display: "flex",
|
|
134
|
+
flexDirection: "row",
|
|
135
|
+
flexWrap: "wrap",
|
|
136
|
+
gap: 8,
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
export const logArgItem = style({
|
|
140
|
+
...typography("t3", "regular"),
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
export const argNull = style({
|
|
144
|
+
color: vars.$color.fg.neutralSubtle,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
export const argUndefined = style({
|
|
148
|
+
color: vars.$color.fg.neutralSubtle,
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
export const argString = recipe({
|
|
152
|
+
base: {
|
|
153
|
+
...typography("t3", "regular"),
|
|
154
|
+
},
|
|
155
|
+
variants: {
|
|
156
|
+
level: {
|
|
157
|
+
log: { color: vars.$color.fg.neutral },
|
|
158
|
+
info: { color: vars.$color.fg.neutral },
|
|
159
|
+
warn: { color: vars.$color.palette.yellow900 },
|
|
160
|
+
error: { color: vars.$color.palette.red900 },
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
export const argPrimitive = recipe({
|
|
166
|
+
base: {
|
|
167
|
+
...typography("t3", "regular"),
|
|
168
|
+
},
|
|
169
|
+
variants: {
|
|
170
|
+
level: {
|
|
171
|
+
log: { color: vars.$color.palette.blue600 },
|
|
172
|
+
info: { color: vars.$color.palette.blue600 },
|
|
173
|
+
warn: { color: vars.$color.palette.yellow900 },
|
|
174
|
+
error: { color: vars.$color.palette.red900 },
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
export const argObject = style({
|
|
180
|
+
display: "flex",
|
|
181
|
+
flexDirection: "column",
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
export const argObjectHeader = style({
|
|
185
|
+
display: "flex",
|
|
186
|
+
flexDirection: "row",
|
|
187
|
+
alignItems: "center",
|
|
188
|
+
gap: 4,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
export const argObjectPreview = style({
|
|
192
|
+
...typography("t3", "medium"),
|
|
193
|
+
color: vars.$color.fg.neutral,
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
export const argObjectContent = style({
|
|
197
|
+
marginTop: 4,
|
|
198
|
+
display: "flex",
|
|
199
|
+
flexDirection: "column",
|
|
200
|
+
gap: 4,
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
export const argObjectProperty = style({
|
|
204
|
+
display: "flex",
|
|
205
|
+
flexDirection: "row",
|
|
206
|
+
alignItems: "flex-start",
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
export const argObjectKey = style({
|
|
210
|
+
...typography("t3", "medium"),
|
|
211
|
+
color: vars.$color.palette.purple600,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
export const argObjectJson = style({
|
|
215
|
+
...typography("t3", "regular"),
|
|
216
|
+
color: vars.$color.fg.neutral,
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
export const replInputRow = style({
|
|
220
|
+
display: "flex",
|
|
221
|
+
flexDirection: "row",
|
|
222
|
+
alignItems: "center",
|
|
223
|
+
gap: 8,
|
|
224
|
+
paddingTop: 8,
|
|
225
|
+
paddingBottom: 8,
|
|
226
|
+
marginTop: -1,
|
|
227
|
+
borderTopWidth: 1,
|
|
228
|
+
borderTopColor: vars.$color.stroke.neutralSubtle,
|
|
229
|
+
borderTopStyle: "solid",
|
|
230
|
+
backgroundImage: `linear-gradient(to bottom, transparent, ${vars.$color.bg.layerDefault})`,
|
|
231
|
+
backgroundSize: "100% 32px",
|
|
232
|
+
backgroundRepeat: "no-repeat",
|
|
233
|
+
backgroundPosition: "top",
|
|
234
|
+
backgroundColor: vars.$color.bg.layerDefault,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
export const replPrompt = style({
|
|
238
|
+
...typography("t10", "medium"),
|
|
239
|
+
color: vars.$color.fg.placeholder,
|
|
240
|
+
paddingBottom: 8,
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
export const replInput = style({
|
|
244
|
+
flex: 1,
|
|
245
|
+
...typography("t5", "regular"),
|
|
246
|
+
color: vars.$color.fg.neutral,
|
|
247
|
+
caretColor: vars.$color.palette.green600,
|
|
248
|
+
paddingBottom: 8,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
export const replRunButton = style({
|
|
252
|
+
padding: "4px 10px",
|
|
253
|
+
backgroundColor: vars.$color.palette.green100,
|
|
254
|
+
borderRadius: 4,
|
|
255
|
+
marginBottom: 8,
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
export const replRunButtonText = style({
|
|
259
|
+
...typography("t3", "medium"),
|
|
260
|
+
color: vars.$color.palette.green600,
|
|
261
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { useConsole, useNetwork, usePerformance } from "../hooks";
|
|
2
|
+
import * as css from "./ConsolePanel.css";
|
|
3
|
+
import { LogPanel } from "./LogPanel";
|
|
4
|
+
import { NetworkPanel } from "./NetworkPanel";
|
|
5
|
+
import { PerformancePanel } from "./PerformancePanel";
|
|
6
|
+
import Tabs from "./Tabs";
|
|
7
|
+
|
|
8
|
+
export const ConsolePanel = () => {
|
|
9
|
+
const { logs, clearLogs } = useConsole();
|
|
10
|
+
const { networks, clearNetworks } = useNetwork();
|
|
11
|
+
const { performances, clearPerformances } = usePerformance();
|
|
12
|
+
|
|
13
|
+
return (
|
|
14
|
+
<view className={css.container}>
|
|
15
|
+
<Tabs
|
|
16
|
+
items={[
|
|
17
|
+
{
|
|
18
|
+
key: "log",
|
|
19
|
+
label: "Log",
|
|
20
|
+
renderContent: () => <LogPanel logs={logs} clearLogs={clearLogs} />,
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
key: "network",
|
|
24
|
+
label: "Network",
|
|
25
|
+
renderContent: () => <NetworkPanel networks={networks} clearNetworks={clearNetworks} />,
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
key: "performance",
|
|
29
|
+
label: "Performance",
|
|
30
|
+
renderContent: () => (
|
|
31
|
+
<PerformancePanel
|
|
32
|
+
performances={performances}
|
|
33
|
+
clearPerformances={clearPerformances}
|
|
34
|
+
/>
|
|
35
|
+
),
|
|
36
|
+
},
|
|
37
|
+
]}
|
|
38
|
+
/>
|
|
39
|
+
</view>
|
|
40
|
+
);
|
|
41
|
+
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { style } from "@vanilla-extract/css";
|
|
2
|
+
import { typography } from "../styles/typography";
|
|
3
|
+
import { vars } from "../styles/vars";
|
|
4
|
+
|
|
5
|
+
export const wrapper = style({
|
|
6
|
+
position: "fixed",
|
|
7
|
+
right: "16px",
|
|
8
|
+
bottom: "84px",
|
|
9
|
+
zIndex: 9999,
|
|
10
|
+
display: "flex",
|
|
11
|
+
flexDirection: "row",
|
|
12
|
+
alignItems: "center",
|
|
13
|
+
gap: "8px",
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
export const container = style({});
|
|
17
|
+
|
|
18
|
+
export const button = style({
|
|
19
|
+
paddingLeft: "8px",
|
|
20
|
+
paddingRight: "8px",
|
|
21
|
+
paddingTop: "4px",
|
|
22
|
+
paddingBottom: "4px",
|
|
23
|
+
borderRadius: "12px",
|
|
24
|
+
backgroundColor: vars.$color.palette.green600,
|
|
25
|
+
display: "flex",
|
|
26
|
+
flexDirection: "column",
|
|
27
|
+
alignItems: "center",
|
|
28
|
+
justifyContent: "center",
|
|
29
|
+
gap: "2px",
|
|
30
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
export const title = style({
|
|
34
|
+
...typography("t4", "regular"),
|
|
35
|
+
color: vars.$color.palette.staticWhite,
|
|
36
|
+
textAlign: "center",
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
export const subtitle = style({
|
|
40
|
+
...typography("t3", "regular"),
|
|
41
|
+
color: vars.$color.palette.staticWhite,
|
|
42
|
+
textAlign: "center",
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
export const reloadButton = style({
|
|
46
|
+
width: "32px",
|
|
47
|
+
height: "32px",
|
|
48
|
+
borderRadius: "16px",
|
|
49
|
+
backgroundColor: vars.$color.palette.green600,
|
|
50
|
+
display: "flex",
|
|
51
|
+
alignItems: "center",
|
|
52
|
+
justifyContent: "center",
|
|
53
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export const reloadIcon = style({
|
|
57
|
+
fontSize: "20px",
|
|
58
|
+
lineHeight: "32px",
|
|
59
|
+
marginBottom: "5px",
|
|
60
|
+
color: vars.$color.palette.staticWhite,
|
|
61
|
+
textAlign: "center",
|
|
62
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { ReactNode } from "@lynx-js/react";
|
|
2
|
+
import * as css from "./FloatingButton.css";
|
|
3
|
+
|
|
4
|
+
interface FloatingButtonProps {
|
|
5
|
+
bindtap: () => void;
|
|
6
|
+
isVisible: boolean;
|
|
7
|
+
children: ReactNode;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export const FloatingButton = ({
|
|
11
|
+
bindtap,
|
|
12
|
+
isVisible,
|
|
13
|
+
children,
|
|
14
|
+
}: FloatingButtonProps) => {
|
|
15
|
+
if (!isVisible) return null;
|
|
16
|
+
|
|
17
|
+
const handleReload = () => {
|
|
18
|
+
try {
|
|
19
|
+
lynx.reload({}, () => {
|
|
20
|
+
console.log("reloaded!");
|
|
21
|
+
});
|
|
22
|
+
} catch (e) {
|
|
23
|
+
console.error("[LynxConsole] reload failed:", e);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<view className={css.wrapper}>
|
|
29
|
+
<view className={css.container} bindtap={bindtap}>
|
|
30
|
+
<view className={css.button}>{children}</view>
|
|
31
|
+
</view>
|
|
32
|
+
<view className={css.reloadButton} bindtap={handleReload}>
|
|
33
|
+
<text className={css.reloadIcon}>{"\u21BB"}</text>
|
|
34
|
+
</view>
|
|
35
|
+
</view>
|
|
36
|
+
);
|
|
37
|
+
};
|