apps-key-guard 0.0.1 → 0.0.2

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 CHANGED
@@ -10,6 +10,10 @@
10
10
  - 支持密钥过期检查
11
11
  - 完全可自定义样式
12
12
  - TypeScript 支持
13
+ - 悬浮窗显示用户信息(应用名称、密钥、等级、过期时间)
14
+ - 密钥显示/隐藏切换(小眼睛图标)
15
+ - 一键退出登录功能
16
+ - 自动安全防护(关闭面板时隐藏密钥)
13
17
 
14
18
  ## 安装
15
19
 
@@ -81,11 +85,12 @@ function App() {
81
85
  | `appName` | `string` | 是 | - | 应用名称,用于标识应用 |
82
86
  | `apiBaseUrl` | `string` | 否 | `http://localhost:8080` | API 基础 URL |
83
87
  | `children` | `ReactNode` | 是 | - | 验证成功后要渲染的子组件 |
84
- | `onValidated` | `(level: string) => void` | 否 | - | 验证成功后的回调函数,返回密钥等级 |
88
+ | `onValidated` | `(level: Level) => void` | 否 | - | 验证成功后的回调函数,返回密钥等级 |
85
89
  | `customStyle` | `CSSProperties` | 否 | - | 自定义容器样式 |
86
90
  | `title` | `string` | 否 | `访问验证` | 标题文本 |
87
91
  | `placeholder` | `string` | 否 | `请输入访问密钥` | 输入框占位符 |
88
92
  | `buttonText` | `string` | 否 | `验证` | 按钮文本 |
93
+ | `showFloatingButton` | `boolean` | 否 | `true` | 是否显示悬浮按钮 |
89
94
 
90
95
  ## 工作原理
91
96
 
@@ -95,6 +100,22 @@ function App() {
95
100
  4. 验证失败时,显示密钥输入表单
96
101
  5. 用户输入密钥后,调用后端 API 进行验证
97
102
  6. 验证成功后,将密钥存储到 localStorage,并渲染子组件
103
+ 7. 验证成功后,右下角显示悬浮按钮,点击可查看密钥信息
104
+ 8. 用户可以通过悬浮窗中的"退出登录"按钮清除本地密钥
105
+
106
+ ## 悬浮窗功能
107
+
108
+ 验证成功后,页面右下角会显示一个悬浮按钮。点击按钮可以打开信息面板,显示:
109
+
110
+ - **应用名称**: 当前访问的应用
111
+ - **密钥**: 默认隐藏显示(用 • 符号遮蔽),点击小眼睛图标可切换显示/隐藏
112
+ - **等级**: 密钥等级(游客/VIP/高级 VIP)
113
+ - **过期时间**: 密钥的过期时间或"永久有效"
114
+ - **退出登录**: 清除本地存储的密钥并返回验证页面
115
+
116
+ **安全性**:关闭面板时会自动重置密钥显示状态为隐藏,保护用户隐私。
117
+
118
+ 可以通过 `showFloatingButton={false}` 禁用悬浮窗功能。
98
119
 
99
120
  ## 后端 API 要求
100
121
 
package/dist/index.d.mts CHANGED
@@ -15,7 +15,10 @@ interface KeyGuardProps {
15
15
  title?: string;
16
16
  placeholder?: string;
17
17
  buttonText?: string;
18
+ showFloatingButton?: boolean;
19
+ authorWechat?: string;
20
+ authorQrCode?: string;
18
21
  }
19
22
  declare const KeyGuard: React.FC<KeyGuardProps>;
20
23
 
21
- export { KeyGuard, type KeyGuardProps, KeyGuard as default };
24
+ export { KeyGuard, type KeyGuardProps, Level, KeyGuard as default };
package/dist/index.d.ts CHANGED
@@ -15,7 +15,10 @@ interface KeyGuardProps {
15
15
  title?: string;
16
16
  placeholder?: string;
17
17
  buttonText?: string;
18
+ showFloatingButton?: boolean;
19
+ authorWechat?: string;
20
+ authorQrCode?: string;
18
21
  }
19
22
  declare const KeyGuard: React.FC<KeyGuardProps>;
20
23
 
21
- export { KeyGuard, type KeyGuardProps, KeyGuard as default };
24
+ export { KeyGuard, type KeyGuardProps, Level, KeyGuard as default };
package/dist/index.js CHANGED
@@ -31,12 +31,20 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  KeyGuard: () => KeyGuard,
34
+ Level: () => Level,
34
35
  default: () => index_default
35
36
  });
36
37
  module.exports = __toCommonJS(index_exports);
37
38
  var import_react = require("react");
38
39
  var import_axios = __toESM(require("axios"));
39
40
  var import_jsx_runtime = require("react/jsx-runtime");
41
+ var Level = /* @__PURE__ */ ((Level2) => {
42
+ Level2["None"] = "none";
43
+ Level2["Guest"] = "guest";
44
+ Level2["VIP"] = "vip";
45
+ Level2["SuperVIP"] = "super_vip";
46
+ return Level2;
47
+ })(Level || {});
40
48
  var STORAGE_KEY_PREFIX = "apps_admin_key_";
