aki-info-detect 2.0.0 → 2.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 +192 -0
- package/dist/aki-info-detect.js +2 -2
- package/dist/aki-info-detect.umd.cjs +2 -2
- package/dist/index.html +1377 -0
- package/package.json +2 -2
package/dist/index.html
ADDED
|
@@ -0,0 +1,1377 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>aki-info-detect | Device Detection Library</title>
|
|
7
|
+
<meta name="description" content="Lightweight JavaScript library for detecting device, browser, hardware, and network information">
|
|
8
|
+
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><text y='.9em' font-size='90'>⚡</text></svg>">
|
|
9
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
10
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
11
|
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500&family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
|
12
|
+
<style>
|
|
13
|
+
:root {
|
|
14
|
+
--bg-primary: #050506;
|
|
15
|
+
--bg-secondary: #0c0c0e;
|
|
16
|
+
--bg-card: #111114;
|
|
17
|
+
--bg-hover: #18181c;
|
|
18
|
+
--border: #1e1e23;
|
|
19
|
+
--border-light: #2a2a32;
|
|
20
|
+
--text-primary: #f5f5f7;
|
|
21
|
+
--text-secondary: #8a8a93;
|
|
22
|
+
--text-muted: #55555d;
|
|
23
|
+
--accent: #fbbf24;
|
|
24
|
+
--accent-secondary: #f59e0b;
|
|
25
|
+
--accent-dim: #a16207;
|
|
26
|
+
--accent-glow: rgba(251, 191, 36, 0.08);
|
|
27
|
+
--success: #4ade80;
|
|
28
|
+
--error: #f87171;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
32
|
+
|
|
33
|
+
html { font-size: 15px; }
|
|
34
|
+
|
|
35
|
+
body {
|
|
36
|
+
font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
37
|
+
background: var(--bg-primary);
|
|
38
|
+
color: var(--text-primary);
|
|
39
|
+
min-height: 100vh;
|
|
40
|
+
line-height: 1.6;
|
|
41
|
+
-webkit-font-smoothing: antialiased;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.bg-gradient {
|
|
45
|
+
position: fixed;
|
|
46
|
+
inset: 0;
|
|
47
|
+
background:
|
|
48
|
+
radial-gradient(ellipse 80% 50% at 20% -10%, rgba(251, 191, 36, 0.08) 0%, transparent 50%),
|
|
49
|
+
radial-gradient(ellipse 60% 40% at 80% 110%, rgba(245, 158, 11, 0.06) 0%, transparent 50%);
|
|
50
|
+
pointer-events: none;
|
|
51
|
+
z-index: -2;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.bg-grid {
|
|
55
|
+
position: fixed;
|
|
56
|
+
inset: 0;
|
|
57
|
+
background-image:
|
|
58
|
+
linear-gradient(rgba(251, 191, 36, 0.02) 1px, transparent 1px),
|
|
59
|
+
linear-gradient(90deg, rgba(251, 191, 36, 0.02) 1px, transparent 1px);
|
|
60
|
+
background-size: 80px 80px;
|
|
61
|
+
pointer-events: none;
|
|
62
|
+
z-index: -1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
.container {
|
|
66
|
+
width: 100%;
|
|
67
|
+
max-width: 1400px;
|
|
68
|
+
margin: 0 auto;
|
|
69
|
+
padding: 28px 20px 50px;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Header */
|
|
73
|
+
header {
|
|
74
|
+
text-align: center;
|
|
75
|
+
margin-bottom: 28px;
|
|
76
|
+
padding-bottom: 24px;
|
|
77
|
+
border-bottom: 1px solid var(--border);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.logo {
|
|
81
|
+
display: inline-flex;
|
|
82
|
+
align-items: center;
|
|
83
|
+
gap: 14px;
|
|
84
|
+
margin-bottom: 10px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.logo-icon {
|
|
88
|
+
width: 44px;
|
|
89
|
+
height: 44px;
|
|
90
|
+
background: linear-gradient(135deg, var(--accent) 0%, var(--accent-dim) 100%);
|
|
91
|
+
border-radius: 12px;
|
|
92
|
+
display: flex;
|
|
93
|
+
align-items: center;
|
|
94
|
+
justify-content: center;
|
|
95
|
+
font-size: 22px;
|
|
96
|
+
box-shadow: 0 0 30px rgba(251, 191, 36, 0.2);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
h1 {
|
|
100
|
+
font-size: 1.8rem;
|
|
101
|
+
font-weight: 600;
|
|
102
|
+
letter-spacing: -0.03em;
|
|
103
|
+
background: linear-gradient(135deg, var(--text-primary) 0%, var(--text-secondary) 100%);
|
|
104
|
+
-webkit-background-clip: text;
|
|
105
|
+
-webkit-text-fill-color: transparent;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.subtitle {
|
|
109
|
+
color: var(--text-secondary);
|
|
110
|
+
font-size: 1rem;
|
|
111
|
+
font-weight: 400;
|
|
112
|
+
margin-top: 4px;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.header-meta {
|
|
116
|
+
display: flex;
|
|
117
|
+
gap: 16px;
|
|
118
|
+
justify-content: center;
|
|
119
|
+
align-items: center;
|
|
120
|
+
margin-top: 16px;
|
|
121
|
+
flex-wrap: wrap;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.badges {
|
|
125
|
+
display: flex;
|
|
126
|
+
gap: 6px;
|
|
127
|
+
flex-wrap: wrap;
|
|
128
|
+
}
|
|
129
|
+
.badges img { height: 20px; opacity: 0.7; transition: opacity 0.2s; }
|
|
130
|
+
.badges a:hover img { opacity: 1; }
|
|
131
|
+
|
|
132
|
+
.install-box {
|
|
133
|
+
background: var(--bg-card);
|
|
134
|
+
border: 1px solid var(--border);
|
|
135
|
+
border-radius: 8px;
|
|
136
|
+
padding: 8px 14px;
|
|
137
|
+
display: flex;
|
|
138
|
+
align-items: center;
|
|
139
|
+
gap: 10px;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.install-box code {
|
|
143
|
+
font-family: 'JetBrains Mono', monospace;
|
|
144
|
+
font-size: 0.9rem;
|
|
145
|
+
color: var(--accent);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.install-box button {
|
|
149
|
+
background: transparent;
|
|
150
|
+
border: 1px solid var(--border);
|
|
151
|
+
color: var(--text-muted);
|
|
152
|
+
padding: 5px 11px;
|
|
153
|
+
border-radius: 5px;
|
|
154
|
+
cursor: pointer;
|
|
155
|
+
font-size: 0.8rem;
|
|
156
|
+
transition: all 0.2s;
|
|
157
|
+
}
|
|
158
|
+
.install-box button:hover {
|
|
159
|
+
border-color: var(--accent);
|
|
160
|
+
color: var(--accent);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/* Tabs */
|
|
164
|
+
.tabs {
|
|
165
|
+
display: flex;
|
|
166
|
+
gap: 4px;
|
|
167
|
+
border-bottom: 1px solid var(--border);
|
|
168
|
+
margin-bottom: 24px;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
.tab {
|
|
172
|
+
background: transparent;
|
|
173
|
+
border: none;
|
|
174
|
+
color: var(--text-secondary);
|
|
175
|
+
padding: 10px 20px;
|
|
176
|
+
cursor: pointer;
|
|
177
|
+
font-size: 0.95rem;
|
|
178
|
+
font-weight: 500;
|
|
179
|
+
transition: all 0.2s;
|
|
180
|
+
border-bottom: 2px solid transparent;
|
|
181
|
+
font-family: inherit;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.tab:hover { color: var(--text-primary); }
|
|
185
|
+
.tab.active {
|
|
186
|
+
color: var(--accent);
|
|
187
|
+
border-bottom-color: var(--accent);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
.tab-content {
|
|
191
|
+
display: none;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
.tab-content.active {
|
|
195
|
+
display: block;
|
|
196
|
+
animation: fadeIn 0.3s ease;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@keyframes fadeIn {
|
|
200
|
+
from { opacity: 0; transform: translateY(10px); }
|
|
201
|
+
to { opacity: 1; transform: translateY(0); }
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* Grid (Demo tab) */
|
|
205
|
+
.grid {
|
|
206
|
+
display: grid;
|
|
207
|
+
grid-template-columns: repeat(1, 1fr);
|
|
208
|
+
gap: 14px;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
@media (min-width: 640px) {
|
|
212
|
+
.grid { grid-template-columns: repeat(2, 1fr); }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@media (min-width: 1024px) {
|
|
216
|
+
.grid { grid-template-columns: repeat(3, 1fr); }
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/* Cards */
|
|
220
|
+
.card {
|
|
221
|
+
background: var(--bg-card);
|
|
222
|
+
border: 1px solid var(--border);
|
|
223
|
+
border-radius: 10px;
|
|
224
|
+
overflow: hidden;
|
|
225
|
+
transition: all 0.25s ease;
|
|
226
|
+
position: relative;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.card::before {
|
|
230
|
+
content: '';
|
|
231
|
+
position: absolute;
|
|
232
|
+
top: 0;
|
|
233
|
+
left: 0;
|
|
234
|
+
right: 0;
|
|
235
|
+
height: 1px;
|
|
236
|
+
background: linear-gradient(90deg, transparent, rgba(251, 191, 36, 0.3), transparent);
|
|
237
|
+
opacity: 0;
|
|
238
|
+
transition: opacity 0.25s;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
.card:hover {
|
|
242
|
+
border-color: var(--border-light);
|
|
243
|
+
transform: translateY(-2px);
|
|
244
|
+
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.card:hover::before { opacity: 1; }
|
|
248
|
+
|
|
249
|
+
.card-header {
|
|
250
|
+
padding: 14px 16px 12px;
|
|
251
|
+
border-bottom: 1px solid var(--border);
|
|
252
|
+
display: flex;
|
|
253
|
+
align-items: center;
|
|
254
|
+
gap: 11px;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.card-icon {
|
|
258
|
+
width: 30px;
|
|
259
|
+
height: 30px;
|
|
260
|
+
background: var(--accent-glow);
|
|
261
|
+
border: 1px solid rgba(251, 191, 36, 0.2);
|
|
262
|
+
border-radius: 7px;
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
justify-content: center;
|
|
266
|
+
font-size: 14px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
.card-title {
|
|
270
|
+
font-size: 0.95rem;
|
|
271
|
+
font-weight: 500;
|
|
272
|
+
color: var(--text-primary);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.card-body { padding: 4px 0; }
|
|
276
|
+
|
|
277
|
+
.row {
|
|
278
|
+
display: flex;
|
|
279
|
+
justify-content: space-between;
|
|
280
|
+
align-items: center;
|
|
281
|
+
padding: 9px 16px;
|
|
282
|
+
border-bottom: 1px solid var(--border);
|
|
283
|
+
transition: background 0.15s;
|
|
284
|
+
}
|
|
285
|
+
.row:last-child { border-bottom: none; }
|
|
286
|
+
.row:hover { background: var(--bg-hover); }
|
|
287
|
+
|
|
288
|
+
.label {
|
|
289
|
+
font-size: 0.9rem;
|
|
290
|
+
color: var(--text-secondary);
|
|
291
|
+
font-weight: 400;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.value {
|
|
295
|
+
font-family: 'JetBrains Mono', monospace;
|
|
296
|
+
font-size: 0.85rem;
|
|
297
|
+
color: var(--text-primary);
|
|
298
|
+
text-align: right;
|
|
299
|
+
max-width: 60%;
|
|
300
|
+
word-break: break-word;
|
|
301
|
+
}
|
|
302
|
+
.value.loading { color: var(--accent); }
|
|
303
|
+
.value.error { color: var(--error); }
|
|
304
|
+
.value.success { color: var(--success); }
|
|
305
|
+
.value.muted { color: var(--text-muted); }
|
|
306
|
+
|
|
307
|
+
.actions {
|
|
308
|
+
padding: 12px 16px;
|
|
309
|
+
display: flex;
|
|
310
|
+
gap: 8px;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
button {
|
|
314
|
+
background: transparent;
|
|
315
|
+
border: 1px solid var(--border);
|
|
316
|
+
color: var(--text-secondary);
|
|
317
|
+
padding: 8px 14px;
|
|
318
|
+
border-radius: 6px;
|
|
319
|
+
cursor: pointer;
|
|
320
|
+
font-size: 0.85rem;
|
|
321
|
+
font-weight: 500;
|
|
322
|
+
transition: all 0.2s;
|
|
323
|
+
font-family: inherit;
|
|
324
|
+
}
|
|
325
|
+
button:hover {
|
|
326
|
+
border-color: var(--accent);
|
|
327
|
+
color: var(--accent);
|
|
328
|
+
background: var(--accent-glow);
|
|
329
|
+
}
|
|
330
|
+
button:active { transform: scale(0.98); }
|
|
331
|
+
|
|
332
|
+
.output {
|
|
333
|
+
grid-column: 1 / -1;
|
|
334
|
+
background: var(--bg-card);
|
|
335
|
+
border: 1px solid var(--border);
|
|
336
|
+
border-radius: 10px;
|
|
337
|
+
margin-top: 10px;
|
|
338
|
+
overflow: hidden;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.output-header {
|
|
342
|
+
padding: 12px 16px;
|
|
343
|
+
border-bottom: 1px solid var(--border);
|
|
344
|
+
display: flex;
|
|
345
|
+
align-items: center;
|
|
346
|
+
justify-content: space-between;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.output-title {
|
|
350
|
+
font-size: 0.9rem;
|
|
351
|
+
font-weight: 500;
|
|
352
|
+
color: var(--text-secondary);
|
|
353
|
+
display: flex;
|
|
354
|
+
align-items: center;
|
|
355
|
+
gap: 8px;
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
.output-body {
|
|
359
|
+
padding: 14px 16px;
|
|
360
|
+
max-height: 280px;
|
|
361
|
+
overflow: auto;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
pre {
|
|
365
|
+
font-family: 'JetBrains Mono', monospace;
|
|
366
|
+
font-size: 0.8rem;
|
|
367
|
+
line-height: 1.7;
|
|
368
|
+
color: var(--text-muted);
|
|
369
|
+
white-space: pre-wrap;
|
|
370
|
+
word-break: break-word;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/* Documentation styles */
|
|
374
|
+
.docs-content {
|
|
375
|
+
max-width: 900px;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
.docs-content h2 {
|
|
379
|
+
font-size: 1.5rem;
|
|
380
|
+
margin-bottom: 12px;
|
|
381
|
+
color: var(--accent);
|
|
382
|
+
font-weight: 600;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
.docs-content h3 {
|
|
386
|
+
font-size: 1.15rem;
|
|
387
|
+
margin: 20px 0 10px;
|
|
388
|
+
color: var(--text-primary);
|
|
389
|
+
font-weight: 500;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
.docs-content p {
|
|
393
|
+
margin-bottom: 12px;
|
|
394
|
+
color: var(--text-secondary);
|
|
395
|
+
font-size: 0.95rem;
|
|
396
|
+
line-height: 1.7;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
.docs-content ul {
|
|
400
|
+
margin: 10px 0 20px 20px;
|
|
401
|
+
color: var(--text-secondary);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
.docs-content li {
|
|
405
|
+
margin: 6px 0;
|
|
406
|
+
font-size: 0.95rem;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
.docs-content code {
|
|
410
|
+
background: var(--bg-card);
|
|
411
|
+
border: 1px solid var(--border);
|
|
412
|
+
padding: 2px 6px;
|
|
413
|
+
border-radius: 4px;
|
|
414
|
+
font-family: 'JetBrains Mono', monospace;
|
|
415
|
+
font-size: 0.85rem;
|
|
416
|
+
color: var(--accent);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.docs-content pre {
|
|
420
|
+
background: var(--bg-card);
|
|
421
|
+
border: 1px solid var(--border);
|
|
422
|
+
padding: 14px;
|
|
423
|
+
border-radius: 8px;
|
|
424
|
+
margin: 12px 0 20px;
|
|
425
|
+
overflow-x: auto;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
.docs-content pre code {
|
|
429
|
+
background: none;
|
|
430
|
+
border: none;
|
|
431
|
+
padding: 0;
|
|
432
|
+
color: var(--text-muted);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
.note-box {
|
|
436
|
+
background: linear-gradient(135deg, rgba(251, 191, 36, 0.04) 0%, rgba(251, 191, 36, 0.02) 100%);
|
|
437
|
+
border: 1px solid rgba(251, 191, 36, 0.15);
|
|
438
|
+
border-radius: 8px;
|
|
439
|
+
padding: 14px 16px;
|
|
440
|
+
margin: 16px 0;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
.note-box strong {
|
|
444
|
+
color: var(--accent);
|
|
445
|
+
font-size: 0.9rem;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.feature-grid {
|
|
449
|
+
display: grid;
|
|
450
|
+
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
451
|
+
gap: 12px;
|
|
452
|
+
margin: 20px 0;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
.feature-item {
|
|
456
|
+
background: var(--bg-card);
|
|
457
|
+
border: 1px solid var(--border);
|
|
458
|
+
border-radius: 8px;
|
|
459
|
+
padding: 12px;
|
|
460
|
+
transition: border-color 0.2s;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
.feature-item:hover { border-color: var(--border-light); }
|
|
464
|
+
|
|
465
|
+
.feature-item strong {
|
|
466
|
+
color: var(--accent);
|
|
467
|
+
font-size: 0.9rem;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/* Footer */
|
|
471
|
+
footer {
|
|
472
|
+
text-align: center;
|
|
473
|
+
margin-top: 32px;
|
|
474
|
+
padding-top: 20px;
|
|
475
|
+
border-top: 1px solid var(--border);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
.footer-links {
|
|
479
|
+
display: flex;
|
|
480
|
+
gap: 24px;
|
|
481
|
+
justify-content: center;
|
|
482
|
+
margin-bottom: 10px;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
.footer-links a {
|
|
486
|
+
color: var(--text-secondary);
|
|
487
|
+
text-decoration: none;
|
|
488
|
+
font-size: 0.9rem;
|
|
489
|
+
font-weight: 500;
|
|
490
|
+
transition: color 0.2s;
|
|
491
|
+
display: flex;
|
|
492
|
+
align-items: center;
|
|
493
|
+
gap: 6px;
|
|
494
|
+
}
|
|
495
|
+
.footer-links a:hover { color: var(--accent); }
|
|
496
|
+
|
|
497
|
+
.footer-credit {
|
|
498
|
+
font-size: 0.85rem;
|
|
499
|
+
color: var(--text-muted);
|
|
500
|
+
}
|
|
501
|
+
.footer-credit a { color: var(--accent); text-decoration: none; }
|
|
502
|
+
|
|
503
|
+
::-webkit-scrollbar { width: 5px; height: 5px; }
|
|
504
|
+
::-webkit-scrollbar-track { background: transparent; }
|
|
505
|
+
::-webkit-scrollbar-thumb { background: var(--border); border-radius: 3px; }
|
|
506
|
+
::-webkit-scrollbar-thumb:hover { background: var(--border-light); }
|
|
507
|
+
|
|
508
|
+
@media (max-width: 639px) {
|
|
509
|
+
html { font-size: 14px; }
|
|
510
|
+
.container { padding: 20px 14px 40px; }
|
|
511
|
+
header { margin-bottom: 20px; padding-bottom: 20px; }
|
|
512
|
+
h1 { font-size: 1.5rem; }
|
|
513
|
+
.header-meta { flex-direction: column; gap: 12px; }
|
|
514
|
+
.tabs { overflow-x: auto; }
|
|
515
|
+
.tab { padding: 10px 16px; font-size: 0.9rem; }
|
|
516
|
+
}
|
|
517
|
+
</style>
|
|
518
|
+
</head>
|
|
519
|
+
<body>
|
|
520
|
+
<div class="bg-gradient"></div>
|
|
521
|
+
<div class="bg-grid"></div>
|
|
522
|
+
|
|
523
|
+
<div class="container">
|
|
524
|
+
<header>
|
|
525
|
+
<div class="logo">
|
|
526
|
+
<div class="logo-icon">⚡</div>
|
|
527
|
+
<h1>aki-info-detect</h1>
|
|
528
|
+
</div>
|
|
529
|
+
<p class="subtitle">Lightweight browser, device & network detection library</p>
|
|
530
|
+
|
|
531
|
+
<div class="header-meta">
|
|
532
|
+
<div class="install-box">
|
|
533
|
+
<code>npm i aki-info-detect</code>
|
|
534
|
+
<button onclick="copyInstall()">Copy</button>
|
|
535
|
+
</div>
|
|
536
|
+
<div class="badges">
|
|
537
|
+
<a href="https://www.npmjs.com/package/aki-info-detect"><img src="https://img.shields.io/npm/v/aki-info-detect?color=f59e0b&label=npm&style=flat-square" alt="npm"></a>
|
|
538
|
+
<a href="https://bundlephobia.com/package/aki-info-detect"><img src="https://img.shields.io/bundlephobia/minzip/aki-info-detect?color=22c55e&label=gzip&style=flat-square" alt="size"></a>
|
|
539
|
+
<a href="https://github.com/lacvietanh/akiInfoDetect.js"><img src="https://img.shields.io/github/stars/lacvietanh/akiInfoDetect.js?style=flat-square&color=8b5cf6" alt="stars"></a>
|
|
540
|
+
</div>
|
|
541
|
+
</div>
|
|
542
|
+
</header>
|
|
543
|
+
|
|
544
|
+
<!-- Tabs -->
|
|
545
|
+
<div class="tabs">
|
|
546
|
+
<button class="tab active" data-tab="intro">Intro</button>
|
|
547
|
+
<button class="tab" data-tab="demo">Demo</button>
|
|
548
|
+
<button class="tab" data-tab="docs">Documentation</button>
|
|
549
|
+
<button class="tab" data-tab="api">API Reference</button>
|
|
550
|
+
</div>
|
|
551
|
+
|
|
552
|
+
<!-- Intro Tab -->
|
|
553
|
+
<div class="tab-content active" id="intro">
|
|
554
|
+
<div class="docs-content">
|
|
555
|
+
<h2>Welcome to aki-info-detect</h2>
|
|
556
|
+
<p>
|
|
557
|
+
<strong>aki-info-detect</strong> is a modern, lightweight JavaScript library that provides comprehensive device, browser, and system information detection for web applications. Built with performance and developer experience in mind, it leverages modern browser APIs including the Client Hints API for accurate hardware detection while maintaining a minimal footprint (~3.8 kB gzipped).
|
|
558
|
+
</p>
|
|
559
|
+
<p>
|
|
560
|
+
Whether you need to customize user experiences based on device capabilities, gather analytics data, or implement platform-specific features, aki-info-detect provides a unified, easy-to-use API that works seamlessly across all modern browsers.
|
|
561
|
+
</p>
|
|
562
|
+
|
|
563
|
+
<div class="note-box">
|
|
564
|
+
<strong>⚡ Quick Start:</strong> Install with <code>npm install aki-info-detect</code> and start detecting in seconds!
|
|
565
|
+
</div>
|
|
566
|
+
|
|
567
|
+
<h2>Key Benefits</h2>
|
|
568
|
+
<div class="feature-grid">
|
|
569
|
+
<div class="feature-item">
|
|
570
|
+
<strong>🎯 Comprehensive Detection</strong>
|
|
571
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Browser, OS, CPU, GPU, RAM, network, battery, and more from a single library</p>
|
|
572
|
+
</div>
|
|
573
|
+
<div class="feature-item">
|
|
574
|
+
<strong>⚡ Performance-First</strong>
|
|
575
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Minimal bundle size with tree-shakeable exports—import only what you need</p>
|
|
576
|
+
</div>
|
|
577
|
+
<div class="feature-item">
|
|
578
|
+
<strong>🔮 Future-Proof</strong>
|
|
579
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Built on modern Web APIs with graceful fallbacks for older browsers</p>
|
|
580
|
+
</div>
|
|
581
|
+
<div class="feature-item">
|
|
582
|
+
<strong>💪 Apple Silicon Ready</strong>
|
|
583
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Advanced detection for Apple M-series chips (M1, M2, M3, M4, and beyond)</p>
|
|
584
|
+
</div>
|
|
585
|
+
<div class="feature-item">
|
|
586
|
+
<strong>🔒 Privacy-Conscious</strong>
|
|
587
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Implements caching for network requests to minimize external API calls</p>
|
|
588
|
+
</div>
|
|
589
|
+
<div class="feature-item">
|
|
590
|
+
<strong>📦 Zero Dependencies</strong>
|
|
591
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">No external runtime dependencies—just pure, optimized JavaScript</p>
|
|
592
|
+
</div>
|
|
593
|
+
</div>
|
|
594
|
+
|
|
595
|
+
<h2>Common Use Cases</h2>
|
|
596
|
+
|
|
597
|
+
<h3>1. Adaptive User Interfaces</h3>
|
|
598
|
+
<p>Dynamically adjust your UI based on device capabilities and screen properties:</p>
|
|
599
|
+
<pre><code>const info = await akiInfoDetect();
|
|
600
|
+
if (info.isMobile) {
|
|
601
|
+
loadMobileUI();
|
|
602
|
+
} else if (info.RAM < 4) {
|
|
603
|
+
enableLowMemoryMode();
|
|
604
|
+
}</code></pre>
|
|
605
|
+
|
|
606
|
+
<h3>2. Analytics & User Insights</h3>
|
|
607
|
+
<p>Gather detailed technical data to understand your user base:</p>
|
|
608
|
+
<pre><code>const info = await akiInfoDetect();
|
|
609
|
+
analytics.track('page_view', {
|
|
610
|
+
browser: info.browser,
|
|
611
|
+
os: info.os.string,
|
|
612
|
+
device: info.isMobile ? 'mobile' : 'desktop',
|
|
613
|
+
gpu: info.GPU
|
|
614
|
+
});</code></pre>
|
|
615
|
+
|
|
616
|
+
<h3>3. Feature Detection & Progressive Enhancement</h3>
|
|
617
|
+
<p>Enable or disable features based on browser capabilities:</p>
|
|
618
|
+
<pre><code>const info = await akiInfoDetect();
|
|
619
|
+
const chromeVersion = parseInt(info.browser.split(' ')[1]);
|
|
620
|
+
if (info.browser.includes('Chrome') && chromeVersion >= 90) {
|
|
621
|
+
enableAdvancedFeatures();
|
|
622
|
+
}</code></pre>
|
|
623
|
+
|
|
624
|
+
<h3>4. Platform-Specific Optimization</h3>
|
|
625
|
+
<p>Optimize content delivery based on hardware capabilities:</p>
|
|
626
|
+
<pre><code>const info = await akiInfoDetect();
|
|
627
|
+
if (info.CPU === 'Apple Silicon') {
|
|
628
|
+
loadWebPImages();
|
|
629
|
+
} else if (info.GPU.includes('NVIDIA')) {
|
|
630
|
+
enableHardwareAcceleration();
|
|
631
|
+
}</code></pre>
|
|
632
|
+
|
|
633
|
+
<h3>5. Network-Aware Loading</h3>
|
|
634
|
+
<p>Adapt content loading strategies based on connection quality:</p>
|
|
635
|
+
<pre><code>const info = await akiInfoDetect();
|
|
636
|
+
const conn = info.getConnection();
|
|
637
|
+
if (conn.type === '4g' && conn.downlink > 5) {
|
|
638
|
+
loadHDContent();
|
|
639
|
+
} else {
|
|
640
|
+
loadCompressedContent();
|
|
641
|
+
}</code></pre>
|
|
642
|
+
|
|
643
|
+
<h2>Comparison with Similar Libraries</h2>
|
|
644
|
+
<p>aki-info-detect stands out from other detection libraries with its modern approach and comprehensive feature set:</p>
|
|
645
|
+
|
|
646
|
+
<div style="overflow-x: auto; margin: 20px 0;">
|
|
647
|
+
<table style="width: 100%; border-collapse: collapse; font-size: 0.9rem;">
|
|
648
|
+
<thead>
|
|
649
|
+
<tr style="border-bottom: 2px solid var(--border);">
|
|
650
|
+
<th style="text-align: left; padding: 10px; color: var(--text-primary);">Feature</th>
|
|
651
|
+
<th style="text-align: center; padding: 10px; color: var(--accent);">aki-info-detect</th>
|
|
652
|
+
<th style="text-align: center; padding: 10px; color: var(--text-secondary);">Platform.js</th>
|
|
653
|
+
<th style="text-align: center; padding: 10px; color: var(--text-secondary);">UA-Parser.js</th>
|
|
654
|
+
<th style="text-align: center; padding: 10px; color: var(--text-secondary);">Detect.js</th>
|
|
655
|
+
</tr>
|
|
656
|
+
</thead>
|
|
657
|
+
<tbody>
|
|
658
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
659
|
+
<td style="padding: 10px; color: var(--text-secondary);">Bundle Size (gzipped)</td>
|
|
660
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">~3.8 kB</td>
|
|
661
|
+
<td style="padding: 10px; text-align: center;">~2.5 kB</td>
|
|
662
|
+
<td style="padding: 10px; text-align: center;">~9 kB</td>
|
|
663
|
+
<td style="padding: 10px; text-align: center;">Varies</td>
|
|
664
|
+
</tr>
|
|
665
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
666
|
+
<td style="padding: 10px; color: var(--text-secondary);">Client Hints API</td>
|
|
667
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
668
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
669
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
670
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
671
|
+
</tr>
|
|
672
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
673
|
+
<td style="padding: 10px; color: var(--text-secondary);">GPU Detection</td>
|
|
674
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
675
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
676
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
677
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
678
|
+
</tr>
|
|
679
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
680
|
+
<td style="padding: 10px; color: var(--text-secondary);">Apple Silicon Detection</td>
|
|
681
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅ (M1-MX)</td>
|
|
682
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
683
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
684
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
685
|
+
</tr>
|
|
686
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
687
|
+
<td style="padding: 10px; color: var(--text-secondary);">Network Info (IP/ISP)</td>
|
|
688
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
689
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
690
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
691
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
692
|
+
</tr>
|
|
693
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
694
|
+
<td style="padding: 10px; color: var(--text-secondary);">Battery & Geolocation</td>
|
|
695
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
696
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
697
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
698
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
699
|
+
</tr>
|
|
700
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
701
|
+
<td style="padding: 10px; color: var(--text-secondary);">Tree-shakeable</td>
|
|
702
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
703
|
+
<td style="padding: 10px; text-align: center; color: var(--text-muted);">⚠️</td>
|
|
704
|
+
<td style="padding: 10px; text-align: center; color: var(--text-muted);">⚠️</td>
|
|
705
|
+
<td style="padding: 10px; text-align: center; color: var(--text-muted);">⚠️</td>
|
|
706
|
+
</tr>
|
|
707
|
+
<tr style="border-bottom: 1px solid var(--border);">
|
|
708
|
+
<td style="padding: 10px; color: var(--text-secondary);">TypeScript Support</td>
|
|
709
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅ Full</td>
|
|
710
|
+
<td style="padding: 10px; text-align: center; color: var(--text-muted);">⚠️ Community</td>
|
|
711
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
712
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌</td>
|
|
713
|
+
</tr>
|
|
714
|
+
<tr>
|
|
715
|
+
<td style="padding: 10px; color: var(--text-secondary);">Active Maintenance</td>
|
|
716
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
717
|
+
<td style="padding: 10px; text-align: center; color: var(--text-muted);">⚠️</td>
|
|
718
|
+
<td style="padding: 10px; text-align: center; color: var(--success);">✅</td>
|
|
719
|
+
<td style="padding: 10px; text-align: center; color: var(--error);">❌ Archived</td>
|
|
720
|
+
</tr>
|
|
721
|
+
</tbody>
|
|
722
|
+
</table>
|
|
723
|
+
</div>
|
|
724
|
+
|
|
725
|
+
<h3>Key Differentiators</h3>
|
|
726
|
+
<ul>
|
|
727
|
+
<li><strong>vs. Platform.js:</strong> Modern evolution with Client Hints API support, hardware detection (GPU, RAM), and network capabilities</li>
|
|
728
|
+
<li><strong>vs. UA-Parser.js:</strong> Lighter bundle while providing more comprehensive information including hardware and network detection</li>
|
|
729
|
+
<li><strong>vs. Detect.js:</strong> Active maintenance (Detect.js is archived), smaller focused API, modern Web API integration</li>
|
|
730
|
+
</ul>
|
|
731
|
+
|
|
732
|
+
<h2>Frequently Asked Questions</h2>
|
|
733
|
+
|
|
734
|
+
<h3>General Questions</h3>
|
|
735
|
+
|
|
736
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
737
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">What browsers does aki-info-detect support?</summary>
|
|
738
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
739
|
+
All modern browsers with ES2020+ support: Chrome/Edge 89+, Firefox 88+, Safari 14+, Opera 76+. Client Hints features work best in Chromium-based browsers.
|
|
740
|
+
</p>
|
|
741
|
+
</details>
|
|
742
|
+
|
|
743
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
744
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Does it work in Node.js or server-side environments?</summary>
|
|
745
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
746
|
+
No, aki-info-detect is specifically designed for browser environments. It relies on browser APIs like <code>navigator</code>, <code>screen</code>, and Web APIs that are not available in Node.js.
|
|
747
|
+
</p>
|
|
748
|
+
</details>
|
|
749
|
+
|
|
750
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
751
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">How accurate is the detection?</summary>
|
|
752
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
753
|
+
Very accurate for modern browsers that support Client Hints API. For browsers without Client Hints, it falls back to user agent parsing which is still reliable but less detailed. GPU and CPU detection is most accurate in Chromium-based browsers.
|
|
754
|
+
</p>
|
|
755
|
+
</details>
|
|
756
|
+
|
|
757
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
758
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Is user agent string spoofing a concern?</summary>
|
|
759
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
760
|
+
While user agents can be spoofed, Client Hints API provides more reliable detection. For critical functionality, always combine with feature detection rather than relying solely on browser/platform detection.
|
|
761
|
+
</p>
|
|
762
|
+
</details>
|
|
763
|
+
|
|
764
|
+
<h3>Privacy & Security</h3>
|
|
765
|
+
|
|
766
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
767
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Does aki-info-detect collect or transmit user data?</summary>
|
|
768
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
769
|
+
No. The library only detects information locally in the browser. The optional network info feature (<code>getNetworkInfo()</code>) makes a request to a public IP API, but this is only triggered when you explicitly call that method.
|
|
770
|
+
</p>
|
|
771
|
+
</details>
|
|
772
|
+
|
|
773
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
774
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">What about user privacy?</summary>
|
|
775
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
776
|
+
aki-info-detect is privacy-conscious. Network requests are cached for 1 hour to minimize external API calls, and all detection happens client-side. No data is sent to our servers.
|
|
777
|
+
</p>
|
|
778
|
+
</details>
|
|
779
|
+
|
|
780
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
781
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Is it GDPR compliant?</summary>
|
|
782
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
783
|
+
Detection of browser/device information is generally considered functional data necessary for website operation. However, always review your local regulations and privacy policies, especially when using geolocation or storing detected data.
|
|
784
|
+
</p>
|
|
785
|
+
</details>
|
|
786
|
+
|
|
787
|
+
<h3>Technical Questions</h3>
|
|
788
|
+
|
|
789
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
790
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Why do I need to configure server headers?</summary>
|
|
791
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
792
|
+
The Client Hints API requires the server to explicitly request detailed information via <code>Accept-CH</code> headers. Without these headers, browsers will only provide basic user agent data. This is a browser security feature designed to enhance user privacy.
|
|
793
|
+
</p>
|
|
794
|
+
</details>
|
|
795
|
+
|
|
796
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
797
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Can I use it with React, Vue, or other frameworks?</summary>
|
|
798
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
799
|
+
Absolutely! aki-info-detect is framework-agnostic. Check the Documentation tab for React Hook and Vue Composable examples.
|
|
800
|
+
</p>
|
|
801
|
+
</details>
|
|
802
|
+
|
|
803
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
804
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">How do I reduce bundle size further?</summary>
|
|
805
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
806
|
+
Use tree-shakeable imports to include only the functions you need:
|
|
807
|
+
<pre style="margin-top: 8px;"><code>import { detectBrowser, detectOS } from 'aki-info-detect';</code></pre>
|
|
808
|
+
</p>
|
|
809
|
+
</details>
|
|
810
|
+
|
|
811
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
812
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Does it support TypeScript?</summary>
|
|
813
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
814
|
+
Yes, full TypeScript declarations are included in the package.
|
|
815
|
+
</p>
|
|
816
|
+
</details>
|
|
817
|
+
|
|
818
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
819
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">How often is the network information cached?</summary>
|
|
820
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
821
|
+
Network info (IP, ISP, country) is cached for 1 hour by default. You can force a refresh by passing <code>true</code> to <code>getNetworkInfo(true)</code>.
|
|
822
|
+
</p>
|
|
823
|
+
</details>
|
|
824
|
+
|
|
825
|
+
<h3>Troubleshooting</h3>
|
|
826
|
+
|
|
827
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
828
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Why am I getting generic hardware info?</summary>
|
|
829
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
830
|
+
Make sure your server is configured to send the required <code>Accept-CH</code> headers. Without these headers, detailed Client Hints data won't be available. Check the Documentation tab for server configuration examples.
|
|
831
|
+
</p>
|
|
832
|
+
</details>
|
|
833
|
+
|
|
834
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
835
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">Why is GPU detection returning "Unknown"?</summary>
|
|
836
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
837
|
+
GPU detection works best in Chromium browsers with Client Hints. Safari and Firefox have limited support. Also, some browsers may restrict this information for privacy reasons.
|
|
838
|
+
</p>
|
|
839
|
+
</details>
|
|
840
|
+
|
|
841
|
+
<details style="margin: 10px 0; padding: 12px; background: var(--bg-card); border: 1px solid var(--border); border-radius: 8px; cursor: pointer;">
|
|
842
|
+
<summary style="font-weight: 500; color: var(--text-primary); cursor: pointer;">The library says "Unknown" for many fields. What's wrong?</summary>
|
|
843
|
+
<p style="margin-top: 10px; color: var(--text-secondary);">
|
|
844
|
+
Check browser console for errors, ensure you're using a supported browser version, and verify that your server is sending proper Client Hints headers (see the Documentation tab for Server Configuration).
|
|
845
|
+
</p>
|
|
846
|
+
</details>
|
|
847
|
+
|
|
848
|
+
<div class="note-box" style="margin-top: 24px;">
|
|
849
|
+
<strong>🚀 Ready to get started?</strong> Check out the <strong>Demo</strong> tab to see the library in action, or visit the <strong>Documentation</strong> tab for installation instructions and code examples.
|
|
850
|
+
</div>
|
|
851
|
+
</div>
|
|
852
|
+
</div>
|
|
853
|
+
|
|
854
|
+
<!-- Demo Tab -->
|
|
855
|
+
<div class="tab-content" id="demo">
|
|
856
|
+
<div class="note-box">
|
|
857
|
+
<strong>⚠️ Server Headers Required:</strong> For deep hardware detection via Client Hints API, configure:
|
|
858
|
+
<code>Accept-CH: Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch, Sec-CH-UA-Bitness</code>
|
|
859
|
+
</div>
|
|
860
|
+
|
|
861
|
+
<div class="grid">
|
|
862
|
+
<!-- Browser -->
|
|
863
|
+
<div class="card">
|
|
864
|
+
<div class="card-header">
|
|
865
|
+
<div class="card-icon">🌐</div>
|
|
866
|
+
<div class="card-title">Browser</div>
|
|
867
|
+
</div>
|
|
868
|
+
<div class="card-body">
|
|
869
|
+
<div class="row"><span class="label">Name</span><span class="value" id="browser">—</span></div>
|
|
870
|
+
<div class="row"><span class="label">Product</span><span class="value" id="product">—</span></div>
|
|
871
|
+
<div class="row"><span class="label">Mobile</span><span class="value" id="isMobile">—</span></div>
|
|
872
|
+
<div class="row"><span class="label">Language</span><span class="value" id="language">—</span></div>
|
|
873
|
+
</div>
|
|
874
|
+
</div>
|
|
875
|
+
|
|
876
|
+
<!-- OS -->
|
|
877
|
+
<div class="card">
|
|
878
|
+
<div class="card-header">
|
|
879
|
+
<div class="card-icon">💻</div>
|
|
880
|
+
<div class="card-title">Operating System</div>
|
|
881
|
+
</div>
|
|
882
|
+
<div class="card-body">
|
|
883
|
+
<div class="row"><span class="label">Name</span><span class="value" id="osName">—</span></div>
|
|
884
|
+
<div class="row"><span class="label">Version</span><span class="value" id="osVersion">—</span></div>
|
|
885
|
+
<div class="row"><span class="label">Platform</span><span class="value" id="osString">—</span></div>
|
|
886
|
+
</div>
|
|
887
|
+
</div>
|
|
888
|
+
|
|
889
|
+
<!-- CPU -->
|
|
890
|
+
<div class="card">
|
|
891
|
+
<div class="card-header">
|
|
892
|
+
<div class="card-icon">⚙️</div>
|
|
893
|
+
<div class="card-title">Processor</div>
|
|
894
|
+
</div>
|
|
895
|
+
<div class="card-body">
|
|
896
|
+
<div class="row"><span class="label">CPU</span><span class="value" id="cpu">—</span></div>
|
|
897
|
+
<div class="row"><span class="label">Cores</span><span class="value" id="cpuCore">—</span></div>
|
|
898
|
+
<div class="row"><span class="label">Architecture</span><span class="value" id="arch">—</span></div>
|
|
899
|
+
</div>
|
|
900
|
+
</div>
|
|
901
|
+
|
|
902
|
+
<!-- Memory & GPU -->
|
|
903
|
+
<div class="card">
|
|
904
|
+
<div class="card-header">
|
|
905
|
+
<div class="card-icon">🎮</div>
|
|
906
|
+
<div class="card-title">Memory & Graphics</div>
|
|
907
|
+
</div>
|
|
908
|
+
<div class="card-body">
|
|
909
|
+
<div class="row"><span class="label">RAM</span><span class="value" id="ram">—</span></div>
|
|
910
|
+
<div class="row"><span class="label">GPU</span><span class="value" id="gpu">—</span></div>
|
|
911
|
+
<div class="row"><span class="label">Manufacturer</span><span class="value" id="manufacturer">—</span></div>
|
|
912
|
+
</div>
|
|
913
|
+
</div>
|
|
914
|
+
|
|
915
|
+
<!-- Battery -->
|
|
916
|
+
<div class="card">
|
|
917
|
+
<div class="card-header">
|
|
918
|
+
<div class="card-icon">🔋</div>
|
|
919
|
+
<div class="card-title">Battery</div>
|
|
920
|
+
</div>
|
|
921
|
+
<div class="card-body">
|
|
922
|
+
<div class="row"><span class="label">Level</span><span class="value" id="batteryLevel">—</span></div>
|
|
923
|
+
<div class="row"><span class="label">Charging</span><span class="value" id="charging">—</span></div>
|
|
924
|
+
</div>
|
|
925
|
+
</div>
|
|
926
|
+
|
|
927
|
+
<!-- Screen -->
|
|
928
|
+
<div class="card">
|
|
929
|
+
<div class="card-header">
|
|
930
|
+
<div class="card-icon">📱</div>
|
|
931
|
+
<div class="card-title">Display</div>
|
|
932
|
+
</div>
|
|
933
|
+
<div class="card-body">
|
|
934
|
+
<div class="row"><span class="label">Resolution</span><span class="value" id="resolution">—</span></div>
|
|
935
|
+
<div class="row"><span class="label">Pixel Ratio</span><span class="value" id="pixelRatio">—</span></div>
|
|
936
|
+
<div class="row"><span class="label">Color Depth</span><span class="value" id="colorDepth">—</span></div>
|
|
937
|
+
</div>
|
|
938
|
+
</div>
|
|
939
|
+
|
|
940
|
+
<!-- Connection -->
|
|
941
|
+
<div class="card">
|
|
942
|
+
<div class="card-header">
|
|
943
|
+
<div class="card-icon">📶</div>
|
|
944
|
+
<div class="card-title">Connection</div>
|
|
945
|
+
</div>
|
|
946
|
+
<div class="card-body">
|
|
947
|
+
<div class="row"><span class="label">Type</span><span class="value" id="connType">—</span></div>
|
|
948
|
+
<div class="row"><span class="label">Downlink</span><span class="value" id="downlink">—</span></div>
|
|
949
|
+
<div class="row"><span class="label">RTT</span><span class="value" id="rtt">—</span></div>
|
|
950
|
+
</div>
|
|
951
|
+
</div>
|
|
952
|
+
|
|
953
|
+
<!-- Network -->
|
|
954
|
+
<div class="card">
|
|
955
|
+
<div class="card-header">
|
|
956
|
+
<div class="card-icon">🌍</div>
|
|
957
|
+
<div class="card-title">Network</div>
|
|
958
|
+
</div>
|
|
959
|
+
<div class="card-body">
|
|
960
|
+
<div class="row"><span class="label">IP</span><span class="value loading" id="ip">Click fetch</span></div>
|
|
961
|
+
<div class="row"><span class="label">ISP</span><span class="value" id="isp">—</span></div>
|
|
962
|
+
<div class="row"><span class="label">Country</span><span class="value" id="country">—</span></div>
|
|
963
|
+
</div>
|
|
964
|
+
<div class="actions">
|
|
965
|
+
<button onclick="fetchNetwork()">Fetch Network</button>
|
|
966
|
+
</div>
|
|
967
|
+
</div>
|
|
968
|
+
|
|
969
|
+
<!-- Location -->
|
|
970
|
+
<div class="card">
|
|
971
|
+
<div class="card-header">
|
|
972
|
+
<div class="card-icon">📍</div>
|
|
973
|
+
<div class="card-title">Location</div>
|
|
974
|
+
</div>
|
|
975
|
+
<div class="card-body">
|
|
976
|
+
<div class="row"><span class="label">Latitude</span><span class="value" id="lat">—</span></div>
|
|
977
|
+
<div class="row"><span class="label">Longitude</span><span class="value" id="lng">—</span></div>
|
|
978
|
+
<div class="row"><span class="label">Accuracy</span><span class="value" id="accuracy">—</span></div>
|
|
979
|
+
</div>
|
|
980
|
+
<div class="actions">
|
|
981
|
+
<button onclick="fetchLocation()">Get Location</button>
|
|
982
|
+
</div>
|
|
983
|
+
</div>
|
|
984
|
+
|
|
985
|
+
<!-- Raw Output -->
|
|
986
|
+
<div class="output">
|
|
987
|
+
<div class="output-header">
|
|
988
|
+
<div class="output-title">
|
|
989
|
+
<span>📋</span>
|
|
990
|
+
<span>Raw JSON Output</span>
|
|
991
|
+
</div>
|
|
992
|
+
<button onclick="copyJSON()">Copy</button>
|
|
993
|
+
</div>
|
|
994
|
+
<div class="output-body">
|
|
995
|
+
<pre id="rawOutput">Loading...</pre>
|
|
996
|
+
</div>
|
|
997
|
+
</div>
|
|
998
|
+
</div>
|
|
999
|
+
</div>
|
|
1000
|
+
|
|
1001
|
+
<!-- Documentation Tab -->
|
|
1002
|
+
<div class="tab-content" id="docs">
|
|
1003
|
+
<div class="docs-content">
|
|
1004
|
+
<h2>Features</h2>
|
|
1005
|
+
<div class="feature-grid">
|
|
1006
|
+
<div class="feature-item">
|
|
1007
|
+
<strong>🌐 Browser Detection</strong>
|
|
1008
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Name, version, rendering engine</p>
|
|
1009
|
+
</div>
|
|
1010
|
+
<div class="feature-item">
|
|
1011
|
+
<strong>💻 OS Detection</strong>
|
|
1012
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Windows, macOS, Linux, iOS, Android</p>
|
|
1013
|
+
</div>
|
|
1014
|
+
<div class="feature-item">
|
|
1015
|
+
<strong>⚙️ Hardware Info</strong>
|
|
1016
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">CPU cores, RAM, GPU, Apple Silicon</p>
|
|
1017
|
+
</div>
|
|
1018
|
+
<div class="feature-item">
|
|
1019
|
+
<strong>🌍 Network Info</strong>
|
|
1020
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Public IP, ISP, country (cached)</p>
|
|
1021
|
+
</div>
|
|
1022
|
+
<div class="feature-item">
|
|
1023
|
+
<strong>📱 Screen Info</strong>
|
|
1024
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Resolution, pixel ratio, orientation</p>
|
|
1025
|
+
</div>
|
|
1026
|
+
<div class="feature-item">
|
|
1027
|
+
<strong>🔋 Battery Status</strong>
|
|
1028
|
+
<p style="font-size: 0.85rem; margin-top: 4px;">Charging state, level percentage</p>
|
|
1029
|
+
</div>
|
|
1030
|
+
</div>
|
|
1031
|
+
|
|
1032
|
+
<h2>Installation</h2>
|
|
1033
|
+
|
|
1034
|
+
<h3>Package Manager</h3>
|
|
1035
|
+
<pre><code>npm install aki-info-detect
|
|
1036
|
+
# or
|
|
1037
|
+
yarn add aki-info-detect
|
|
1038
|
+
# or
|
|
1039
|
+
pnpm add aki-info-detect</code></pre>
|
|
1040
|
+
|
|
1041
|
+
<h3>CDN (ES Module)</h3>
|
|
1042
|
+
<pre><code><script type="module">
|
|
1043
|
+
import akiInfoDetect from 'https://unpkg.com/aki-info-detect/dist/aki-info-detect.js';
|
|
1044
|
+
const info = await akiInfoDetect();
|
|
1045
|
+
console.log(info);
|
|
1046
|
+
</script></code></pre>
|
|
1047
|
+
|
|
1048
|
+
<h3>CDN (UMD)</h3>
|
|
1049
|
+
<pre><code><script src="https://unpkg.com/aki-info-detect/dist/aki-info-detect.umd.cjs"></script>
|
|
1050
|
+
<script>
|
|
1051
|
+
akiInfoDetect().then(info => console.log(info));
|
|
1052
|
+
</script></code></pre>
|
|
1053
|
+
|
|
1054
|
+
<h2>Quick Start</h2>
|
|
1055
|
+
<pre><code>import akiInfoDetect from 'aki-info-detect';
|
|
1056
|
+
|
|
1057
|
+
// Get all info
|
|
1058
|
+
const info = await akiInfoDetect();
|
|
1059
|
+
console.log(info.browser); // "Chrome 120.0"
|
|
1060
|
+
console.log(info.os.name); // "macOS"
|
|
1061
|
+
console.log(info.CPU); // "Apple M3 Pro"
|
|
1062
|
+
|
|
1063
|
+
// Tree-shakeable imports
|
|
1064
|
+
import { detectBrowser, detectOS } from 'aki-info-detect';
|
|
1065
|
+
const browser = detectBrowser();
|
|
1066
|
+
const os = detectOS();</code></pre>
|
|
1067
|
+
|
|
1068
|
+
<h2>Server Configuration</h2>
|
|
1069
|
+
<p>For deep hardware detection, configure your server to send Client Hints headers:</p>
|
|
1070
|
+
|
|
1071
|
+
<h3>Express.js</h3>
|
|
1072
|
+
<pre><code>app.use((req, res, next) => {
|
|
1073
|
+
res.setHeader('Accept-CH',
|
|
1074
|
+
'Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, ' +
|
|
1075
|
+
'Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch, Sec-CH-UA-Bitness'
|
|
1076
|
+
);
|
|
1077
|
+
next();
|
|
1078
|
+
});</code></pre>
|
|
1079
|
+
|
|
1080
|
+
<h3>Nginx</h3>
|
|
1081
|
+
<pre><code>add_header Accept-CH "Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, Sec-CH-UA-Platform-Version, Sec-CH-UA-Arch, Sec-CH-UA-Bitness";</code></pre>
|
|
1082
|
+
|
|
1083
|
+
<h3>Vite</h3>
|
|
1084
|
+
<pre><code>// vite.config.js
|
|
1085
|
+
export default {
|
|
1086
|
+
server: {
|
|
1087
|
+
headers: {
|
|
1088
|
+
'Accept-CH': 'Sec-CH-UA, Sec-CH-UA-Mobile, Sec-CH-UA-Platform, ...'
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
};</code></pre>
|
|
1092
|
+
|
|
1093
|
+
<h2>Bundle Size</h2>
|
|
1094
|
+
<ul>
|
|
1095
|
+
<li><strong>ES Module:</strong> 14.85 kB</li>
|
|
1096
|
+
<li><strong>UMD:</strong> 9.38 kB</li>
|
|
1097
|
+
<li><strong>Gzipped:</strong> ~3.8 kB</li>
|
|
1098
|
+
</ul>
|
|
1099
|
+
|
|
1100
|
+
<h2>Browser Support</h2>
|
|
1101
|
+
<p>All modern browsers with ES2020+ support:</p>
|
|
1102
|
+
<ul>
|
|
1103
|
+
<li>Chrome/Edge 90+</li>
|
|
1104
|
+
<li>Firefox 88+</li>
|
|
1105
|
+
<li>Safari 14+</li>
|
|
1106
|
+
<li>Opera 76+</li>
|
|
1107
|
+
</ul>
|
|
1108
|
+
</div>
|
|
1109
|
+
</div>
|
|
1110
|
+
|
|
1111
|
+
<!-- API Reference Tab -->
|
|
1112
|
+
<div class="tab-content" id="api">
|
|
1113
|
+
<div class="docs-content">
|
|
1114
|
+
<h2>API Reference</h2>
|
|
1115
|
+
|
|
1116
|
+
<h3>Default Export: <code>akiInfoDetect()</code></h3>
|
|
1117
|
+
<p>Returns a Promise that resolves to an object containing all detected information.</p>
|
|
1118
|
+
<pre><code>const info = await akiInfoDetect();</code></pre>
|
|
1119
|
+
|
|
1120
|
+
<h3>Return Object</h3>
|
|
1121
|
+
<pre><code>{
|
|
1122
|
+
// Browser info
|
|
1123
|
+
browser: string, // "Chrome 120.0"
|
|
1124
|
+
product: string, // "Gecko"
|
|
1125
|
+
manufacturer: string, // "Google Inc."
|
|
1126
|
+
isMobile: boolean, // true/false
|
|
1127
|
+
language: string, // "en-US"
|
|
1128
|
+
|
|
1129
|
+
// OS info
|
|
1130
|
+
os: {
|
|
1131
|
+
name: string, // "macOS"
|
|
1132
|
+
version: string, // "14.1.2"
|
|
1133
|
+
string: string // "macOS 14.1.2"
|
|
1134
|
+
},
|
|
1135
|
+
|
|
1136
|
+
// Hardware
|
|
1137
|
+
CPU: string, // "Apple M3 Pro"
|
|
1138
|
+
CPUCore: number, // 12
|
|
1139
|
+
arch: string, // "arm64"
|
|
1140
|
+
RAM: number, // 16 (GB)
|
|
1141
|
+
GPU: string, // "Apple M3 Pro"
|
|
1142
|
+
|
|
1143
|
+
// Battery
|
|
1144
|
+
battery: {
|
|
1145
|
+
isCharging: boolean, // true/false
|
|
1146
|
+
level: number // 0-100
|
|
1147
|
+
},
|
|
1148
|
+
|
|
1149
|
+
// Methods
|
|
1150
|
+
getScreen: () => Object,
|
|
1151
|
+
getConnection: () => Object,
|
|
1152
|
+
getIP: () => Promise<string>,
|
|
1153
|
+
getISP: () => Promise<string>,
|
|
1154
|
+
getCountry: () => Promise<string>,
|
|
1155
|
+
getLocation: () => Promise<Object>
|
|
1156
|
+
}</code></pre>
|
|
1157
|
+
|
|
1158
|
+
<h3>Named Exports</h3>
|
|
1159
|
+
|
|
1160
|
+
<h4><code>detectBrowser()</code></h4>
|
|
1161
|
+
<p>Returns browser name and version.</p>
|
|
1162
|
+
<pre><code>import { detectBrowser } from 'aki-info-detect';
|
|
1163
|
+
const browser = detectBrowser(); // "Chrome 120.0"</code></pre>
|
|
1164
|
+
|
|
1165
|
+
<h4><code>detectOS()</code></h4>
|
|
1166
|
+
<p>Returns OS information.</p>
|
|
1167
|
+
<pre><code>import { detectOS } from 'aki-info-detect';
|
|
1168
|
+
const os = detectOS();
|
|
1169
|
+
// { name: "macOS", version: "14.1.2", string: "macOS 14.1.2" }</code></pre>
|
|
1170
|
+
|
|
1171
|
+
<h4><code>getHardwareInfo()</code></h4>
|
|
1172
|
+
<p>Returns CPU, GPU, RAM information (async).</p>
|
|
1173
|
+
<pre><code>import { getHardwareInfo } from 'aki-info-detect';
|
|
1174
|
+
const hw = await getHardwareInfo();
|
|
1175
|
+
// { CPU: "...", cores: 12, arch: "...", RAM: 16, GPU: "..." }</code></pre>
|
|
1176
|
+
|
|
1177
|
+
<h4><code>getNetworkInfo()</code></h4>
|
|
1178
|
+
<p>Returns network information with caching (async).</p>
|
|
1179
|
+
<pre><code>import { getNetworkInfo } from 'aki-info-detect';
|
|
1180
|
+
const net = await getNetworkInfo();
|
|
1181
|
+
// { ip: "...", isp: "...", country: "..." }</code></pre>
|
|
1182
|
+
|
|
1183
|
+
<h4><code>getScreen()</code></h4>
|
|
1184
|
+
<p>Returns screen dimensions and properties.</p>
|
|
1185
|
+
<pre><code>import { getScreen } from 'aki-info-detect';
|
|
1186
|
+
const screen = getScreen();
|
|
1187
|
+
// { width: 1920, height: 1080, pixelRatio: 2, ... }</code></pre>
|
|
1188
|
+
|
|
1189
|
+
<h4><code>getBattery()</code></h4>
|
|
1190
|
+
<p>Returns battery status (async).</p>
|
|
1191
|
+
<pre><code>import { getBattery } from 'aki-info-detect';
|
|
1192
|
+
const battery = await getBattery();
|
|
1193
|
+
// { isCharging: true, level: 85 }</code></pre>
|
|
1194
|
+
|
|
1195
|
+
<h3>Caching</h3>
|
|
1196
|
+
<p>Network requests (IP, ISP, Country) are cached for 1 hour to reduce API calls.</p>
|
|
1197
|
+
<pre><code>// First call: fetches from API
|
|
1198
|
+
const ip1 = await info.getIP();
|
|
1199
|
+
|
|
1200
|
+
// Within 1 hour: returns cached value
|
|
1201
|
+
const ip2 = await info.getIP();</code></pre>
|
|
1202
|
+
|
|
1203
|
+
<h3>Error Handling</h3>
|
|
1204
|
+
<pre><code>try {
|
|
1205
|
+
const info = await akiInfoDetect();
|
|
1206
|
+
console.log(info.browser);
|
|
1207
|
+
} catch (error) {
|
|
1208
|
+
console.error('Detection failed:', error);
|
|
1209
|
+
}</code></pre>
|
|
1210
|
+
|
|
1211
|
+
<h3>TypeScript Support</h3>
|
|
1212
|
+
<p>Full TypeScript declarations included.</p>
|
|
1213
|
+
<pre><code>import akiInfoDetect, { type DetectionResult } from 'aki-info-detect';
|
|
1214
|
+
|
|
1215
|
+
const info: DetectionResult = await akiInfoDetect();</code></pre>
|
|
1216
|
+
</div>
|
|
1217
|
+
</div>
|
|
1218
|
+
|
|
1219
|
+
<footer>
|
|
1220
|
+
<div class="footer-links">
|
|
1221
|
+
<a href="https://github.com/lacvietanh/akiInfoDetect.js">
|
|
1222
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
|
1223
|
+
GitHub
|
|
1224
|
+
</a>
|
|
1225
|
+
<a href="https://www.npmjs.com/package/aki-info-detect">
|
|
1226
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M0 7.334v8h6.666v1.332H12v-1.332h12v-8H0zm6.666 6.664H5.334v-4H3.999v4H1.335V8.667h5.331v5.331zm4 0v1.336H8.001V8.667h5.334v5.332h-2.669v-.001zm12.001 0h-1.33v-4h-1.336v4h-1.335v-4h-1.33v4h-2.671V8.667h8.002v5.331zM10.665 10H12v2.667h-1.335V10z"/></svg>
|
|
1227
|
+
npm
|
|
1228
|
+
</a>
|
|
1229
|
+
<a href="https://bundlephobia.com/package/aki-info-detect">
|
|
1230
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
|
|
1231
|
+
Size
|
|
1232
|
+
</a>
|
|
1233
|
+
</div>
|
|
1234
|
+
<p class="footer-credit">MIT License · Made with ⚡ by <a href="https://github.com/lacvietanh">lacvietanh</a></p>
|
|
1235
|
+
</footer>
|
|
1236
|
+
</div>
|
|
1237
|
+
|
|
1238
|
+
<script type="module">
|
|
1239
|
+
// Tab switching
|
|
1240
|
+
document.querySelectorAll('.tab').forEach(tab => {
|
|
1241
|
+
tab.addEventListener('click', () => {
|
|
1242
|
+
const targetId = tab.dataset.tab;
|
|
1243
|
+
|
|
1244
|
+
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
1245
|
+
document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
|
|
1246
|
+
|
|
1247
|
+
tab.classList.add('active');
|
|
1248
|
+
document.getElementById(targetId).classList.add('active');
|
|
1249
|
+
});
|
|
1250
|
+
});
|
|
1251
|
+
|
|
1252
|
+
// Library loading
|
|
1253
|
+
const isDev = location.port === '3000';
|
|
1254
|
+
const module = isDev
|
|
1255
|
+
? await import('/src/index.js')
|
|
1256
|
+
: await import('./aki-info-detect.js');
|
|
1257
|
+
|
|
1258
|
+
const akiInfoDetect = module.default;
|
|
1259
|
+
let info = null;
|
|
1260
|
+
let rawData = null;
|
|
1261
|
+
|
|
1262
|
+
async function init() {
|
|
1263
|
+
try {
|
|
1264
|
+
info = await akiInfoDetect();
|
|
1265
|
+
|
|
1266
|
+
document.getElementById('browser').textContent = info.browser || '—';
|
|
1267
|
+
document.getElementById('product').textContent = info.product || '—';
|
|
1268
|
+
document.getElementById('isMobile').textContent = info.isMobile ? 'Yes' : 'No';
|
|
1269
|
+
document.getElementById('language').textContent = info.language || '—';
|
|
1270
|
+
|
|
1271
|
+
document.getElementById('osName').textContent = info.os?.name || '—';
|
|
1272
|
+
document.getElementById('osVersion').textContent = info.os?.version || '—';
|
|
1273
|
+
document.getElementById('osString').textContent = info.os?.string || '—';
|
|
1274
|
+
|
|
1275
|
+
document.getElementById('cpu').textContent = info.CPU || '—';
|
|
1276
|
+
document.getElementById('cpuCore').textContent = info.CPUCore ? `${info.CPUCore} cores` : '—';
|
|
1277
|
+
document.getElementById('arch').textContent = info.arch || '—';
|
|
1278
|
+
|
|
1279
|
+
document.getElementById('ram').textContent = info.RAM ? `${info.RAM} GB` : '—';
|
|
1280
|
+
document.getElementById('gpu').textContent = info.GPU || '—';
|
|
1281
|
+
document.getElementById('manufacturer').textContent = info.manufacturer || '—';
|
|
1282
|
+
|
|
1283
|
+
if (info.battery?.level > 0) {
|
|
1284
|
+
document.getElementById('batteryLevel').textContent = `${info.battery.level}%`;
|
|
1285
|
+
document.getElementById('charging').textContent = info.battery.isCharging ? 'Yes ⚡' : 'No';
|
|
1286
|
+
} else {
|
|
1287
|
+
document.getElementById('batteryLevel').textContent = 'N/A';
|
|
1288
|
+
document.getElementById('batteryLevel').className = 'value muted';
|
|
1289
|
+
document.getElementById('charging').textContent = 'N/A';
|
|
1290
|
+
document.getElementById('charging').className = 'value muted';
|
|
1291
|
+
}
|
|
1292
|
+
|
|
1293
|
+
const screen = info.getScreen();
|
|
1294
|
+
document.getElementById('resolution').textContent = `${screen.width} × ${screen.height}`;
|
|
1295
|
+
document.getElementById('pixelRatio').textContent = `${screen.pixelRatio}x`;
|
|
1296
|
+
document.getElementById('colorDepth').textContent = `${screen.colorDepth}-bit`;
|
|
1297
|
+
|
|
1298
|
+
const conn = info.getConnection();
|
|
1299
|
+
document.getElementById('connType').textContent = conn.type !== 'unknown' ? conn.type : '—';
|
|
1300
|
+
document.getElementById('downlink').textContent = conn.downlink ? `${conn.downlink} Mbps` : '—';
|
|
1301
|
+
document.getElementById('rtt').textContent = conn.rtt ? `${conn.rtt} ms` : '—';
|
|
1302
|
+
|
|
1303
|
+
rawData = { ...info };
|
|
1304
|
+
delete rawData.getIP;
|
|
1305
|
+
delete rawData.getISP;
|
|
1306
|
+
delete rawData.getCountry;
|
|
1307
|
+
delete rawData.getConnection;
|
|
1308
|
+
delete rawData.getScreen;
|
|
1309
|
+
delete rawData.getLocation;
|
|
1310
|
+
rawData.screen = screen;
|
|
1311
|
+
rawData.connection = conn;
|
|
1312
|
+
document.getElementById('rawOutput').textContent = JSON.stringify(rawData, null, 2);
|
|
1313
|
+
|
|
1314
|
+
} catch (err) {
|
|
1315
|
+
document.getElementById('rawOutput').textContent = 'Error: ' + err.message;
|
|
1316
|
+
console.error(err);
|
|
1317
|
+
}
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
window.fetchNetwork = async function() {
|
|
1321
|
+
if (!info) return;
|
|
1322
|
+
document.getElementById('ip').className = 'value loading';
|
|
1323
|
+
document.getElementById('ip').textContent = 'Fetching...';
|
|
1324
|
+
try {
|
|
1325
|
+
const [ip, isp, country] = await Promise.all([
|
|
1326
|
+
info.getIP(),
|
|
1327
|
+
info.getISP(),
|
|
1328
|
+
info.getCountry()
|
|
1329
|
+
]);
|
|
1330
|
+
document.getElementById('ip').className = 'value';
|
|
1331
|
+
document.getElementById('ip').textContent = ip || '—';
|
|
1332
|
+
document.getElementById('isp').textContent = isp || '—';
|
|
1333
|
+
document.getElementById('country').textContent = country || '—';
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
document.getElementById('ip').className = 'value error';
|
|
1336
|
+
document.getElementById('ip').textContent = 'Error';
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1340
|
+
window.fetchLocation = async function() {
|
|
1341
|
+
if (!info) return;
|
|
1342
|
+
document.getElementById('lat').className = 'value loading';
|
|
1343
|
+
document.getElementById('lat').textContent = 'Getting...';
|
|
1344
|
+
try {
|
|
1345
|
+
const loc = await info.getLocation();
|
|
1346
|
+
document.getElementById('lat').className = 'value';
|
|
1347
|
+
document.getElementById('lat').textContent = loc.latitude?.toFixed(6) || '—';
|
|
1348
|
+
document.getElementById('lng').textContent = loc.longitude?.toFixed(6) || '—';
|
|
1349
|
+
document.getElementById('accuracy').textContent = loc.accuracy ? `±${loc.accuracy}m` : '—';
|
|
1350
|
+
} catch (err) {
|
|
1351
|
+
document.getElementById('lat').className = 'value error';
|
|
1352
|
+
document.getElementById('lat').textContent = 'Denied';
|
|
1353
|
+
document.getElementById('lng').textContent = '—';
|
|
1354
|
+
document.getElementById('accuracy').textContent = '—';
|
|
1355
|
+
}
|
|
1356
|
+
};
|
|
1357
|
+
|
|
1358
|
+
window.copyInstall = function() {
|
|
1359
|
+
navigator.clipboard.writeText('npm install aki-info-detect');
|
|
1360
|
+
const btn = document.querySelector('.install-box button');
|
|
1361
|
+
btn.textContent = 'Copied!';
|
|
1362
|
+
setTimeout(() => btn.textContent = 'Copy', 1500);
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1365
|
+
window.copyJSON = function() {
|
|
1366
|
+
if (rawData) {
|
|
1367
|
+
navigator.clipboard.writeText(JSON.stringify(rawData, null, 2));
|
|
1368
|
+
const btn = document.querySelector('.output button');
|
|
1369
|
+
btn.textContent = 'Copied!';
|
|
1370
|
+
setTimeout(() => btn.textContent = 'Copy', 1500);
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
init();
|
|
1375
|
+
</script>
|
|
1376
|
+
</body>
|
|
1377
|
+
</html>
|