41
49
  var KeyGuard = ({
42
50
  appName,
@@ -46,14 +54,22 @@ var KeyGuard = ({
46
54
  customStyle,
47
55
  title = "\u8BBF\u95EE\u9A8C\u8BC1",
48
56
  placeholder = "\u8BF7\u8F93\u5165\u8BBF\u95EE\u5BC6\u94A5",
49
- buttonText = "\u9A8C\u8BC1"
57
+ buttonText = "\u9A8C\u8BC1",
58
+ showFloatingButton = true,
59
+ authorWechat = "zhoulixiang0305",
60
+ authorQrCode = "https://i.postimg.cc/bJz33sy2/saler.jpg"
50
61
  }) => {
51
62
  const [isValidated, setIsValidated] = (0, import_react.useState)(false);
52
63
  const [keyValue, setKeyValue] = (0, import_react.useState)("");
53
64
  const [error, setError] = (0, import_react.useState)("");
54
65
  const [loading, setLoading] = (0, import_react.useState)(false);
55
66
  const [initializing, setInitializing] = (0, import_react.useState)(true);
67
+ const [userInfo, setUserInfo] = (0, import_react.useState)(null);
68
+ const [showPanel, setShowPanel] = (0, import_react.useState)(false);
69
+ const [showKey, setShowKey] = (0, import_react.useState)(false);
70
+ const [showContactDialog, setShowContactDialog] = (0, import_react.useState)(false);
56
71
  const storageKey = `${STORAGE_KEY_PREFIX}${appName}`;
72
+ const storageInfoKey = `${STORAGE_KEY_PREFIX}${appName}_info`;
57
73
  const verifyKey = async (key) => {
58
74
  try {
59
75
  const response = await import_axios.default.post(
@@ -64,8 +80,15 @@ var KeyGuard = ({
64
80
  }
65
81
  );
66
82
  const { data } = response.data;
67
- if (data.valid && data.level && data.level !== "none") {
83
+ if (data.valid && data.level && data.level !== "none" /* None */) {
68
84
  localStorage.setItem(storageKey, key);
85
+ const info = {
86
+ keyValue: key,
87
+ level: data.level,
88
+ expiresAt: data.expires_at
89
+ };
90
+ setUserInfo(info);
91
+ localStorage.setItem(storageInfoKey, JSON.stringify(info));
69
92
  if (onValidated && data.level) {
70
93
  onValidated(data.level);
71
94
  }
@@ -86,12 +109,22 @@ var KeyGuard = ({
86
109
  (0, import_react.useEffect)(() => {
87
110
  const checkStoredKey = async () => {
88
111
  const storedKey = localStorage.getItem(storageKey);
112
+ const storedInfo = localStorage.getItem(storageInfoKey);
89
113
  if (storedKey) {
114
+ if (storedInfo) {
115
+ try {
116
+ const info = JSON.parse(storedInfo);
117
+ setUserInfo(info);
118
+ } catch (e) {
119
+ }
120
+ }
90
121
  const isValid = await verifyKey(storedKey);
91
122
  if (isValid) {
92
123
  setIsValidated(true);
93
124
  } else {
94
125
  localStorage.removeItem(storageKey);
126
+ localStorage.removeItem(storageInfoKey);
127
+ setUserInfo(null);
95
128
  }
96
129
  }
97
130
  setInitializing(false);
@@ -112,11 +145,224 @@ var KeyGuard = ({
112
145
  }
113
146
  setLoading(false);
114
147
  };
148
+ const handleLogout = () => {
149
+ localStorage.removeItem(storageKey);
150
+ localStorage.removeItem(storageInfoKey);
151
+ setUserInfo(null);
152
+ setIsValidated(false);
153
+ setKeyValue("");
154
+ setShowPanel(false);
155
+ setShowKey(false);
156
+ };
157
+ const handleClosePanel = () => {
158
+ setShowPanel(false);
159
+ setShowKey(false);
160
+ setShowContactDialog(false);
161
+ };
162
+ const formatLevel = (level) => {
163
+ const levelMap = {
164
+ ["none" /* None */]: "\u65E0\u6743\u9650",
165
+ ["guest" /* Guest */]: "\u6E38\u5BA2",
166
+ ["vip" /* VIP */]: "VIP",
167
+ ["super_vip" /* SuperVIP */]: "\u9AD8\u7EA7 VIP"
168
+ };
169
+ return levelMap[level] || level;
170
+ };
171
+ const formatExpiresAt = (expiresAt) => {
172
+ if (!expiresAt) return "\u6C38\u4E45\u6709\u6548";
173
+ try {
174
+ const date = new Date(expiresAt);
175
+ return date.toLocaleString("zh-CN");
176
+ } catch (e) {
177
+ return expiresAt;
178
+ }
179
+ };
115
180
  if (initializing) {
116
181
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: defaultCardStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: loadingStyle, children: "\u9A8C\u8BC1\u4E2D..." }) }) });
117
182
  }
118
183
  if (isValidated) {
119
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
184
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
185
+ children,
186
+ showFloatingButton && userInfo && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
187
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
188
+ "button",
189
+ {
190
+ onClick: () => setShowPanel(!showPanel),
191
+ style: floatingButtonStyle,
192
+ "aria-label": "\u7528\u6237\u4FE1\u606F",
193
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
194
+ "svg",
195
+ {
196
+ width: "24",
197
+ height: "24",
198
+ viewBox: "0 0 24 24",
199
+ fill: "none",
200
+ stroke: "currentColor",
201
+ strokeWidth: "2",
202
+ children: [
203
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
204
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "7", r: "4" })
205
+ ]
206
+ }
207
+ )
208
+ }
209
+ ),
210
+ showPanel && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
211
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: overlayStyle, onClick: handleClosePanel }),
212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelStyle, children: [
213
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelHeaderStyle, children: [
214
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: panelTitleStyle, children: "\u5BC6\u94A5\u4FE1\u606F" }),
215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
216
+ "button",
217
+ {
218
+ onClick: handleClosePanel,
219
+ style: closeButtonStyle,
220
+ "aria-label": "\u5173\u95ED",
221
+ children: "\u2715"
222
+ }
223
+ )
224
+ ] }),
225
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelBodyStyle, children: [
226
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: infoItemStyle, children: [
227
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoLabelStyle, children: "\u5E94\u7528\u540D\u79F0" }),
228
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoValueStyle, children: appName })
229
+ ] }),
230
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: infoItemStyle, children: [
231
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoLabelStyle, children: "\u5BC6\u94A5" }),
232
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: keyDisplayContainerStyle, children: [
233
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoValueStyle, children: showKey ? userInfo.keyValue : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }),
234
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
235
+ "button",
236
+ {
237
+ onClick: () => setShowKey(!showKey),
238
+ style: eyeButtonStyle,
239
+ "aria-label": showKey ? "\u9690\u85CF\u5BC6\u94A5" : "\u663E\u793A\u5BC6\u94A5",
240
+ children: showKey ? (
241
+ // 睁眼图标
242
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
243
+ "svg",
244
+ {
245
+ width: "18",
246
+ height: "18",
247
+ viewBox: "0 0 24 24",
248
+ fill: "none",
249
+ stroke: "currentColor",
250
+ strokeWidth: "2",
251
+ strokeLinecap: "round",
252
+ strokeLinejoin: "round",
253
+ children: [
254
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("circle", { cx: "12", cy: "12", r: "3" })
256
+ ]
257
+ }
258
+ )
259
+ ) : (
260
+ // 闭眼图标
261
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
262
+ "svg",
263
+ {
264
+ width: "18",
265
+ height: "18",
266
+ viewBox: "0 0 24 24",
267
+ fill: "none",
268
+ stroke: "currentColor",
269
+ strokeWidth: "2",
270
+ strokeLinecap: "round",
271
+ strokeLinejoin: "round",
272
+ children: [
273
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
274
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
275
+ ]
276
+ }
277
+ )
278
+ )
279
+ }
280
+ )
281
+ ] })
282
+ ] }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: infoItemStyle, children: [
284
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoLabelStyle, children: "\u7B49\u7EA7" }),
285
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: levelBadgeStyle(userInfo.level), children: formatLevel(userInfo.level) })
286
+ ] }),
287
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: infoItemStyle, children: [
288
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoLabelStyle, children: "\u8FC7\u671F\u65F6\u95F4" }),
289
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: infoValueStyle, children: formatExpiresAt(userInfo.expiresAt) })
290
+ ] })
291
+ ] }),
292
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelFooterStyle, children: [
293
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
294
+ "button",
295
+ {
296
+ onClick: () => setShowContactDialog(true),
297
+ style: contactButtonStyle,
298
+ children: "\u8054\u7CFB\u4F5C\u8005"
299
+ }
300
+ ),
301
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", { onClick: handleLogout, style: logoutButtonStyle, children: "\u9000\u51FA\u767B\u5F55" })
302
+ ] })
303
+ ] })
304
+ ] }),
305
+ showContactDialog && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
306
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
307
+ "div",
308
+ {
309
+ style: overlayStyle,
310
+ onClick: () => setShowContactDialog(false)
311
+ }
312
+ ),
313
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: contactDialogStyle, children: [
314
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: panelHeaderStyle, children: [
315
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { style: panelTitleStyle, children: "\u8054\u7CFB\u4F5C\u8005" }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
317
+ "button",
318
+ {
319
+ onClick: () => setShowContactDialog(false),
320
+ style: closeButtonStyle,
321
+ "aria-label": "\u5173\u95ED",
322
+ children: "\u2715"
323
+ }
324
+ )
325
+ ] }),
326
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: contactDialogBodyStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: contactInfoStyle, children: [
327
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: wechatInfoStyle, children: [
328
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: wechatLabelStyle, children: "\u5FAE\u4FE1\u53F7\uFF1A" }),
329
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: wechatValueStyle, children: authorWechat }),
330
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
331
+ "button",
332
+ {
333
+ onClick: () => {
334
+ navigator.clipboard.writeText(authorWechat).then(() => {
335
+ alert("\u5FAE\u4FE1\u53F7\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
336
+ }).catch(() => {
337
+ alert("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u590D\u5236");
338
+ });
339
+ },
340
+ style: copyButtonStyle,
341
+ "aria-label": "\u590D\u5236\u5FAE\u4FE1\u53F7",
342
+ children: "\u590D\u5236"
343
+ }
344
+ )
345
+ ] }),
346
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: qrCodeContainerStyle, children: [
347
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: qrCodeLabelStyle, children: "\u626B\u7801\u6DFB\u52A0\u5FAE\u4FE1" }),
348
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: qrCodePlaceholderStyle, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
349
+ "img",
350
+ {
351
+ src: authorQrCode,
352
+ alt: "\u5FAE\u4FE1\u4E8C\u7EF4\u7801",
353
+ style: qrCodeImageStyle,
354
+ onError: (e) => {
355
+ const target = e.target;
356
+ target.src = "https://via.placeholder.com/200x200?text=\u4E8C\u7EF4\u7801\u52A0\u8F7D\u5931\u8D25";
357
+ }
358
+ }
359
+ ) })
360
+ ] })
361
+ ] }) })
362
+ ] })
363
+ ] })
364
+ ] })
365
+ ] });
120
366
  }
121
367
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: defaultCardStyle, children: [
122
368
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: titleStyle, children: title }),
@@ -193,8 +439,249 @@ var loadingStyle = {
193
439
  color: "#666",
194
440
  fontSize: "1rem"
195
441
  };
442
+ var floatingButtonStyle = {
443
+ position: "fixed",
444
+ bottom: "2rem",
445
+ right: "2rem",
446
+ width: "56px",
447
+ height: "56px",
448
+ borderRadius: "50%",
449
+ backgroundColor: "#007bff",
450
+ color: "white",
451
+ border: "none",
452
+ boxShadow: "0 4px 12px rgba(0, 123, 255, 0.4)",
453
+ cursor: "pointer",
454
+ display: "flex",
455
+ alignItems: "center",
456
+ justifyContent: "center",
457
+ transition: "all 0.3s ease",
458
+ zIndex: 1e3
459
+ };
460
+ var overlayStyle = {
461
+ position: "fixed",
462
+ top: 0,
463
+ left: 0,
464
+ right: 0,
465
+ bottom: 0,
466
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
467
+ zIndex: 1001,
468
+ animation: "fadeIn 0.2s ease"
469
+ };
470
+ var panelStyle = {
471
+ position: "fixed",
472
+ top: "50%",
473
+ left: "50%",
474
+ transform: "translate(-50%, -50%)",
475
+ backgroundColor: "white",
476
+ borderRadius: "12px",
477
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
478
+ width: "90%",
479
+ maxWidth: "400px",
480
+ zIndex: 1002,
481
+ animation: "slideIn 0.3s ease"
482
+ };
483
+ var panelHeaderStyle = {
484
+ display: "flex",
485
+ justifyContent: "space-between",
486
+ alignItems: "center",
487
+ padding: "1.5rem",
488
+ borderBottom: "1px solid #e9ecef"
489
+ };
490
+ var panelTitleStyle = {
491
+ margin: 0,
492
+ fontSize: "1.25rem",
493
+ fontWeight: "600",
494
+ color: "#333"
495
+ };
496
+ var closeButtonStyle = {
497
+ background: "none",
498
+ border: "none",
499
+ fontSize: "1.5rem",
500
+ color: "#999",
501
+ cursor: "pointer",
502
+ padding: "0",
503
+ width: "32px",
504
+ height: "32px",
505
+ display: "flex",
506
+ alignItems: "center",
507
+ justifyContent: "center",
508
+ borderRadius: "4px",
509
+ transition: "background-color 0.2s"
510
+ };
511
+ var panelBodyStyle = {
512
+ padding: "1.5rem",
513
+ display: "flex",
514
+ flexDirection: "column",
515
+ gap: "1rem"
516
+ };
517
+ var infoItemStyle = {
518
+ display: "flex",
519
+ justifyContent: "space-between",
520
+ alignItems: "center",
521
+ padding: "0.75rem",
522
+ backgroundColor: "#f8f9fa",
523
+ borderRadius: "6px"
524
+ };
525
+ var keyDisplayContainerStyle = {
526
+ display: "flex",
527
+ alignItems: "center",
528
+ gap: "0.5rem"
529
+ };
530
+ var eyeButtonStyle = {
531
+ background: "none",
532
+ border: "none",
533
+ color: "#6c757d",
534
+ cursor: "pointer",
535
+ padding: "0.25rem",
536
+ display: "flex",
537
+ alignItems: "center",
538
+ justifyContent: "center",
539
+ borderRadius: "4px",
540
+ transition: "all 0.2s"
541
+ };
542
+ var infoLabelStyle = {
543
+ fontSize: "0.875rem",
544
+ color: "#6c757d",
545
+ fontWeight: "500"
546
+ };
547
+ var infoValueStyle = {
548
+ fontSize: "0.875rem",
549
+ color: "#333",
550
+ fontWeight: "500"
551
+ };
552
+ var levelBadgeStyle = (level) => {
553
+ const colors = {
554
+ ["none" /* None */]: { bg: "#6c757d", color: "white" },
555
+ ["guest" /* Guest */]: { bg: "#17a2b8", color: "white" },
556
+ ["vip" /* VIP */]: { bg: "#ffc107", color: "#333" },
557
+ ["super_vip" /* SuperVIP */]: { bg: "#dc3545", color: "white" }
558
+ };
559
+ const { bg, color } = colors[level] || colors["none" /* None */];
560
+ return {
561
+ padding: "0.25rem 0.75rem",
562
+ borderRadius: "12px",
563
+ backgroundColor: bg,
564
+ color,
565
+ fontSize: "0.75rem",
566
+ fontWeight: "600",
567
+ textTransform: "uppercase"
568
+ };
569
+ };
570
+ var panelFooterStyle = {
571
+ padding: "1.5rem",
572
+ borderTop: "1px solid #e9ecef"
573
+ };
574
+ var contactButtonStyle = {
575
+ width: "100%",
576
+ padding: "0.75rem",
577
+ fontSize: "1rem",
578
+ fontWeight: "500",
579
+ color: "white",
580
+ backgroundColor: "#28a745",
581
+ border: "none",
582
+ borderRadius: "6px",
583
+ cursor: "pointer",
584
+ transition: "background-color 0.2s",
585
+ marginBottom: "0.75rem"
586
+ };
587
+ var logoutButtonStyle = {
588
+ width: "100%",
589
+ padding: "0.75rem",
590
+ fontSize: "1rem",
591
+ fontWeight: "500",
592
+ color: "white",
593
+ backgroundColor: "#dc3545",
594
+ border: "none",
595
+ borderRadius: "6px",
596
+ cursor: "pointer",
597
+ transition: "background-color 0.2s"
598
+ };
599
+ var contactDialogStyle = {
600
+ position: "fixed",
601
+ top: "50%",
602
+ left: "50%",
603
+ transform: "translate(-50%, -50%)",
604
+ backgroundColor: "white",
605
+ borderRadius: "12px",
606
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
607
+ width: "90%",
608
+ maxWidth: "400px",
609
+ zIndex: 1003,
610
+ animation: "slideIn 0.3s ease"
611
+ };
612
+ var contactDialogBodyStyle = {
613
+ padding: "1.5rem",
614
+ display: "flex",
615
+ flexDirection: "column",
616
+ gap: "1.5rem"
617
+ };
618
+ var contactInfoStyle = {
619
+ display: "flex",
620
+ flexDirection: "column",
621
+ gap: "1.5rem"
622
+ };
623
+ var wechatInfoStyle = {
624
+ display: "flex",
625
+ alignItems: "center",
626
+ gap: "0.75rem",
627
+ padding: "1rem",
628
+ backgroundColor: "#f8f9fa",
629
+ borderRadius: "8px",
630
+ flexWrap: "wrap"
631
+ };
632
+ var wechatLabelStyle = {
633
+ fontSize: "0.875rem",
634
+ color: "#6c757d",
635
+ fontWeight: "500"
636
+ };
637
+ var wechatValueStyle = {
638
+ fontSize: "1rem",
639
+ color: "#333",
640
+ fontWeight: "600",
641
+ flex: 1,
642
+ minWidth: "120px"
643
+ };
644
+ var copyButtonStyle = {
645
+ padding: "0.5rem 1rem",
646
+ fontSize: "0.875rem",
647
+ fontWeight: "500",
648
+ color: "#007bff",
649
+ backgroundColor: "white",
650
+ border: "1px solid #007bff",
651
+ borderRadius: "4px",
652
+ cursor: "pointer",
653
+ transition: "all 0.2s"
654
+ };
655
+ var qrCodeContainerStyle = {
656
+ display: "flex",
657
+ flexDirection: "column",
658
+ alignItems: "center",
659
+ gap: "1rem"
660
+ };
661
+ var qrCodeLabelStyle = {
662
+ fontSize: "0.875rem",
663
+ color: "#6c757d",
664
+ fontWeight: "500"
665
+ };
666
+ var qrCodePlaceholderStyle = {
667
+ display: "flex",
668
+ flexDirection: "column",
669
+ alignItems: "center",
670
+ gap: "0.5rem",
671
+ padding: "1rem",
672
+ backgroundColor: "#f8f9fa",
673
+ borderRadius: "8px",
674
+ width: "100%"
675
+ };
676
+ var qrCodeImageStyle = {
677
+ width: "200px",
678
+ height: "200px",
679
+ borderRadius: "8px",
680
+ border: "1px solid #e9ecef"
681
+ };
196
682
  var index_default = KeyGuard;
197
683
  // Annotate the CommonJS export names for ESM import in node:
198
684
  0 && (module.exports = {
199
- KeyGuard
685
+ KeyGuard,
686
+ Level
200
687
  });
package/dist/index.mjs CHANGED
@@ -2,6 +2,13 @@
2
2
  import { useState, useEffect } from "react";
3
3
  import axios from "axios";
4
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ var Level = /* @__PURE__ */ ((Level2) => {
6
+ Level2["None"] = "none";
7
+ Level2["Guest"] = "guest";
8
+ Level2["VIP"] = "vip";
9
+ Level2["SuperVIP"] = "super_vip";
10
+ return Level2;
11
+ })(Level || {});
5
12
  var STORAGE_KEY_PREFIX = "apps_admin_key_";
6
13
  var KeyGuard = ({
7
14
  appName,
@@ -11,14 +18,22 @@ var KeyGuard = ({
11
18
  customStyle,
12
19
  title = "\u8BBF\u95EE\u9A8C\u8BC1",
13
20
  placeholder = "\u8BF7\u8F93\u5165\u8BBF\u95EE\u5BC6\u94A5",
14
- buttonText = "\u9A8C\u8BC1"
21
+ buttonText = "\u9A8C\u8BC1",
22
+ showFloatingButton = true,
23
+ authorWechat = "zhoulixiang0305",
24
+ authorQrCode = "https://i.postimg.cc/bJz33sy2/saler.jpg"
15
25
  }) => {
16
26
  const [isValidated, setIsValidated] = useState(false);
17
27
  const [keyValue, setKeyValue] = useState("");
18
28
  const [error, setError] = useState("");
19
29
  const [loading, setLoading] = useState(false);
20
30
  const [initializing, setInitializing] = useState(true);
31
+ const [userInfo, setUserInfo] = useState(null);
32
+ const [showPanel, setShowPanel] = useState(false);
33
+ const [showKey, setShowKey] = useState(false);
34
+ const [showContactDialog, setShowContactDialog] = useState(false);
21
35
  const storageKey = `${STORAGE_KEY_PREFIX}${appName}`;
36
+ const storageInfoKey = `${STORAGE_KEY_PREFIX}${appName}_info`;
22
37
  const verifyKey = async (key) => {
23
38
  try {
24
39
  const response = await axios.post(
@@ -29,8 +44,15 @@ var KeyGuard = ({
29
44
  }
30
45
  );
31
46
  const { data } = response.data;
32
- if (data.valid && data.level && data.level !== "none") {
47
+ if (data.valid && data.level && data.level !== "none" /* None */) {
33
48
  localStorage.setItem(storageKey, key);
49
+ const info = {
50
+ keyValue: key,
51
+ level: data.level,
52
+ expiresAt: data.expires_at
53
+ };
54
+ setUserInfo(info);
55
+ localStorage.setItem(storageInfoKey, JSON.stringify(info));
34
56
  if (onValidated && data.level) {
35
57
  onValidated(data.level);
36
58
  }
@@ -51,12 +73,22 @@ var KeyGuard = ({
51
73
  useEffect(() => {
52
74
  const checkStoredKey = async () => {
53
75
  const storedKey = localStorage.getItem(storageKey);
76
+ const storedInfo = localStorage.getItem(storageInfoKey);
54
77
  if (storedKey) {
78
+ if (storedInfo) {
79
+ try {
80
+ const info = JSON.parse(storedInfo);
81
+ setUserInfo(info);
82
+ } catch (e) {
83
+ }
84
+ }
55
85
  const isValid = await verifyKey(storedKey);
56
86
  if (isValid) {
57
87
  setIsValidated(true);
58
88
  } else {
59
89
  localStorage.removeItem(storageKey);
90
+ localStorage.removeItem(storageInfoKey);
91
+ setUserInfo(null);
60
92
  }
61
93
  }
62
94
  setInitializing(false);
@@ -77,11 +109,224 @@ var KeyGuard = ({
77
109
  }
78
110
  setLoading(false);
79
111
  };
112
+ const handleLogout = () => {
113
+ localStorage.removeItem(storageKey);
114
+ localStorage.removeItem(storageInfoKey);
115
+ setUserInfo(null);
116
+ setIsValidated(false);
117
+ setKeyValue("");
118
+ setShowPanel(false);
119
+ setShowKey(false);
120
+ };
121
+ const handleClosePanel = () => {
122
+ setShowPanel(false);
123
+ setShowKey(false);
124
+ setShowContactDialog(false);
125
+ };
126
+ const formatLevel = (level) => {
127
+ const levelMap = {
128
+ ["none" /* None */]: "\u65E0\u6743\u9650",
129
+ ["guest" /* Guest */]: "\u6E38\u5BA2",
130
+ ["vip" /* VIP */]: "VIP",
131
+ ["super_vip" /* SuperVIP */]: "\u9AD8\u7EA7 VIP"
132
+ };
133
+ return levelMap[level] || level;
134
+ };
135
+ const formatExpiresAt = (expiresAt) => {
136
+ if (!expiresAt) return "\u6C38\u4E45\u6709\u6548";
137
+ try {
138
+ const date = new Date(expiresAt);
139
+ return date.toLocaleString("zh-CN");
140
+ } catch (e) {
141
+ return expiresAt;
142
+ }
143
+ };
80
144
  if (initializing) {
81
145
  return /* @__PURE__ */ jsx("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ jsx("div", { style: defaultCardStyle, children: /* @__PURE__ */ jsx("div", { style: loadingStyle, children: "\u9A8C\u8BC1\u4E2D..." }) }) });
82
146
  }
83
147
  if (isValidated) {
84
- return /* @__PURE__ */ jsx(Fragment, { children });
148
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
149
+ children,
150
+ showFloatingButton && userInfo && /* @__PURE__ */ jsxs(Fragment, { children: [
151
+ /* @__PURE__ */ jsx(
152
+ "button",
153
+ {
154
+ onClick: () => setShowPanel(!showPanel),
155
+ style: floatingButtonStyle,
156
+ "aria-label": "\u7528\u6237\u4FE1\u606F",
157
+ children: /* @__PURE__ */ jsxs(
158
+ "svg",
159
+ {
160
+ width: "24",
161
+ height: "24",
162
+ viewBox: "0 0 24 24",
163
+ fill: "none",
164
+ stroke: "currentColor",
165
+ strokeWidth: "2",
166
+ children: [
167
+ /* @__PURE__ */ jsx("path", { d: "M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2" }),
168
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "7", r: "4" })
169
+ ]
170
+ }
171
+ )
172
+ }
173
+ ),
174
+ showPanel && /* @__PURE__ */ jsxs(Fragment, { children: [
175
+ /* @__PURE__ */ jsx("div", { style: overlayStyle, onClick: handleClosePanel }),
176
+ /* @__PURE__ */ jsxs("div", { style: panelStyle, children: [
177
+ /* @__PURE__ */ jsxs("div", { style: panelHeaderStyle, children: [
178
+ /* @__PURE__ */ jsx("h3", { style: panelTitleStyle, children: "\u5BC6\u94A5\u4FE1\u606F" }),
179
+ /* @__PURE__ */ jsx(
180
+ "button",
181
+ {
182
+ onClick: handleClosePanel,
183
+ style: closeButtonStyle,
184
+ "aria-label": "\u5173\u95ED",
185
+ children: "\u2715"
186
+ }
187
+ )
188
+ ] }),
189
+ /* @__PURE__ */ jsxs("div", { style: panelBodyStyle, children: [
190
+ /* @__PURE__ */ jsxs("div", { style: infoItemStyle, children: [
191
+ /* @__PURE__ */ jsx("span", { style: infoLabelStyle, children: "\u5E94\u7528\u540D\u79F0" }),
192
+ /* @__PURE__ */ jsx("span", { style: infoValueStyle, children: appName })
193
+ ] }),
194
+ /* @__PURE__ */ jsxs("div", { style: infoItemStyle, children: [
195
+ /* @__PURE__ */ jsx("span", { style: infoLabelStyle, children: "\u5BC6\u94A5" }),
196
+ /* @__PURE__ */ jsxs("div", { style: keyDisplayContainerStyle, children: [
197
+ /* @__PURE__ */ jsx("span", { style: infoValueStyle, children: showKey ? userInfo.keyValue : "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022" }),
198
+ /* @__PURE__ */ jsx(
199
+ "button",
200
+ {
201
+ onClick: () => setShowKey(!showKey),
202
+ style: eyeButtonStyle,
203
+ "aria-label": showKey ? "\u9690\u85CF\u5BC6\u94A5" : "\u663E\u793A\u5BC6\u94A5",
204
+ children: showKey ? (
205
+ // 睁眼图标
206
+ /* @__PURE__ */ jsxs(
207
+ "svg",
208
+ {
209
+ width: "18",
210
+ height: "18",
211
+ viewBox: "0 0 24 24",
212
+ fill: "none",
213
+ stroke: "currentColor",
214
+ strokeWidth: "2",
215
+ strokeLinecap: "round",
216
+ strokeLinejoin: "round",
217
+ children: [
218
+ /* @__PURE__ */ jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
219
+ /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "3" })
220
+ ]
221
+ }
222
+ )
223
+ ) : (
224
+ // 闭眼图标
225
+ /* @__PURE__ */ jsxs(
226
+ "svg",
227
+ {
228
+ width: "18",
229
+ height: "18",
230
+ viewBox: "0 0 24 24",
231
+ fill: "none",
232
+ stroke: "currentColor",
233
+ strokeWidth: "2",
234
+ strokeLinecap: "round",
235
+ strokeLinejoin: "round",
236
+ children: [
237
+ /* @__PURE__ */ jsx("path", { d: "M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" }),
238
+ /* @__PURE__ */ jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
239
+ ]
240
+ }
241
+ )
242
+ )
243
+ }
244
+ )
245
+ ] })
246
+ ] }),
247
+ /* @__PURE__ */ jsxs("div", { style: infoItemStyle, children: [
248
+ /* @__PURE__ */ jsx("span", { style: infoLabelStyle, children: "\u7B49\u7EA7" }),
249
+ /* @__PURE__ */ jsx("span", { style: levelBadgeStyle(userInfo.level), children: formatLevel(userInfo.level) })
250
+ ] }),
251
+ /* @__PURE__ */ jsxs("div", { style: infoItemStyle, children: [
252
+ /* @__PURE__ */ jsx("span", { style: infoLabelStyle, children: "\u8FC7\u671F\u65F6\u95F4" }),
253
+ /* @__PURE__ */ jsx("span", { style: infoValueStyle, children: formatExpiresAt(userInfo.expiresAt) })
254
+ ] })
255
+ ] }),
256
+ /* @__PURE__ */ jsxs("div", { style: panelFooterStyle, children: [
257
+ /* @__PURE__ */ jsx(
258
+ "button",
259
+ {
260
+ onClick: () => setShowContactDialog(true),
261
+ style: contactButtonStyle,
262
+ children: "\u8054\u7CFB\u4F5C\u8005"
263
+ }
264
+ ),
265
+ /* @__PURE__ */ jsx("button", { onClick: handleLogout, style: logoutButtonStyle, children: "\u9000\u51FA\u767B\u5F55" })
266
+ ] })
267
+ ] })
268
+ ] }),
269
+ showContactDialog && /* @__PURE__ */ jsxs(Fragment, { children: [
270
+ /* @__PURE__ */ jsx(
271
+ "div",
272
+ {
273
+ style: overlayStyle,
274
+ onClick: () => setShowContactDialog(false)
275
+ }
276
+ ),
277
+ /* @__PURE__ */ jsxs("div", { style: contactDialogStyle, children: [
278
+ /* @__PURE__ */ jsxs("div", { style: panelHeaderStyle, children: [
279
+ /* @__PURE__ */ jsx("h3", { style: panelTitleStyle, children: "\u8054\u7CFB\u4F5C\u8005" }),
280
+ /* @__PURE__ */ jsx(
281
+ "button",
282
+ {
283
+ onClick: () => setShowContactDialog(false),
284
+ style: closeButtonStyle,
285
+ "aria-label": "\u5173\u95ED",
286
+ children: "\u2715"
287
+ }
288
+ )
289
+ ] }),
290
+ /* @__PURE__ */ jsx("div", { style: contactDialogBodyStyle, children: /* @__PURE__ */ jsxs("div", { style: contactInfoStyle, children: [
291
+ /* @__PURE__ */ jsxs("div", { style: wechatInfoStyle, children: [
292
+ /* @__PURE__ */ jsx("span", { style: wechatLabelStyle, children: "\u5FAE\u4FE1\u53F7\uFF1A" }),
293
+ /* @__PURE__ */ jsx("span", { style: wechatValueStyle, children: authorWechat }),
294
+ /* @__PURE__ */ jsx(
295
+ "button",
296
+ {
297
+ onClick: () => {
298
+ navigator.clipboard.writeText(authorWechat).then(() => {
299
+ alert("\u5FAE\u4FE1\u53F7\u5DF2\u590D\u5236\u5230\u526A\u8D34\u677F");
300
+ }).catch(() => {
301
+ alert("\u590D\u5236\u5931\u8D25\uFF0C\u8BF7\u624B\u52A8\u590D\u5236");
302
+ });
303
+ },
304
+ style: copyButtonStyle,
305
+ "aria-label": "\u590D\u5236\u5FAE\u4FE1\u53F7",
306
+ children: "\u590D\u5236"
307
+ }
308
+ )
309
+ ] }),
310
+ /* @__PURE__ */ jsxs("div", { style: qrCodeContainerStyle, children: [
311
+ /* @__PURE__ */ jsx("div", { style: qrCodeLabelStyle, children: "\u626B\u7801\u6DFB\u52A0\u5FAE\u4FE1" }),
312
+ /* @__PURE__ */ jsx("div", { style: qrCodePlaceholderStyle, children: /* @__PURE__ */ jsx(
313
+ "img",
314
+ {
315
+ src: authorQrCode,
316
+ alt: "\u5FAE\u4FE1\u4E8C\u7EF4\u7801",
317
+ style: qrCodeImageStyle,
318
+ onError: (e) => {
319
+ const target = e.target;
320
+ target.src = "https://via.placeholder.com/200x200?text=\u4E8C\u7EF4\u7801\u52A0\u8F7D\u5931\u8D25";
321
+ }
322
+ }
323
+ ) })
324
+ ] })
325
+ ] }) })
326
+ ] })
327
+ ] })
328
+ ] })
329
+ ] });
85
330
  }
86
331
  return /* @__PURE__ */ jsx("div", { style: { ...defaultContainerStyle, ...customStyle }, children: /* @__PURE__ */ jsxs("div", { style: defaultCardStyle, children: [
87
332
  /* @__PURE__ */ jsx("h2", { style: titleStyle, children: title }),
@@ -158,8 +403,249 @@ var loadingStyle = {
158
403
  color: "#666",
159
404
  fontSize: "1rem"
160
405
  };
406
+ var floatingButtonStyle = {
407
+ position: "fixed",
408
+ bottom: "2rem",
409
+ right: "2rem",
410
+ width: "56px",
411
+ height: "56px",
412
+ borderRadius: "50%",
413
+ backgroundColor: "#007bff",
414
+ color: "white",
415
+ border: "none",
416
+ boxShadow: "0 4px 12px rgba(0, 123, 255, 0.4)",
417
+ cursor: "pointer",
418
+ display: "flex",
419
+ alignItems: "center",
420
+ justifyContent: "center",
421
+ transition: "all 0.3s ease",
422
+ zIndex: 1e3
423
+ };
424
+ var overlayStyle = {
425
+ position: "fixed",
426
+ top: 0,
427
+ left: 0,
428
+ right: 0,
429
+ bottom: 0,
430
+ backgroundColor: "rgba(0, 0, 0, 0.5)",
431
+ zIndex: 1001,
432
+ animation: "fadeIn 0.2s ease"
433
+ };
434
+ var panelStyle = {
435
+ position: "fixed",
436
+ top: "50%",
437
+ left: "50%",
438
+ transform: "translate(-50%, -50%)",
439
+ backgroundColor: "white",
440
+ borderRadius: "12px",
441
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
442
+ width: "90%",
443
+ maxWidth: "400px",
444
+ zIndex: 1002,
445
+ animation: "slideIn 0.3s ease"
446
+ };
447
+ var panelHeaderStyle = {
448
+ display: "flex",
449
+ justifyContent: "space-between",
450
+ alignItems: "center",
451
+ padding: "1.5rem",
452
+ borderBottom: "1px solid #e9ecef"
453
+ };
454
+ var panelTitleStyle = {
455
+ margin: 0,
456
+ fontSize: "1.25rem",
457
+ fontWeight: "600",
458
+ color: "#333"
459
+ };
460
+ var closeButtonStyle = {
461
+ background: "none",
462
+ border: "none",
463
+ fontSize: "1.5rem",
464
+ color: "#999",
465
+ cursor: "pointer",
466
+ padding: "0",
467
+ width: "32px",
468
+ height: "32px",
469
+ display: "flex",
470
+ alignItems: "center",
471
+ justifyContent: "center",
472
+ borderRadius: "4px",
473
+ transition: "background-color 0.2s"
474
+ };
475
+ var panelBodyStyle = {
476
+ padding: "1.5rem",
477
+ display: "flex",
478
+ flexDirection: "column",
479
+ gap: "1rem"
480
+ };
481
+ var infoItemStyle = {
482
+ display: "flex",
483
+ justifyContent: "space-between",
484
+ alignItems: "center",
485
+ padding: "0.75rem",
486
+ backgroundColor: "#f8f9fa",
487
+ borderRadius: "6px"
488
+ };
489
+ var keyDisplayContainerStyle = {
490
+ display: "flex",
491
+ alignItems: "center",
492
+ gap: "0.5rem"
493
+ };
494
+ var eyeButtonStyle = {
495
+ background: "none",
496
+ border: "none",
497
+ color: "#6c757d",
498
+ cursor: "pointer",
499
+ padding: "0.25rem",
500
+ display: "flex",
501
+ alignItems: "center",
502
+ justifyContent: "center",
503
+ borderRadius: "4px",
504
+ transition: "all 0.2s"
505
+ };
506
+ var infoLabelStyle = {
507
+ fontSize: "0.875rem",
508
+ color: "#6c757d",
509
+ fontWeight: "500"
510
+ };
511
+ var infoValueStyle = {
512
+ fontSize: "0.875rem",
513
+ color: "#333",
514
+ fontWeight: "500"
515
+ };
516
+ var levelBadgeStyle = (level) => {
517
+ const colors = {
518
+ ["none" /* None */]: { bg: "#6c757d", color: "white" },
519
+ ["guest" /* Guest */]: { bg: "#17a2b8", color: "white" },
520
+ ["vip" /* VIP */]: { bg: "#ffc107", color: "#333" },
521
+ ["super_vip" /* SuperVIP */]: { bg: "#dc3545", color: "white" }
522
+ };
523
+ const { bg, color } = colors[level] || colors["none" /* None */];
524
+ return {
525
+ padding: "0.25rem 0.75rem",
526
+ borderRadius: "12px",
527
+ backgroundColor: bg,
528
+ color,
529
+ fontSize: "0.75rem",
530
+ fontWeight: "600",
531
+ textTransform: "uppercase"
532
+ };
533
+ };
534
+ var panelFooterStyle = {
535
+ padding: "1.5rem",
536
+ borderTop: "1px solid #e9ecef"
537
+ };
538
+ var contactButtonStyle = {
539
+ width: "100%",
540
+ padding: "0.75rem",
541
+ fontSize: "1rem",
542
+ fontWeight: "500",
543
+ color: "white",
544
+ backgroundColor: "#28a745",
545
+ border: "none",
546
+ borderRadius: "6px",
547
+ cursor: "pointer",
548
+ transition: "background-color 0.2s",
549
+ marginBottom: "0.75rem"
550
+ };
551
+ var logoutButtonStyle = {
552
+ width: "100%",
553
+ padding: "0.75rem",
554
+ fontSize: "1rem",
555
+ fontWeight: "500",
556
+ color: "white",
557
+ backgroundColor: "#dc3545",
558
+ border: "none",
559
+ borderRadius: "6px",
560
+ cursor: "pointer",
561
+ transition: "background-color 0.2s"
562
+ };
563
+ var contactDialogStyle = {
564
+ position: "fixed",
565
+ top: "50%",
566
+ left: "50%",
567
+ transform: "translate(-50%, -50%)",
568
+ backgroundColor: "white",
569
+ borderRadius: "12px",
570
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2)",
571
+ width: "90%",
572
+ maxWidth: "400px",
573
+ zIndex: 1003,
574
+ animation: "slideIn 0.3s ease"
575
+ };
576
+ var contactDialogBodyStyle = {
577
+ padding: "1.5rem",
578
+ display: "flex",
579
+ flexDirection: "column",
580
+ gap: "1.5rem"
581
+ };
582
+ var contactInfoStyle = {
583
+ display: "flex",
584
+ flexDirection: "column",
585
+ gap: "1.5rem"
586
+ };
587
+ var wechatInfoStyle = {
588
+ display: "flex",
589
+ alignItems: "center",
590
+ gap: "0.75rem",
591
+ padding: "1rem",
592
+ backgroundColor: "#f8f9fa",
593
+ borderRadius: "8px",
594
+ flexWrap: "wrap"
595
+ };
596
+ var wechatLabelStyle = {
597
+ fontSize: "0.875rem",
598
+ color: "#6c757d",
599
+ fontWeight: "500"
600
+ };
601
+ var wechatValueStyle = {
602
+ fontSize: "1rem",
603
+ color: "#333",
604
+ fontWeight: "600",
605
+ flex: 1,
606
+ minWidth: "120px"
607
+ };
608
+ var copyButtonStyle = {
609
+ padding: "0.5rem 1rem",
610
+ fontSize: "0.875rem",
611
+ fontWeight: "500",
612
+ color: "#007bff",
613
+ backgroundColor: "white",
614
+ border: "1px solid #007bff",
615
+ borderRadius: "4px",
616
+ cursor: "pointer",
617
+ transition: "all 0.2s"
618
+ };
619
+ var qrCodeContainerStyle = {
620
+ display: "flex",
621
+ flexDirection: "column",
622
+ alignItems: "center",
623
+ gap: "1rem"
624
+ };
625
+ var qrCodeLabelStyle = {
626
+ fontSize: "0.875rem",
627
+ color: "#6c757d",
628
+ fontWeight: "500"
629
+ };
630
+ var qrCodePlaceholderStyle = {
631
+ display: "flex",
632
+ flexDirection: "column",
633
+ alignItems: "center",
634
+ gap: "0.5rem",
635
+ padding: "1rem",
636
+ backgroundColor: "#f8f9fa",
637
+ borderRadius: "8px",
638
+ width: "100%"
639
+ };
640
+ var qrCodeImageStyle = {
641
+ width: "200px",
642
+ height: "200px",
643
+ borderRadius: "8px",
644
+ border: "1px solid #e9ecef"
645
+ };
161
646
  var index_default = KeyGuard;
162
647
  export {
163
648
  KeyGuard,
649
+ Level,
164
650
  index_default as default
165
651
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "apps-key-guard",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "A React component for key-based access control with localStorage caching",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",