ipfyi-embed 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +157 -0
- package/dist/embed.esm.js +1841 -0
- package/dist/embed.min.js +1018 -0
- package/dist/index.d.ts +27 -0
- package/package.json +44 -0
|
@@ -0,0 +1,1841 @@
|
|
|
1
|
+
/* ipfyi-embed v1.0.0 | MIT | https://widget.ipfyi.com */
|
|
2
|
+
|
|
3
|
+
// src/styles/modern.ts
|
|
4
|
+
function getModernCSS() {
|
|
5
|
+
return `
|
|
6
|
+
/* Modern: gradient accent header */
|
|
7
|
+
.networkfyi-header {
|
|
8
|
+
background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 70%, #000));
|
|
9
|
+
border-radius: 12px 12px 0 0;
|
|
10
|
+
padding: 16px 20px;
|
|
11
|
+
display: flex;
|
|
12
|
+
align-items: flex-start;
|
|
13
|
+
gap: 14px;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.networkfyi-header-title {
|
|
17
|
+
font-size: 15px;
|
|
18
|
+
font-weight: 700;
|
|
19
|
+
color: #fff;
|
|
20
|
+
margin: 0 0 4px 0;
|
|
21
|
+
line-height: 1.3;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.networkfyi-header-subtitle {
|
|
25
|
+
font-size: 12px;
|
|
26
|
+
color: rgba(255, 255, 255, 0.8);
|
|
27
|
+
margin: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/* Icon area */
|
|
31
|
+
.networkfyi-img {
|
|
32
|
+
width: 56px;
|
|
33
|
+
height: 56px;
|
|
34
|
+
border-radius: 8px;
|
|
35
|
+
object-fit: cover;
|
|
36
|
+
background: rgba(255, 255, 255, 0.15);
|
|
37
|
+
flex-shrink: 0;
|
|
38
|
+
display: flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
overflow: hidden;
|
|
42
|
+
font-size: 24px;
|
|
43
|
+
color: #fff;
|
|
44
|
+
font-weight: 700;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
.networkfyi-img img {
|
|
48
|
+
width: 100%;
|
|
49
|
+
height: 100%;
|
|
50
|
+
object-fit: cover;
|
|
51
|
+
border-radius: 8px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/* Body area */
|
|
55
|
+
.networkfyi-body {
|
|
56
|
+
padding: 16px 20px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* Key-value rows \u2014 spacious */
|
|
60
|
+
.networkfyi-row {
|
|
61
|
+
display: flex;
|
|
62
|
+
justify-content: space-between;
|
|
63
|
+
align-items: flex-start;
|
|
64
|
+
gap: 12px;
|
|
65
|
+
padding: 8px 0;
|
|
66
|
+
border-bottom: 1px solid var(--border);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.networkfyi-row:last-child {
|
|
70
|
+
border-bottom: none;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.networkfyi-label {
|
|
74
|
+
font-size: 12px;
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
color: var(--muted);
|
|
77
|
+
white-space: nowrap;
|
|
78
|
+
flex-shrink: 0;
|
|
79
|
+
min-width: 30%;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.networkfyi-value {
|
|
83
|
+
font-size: 13px;
|
|
84
|
+
color: var(--text);
|
|
85
|
+
text-align: right;
|
|
86
|
+
word-break: break-word;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* Section title */
|
|
90
|
+
.networkfyi-section-title {
|
|
91
|
+
font-size: 11px;
|
|
92
|
+
font-weight: 600;
|
|
93
|
+
color: var(--muted);
|
|
94
|
+
text-transform: uppercase;
|
|
95
|
+
letter-spacing: 0.06em;
|
|
96
|
+
margin: 0 0 10px 0;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Tags \u2014 colored rounded badges */
|
|
100
|
+
.networkfyi-tag {
|
|
101
|
+
display: inline-block;
|
|
102
|
+
font-size: 11px;
|
|
103
|
+
font-weight: 600;
|
|
104
|
+
padding: 3px 10px;
|
|
105
|
+
border-radius: 12px;
|
|
106
|
+
background: color-mix(in srgb, var(--accent) 12%, transparent);
|
|
107
|
+
color: var(--accent);
|
|
108
|
+
margin: 2px 3px 2px 0;
|
|
109
|
+
letter-spacing: 0.02em;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Link */
|
|
113
|
+
.networkfyi-link {
|
|
114
|
+
font-size: 13px;
|
|
115
|
+
font-weight: 500;
|
|
116
|
+
color: var(--link);
|
|
117
|
+
text-decoration: none;
|
|
118
|
+
display: inline-flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 4px;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
.networkfyi-link:hover {
|
|
124
|
+
opacity: 0.8;
|
|
125
|
+
text-decoration: underline;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.networkfyi-link svg {
|
|
129
|
+
width: 12px;
|
|
130
|
+
height: 12px;
|
|
131
|
+
flex-shrink: 0;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/* Footer link row */
|
|
135
|
+
.networkfyi-footer-link {
|
|
136
|
+
display: flex;
|
|
137
|
+
align-items: center;
|
|
138
|
+
justify-content: space-between;
|
|
139
|
+
padding: 12px 20px;
|
|
140
|
+
border-top: 1px solid var(--border);
|
|
141
|
+
gap: 8px;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
145
|
+
Card shared: stats row (horizontal flex)
|
|
146
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
147
|
+
.networkfyi-stats-row { display:flex; gap:12px; padding:10px 18px; border-bottom:1px solid var(--border); }
|
|
148
|
+
.networkfyi-stat { text-align:center; flex:1; }
|
|
149
|
+
.networkfyi-stat-value { font-size:18px; font-weight:700; color:var(--accent); }
|
|
150
|
+
.networkfyi-stat-label { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:0.03em; }
|
|
151
|
+
|
|
152
|
+
/* Card shared: stats grid (2x2 boxes) */
|
|
153
|
+
.networkfyi-stats-grid { display:grid; grid-template-columns:1fr 1fr; gap:8px; padding:10px 18px; border-bottom:1px solid var(--border); }
|
|
154
|
+
.networkfyi-stat-box { padding:6px 8px; background:color-mix(in srgb, var(--accent) 8%, var(--bg)); border-radius:8px; }
|
|
155
|
+
.networkfyi-stat-box-label { font-size:9px; color:color-mix(in srgb, var(--accent) 80%, var(--text)); text-transform:uppercase; }
|
|
156
|
+
.networkfyi-stat-box-value { font-size:13px; font-weight:700; color:var(--text); margin-top:1px; }
|
|
157
|
+
|
|
158
|
+
/* Card shared: key-value dotted rows */
|
|
159
|
+
.networkfyi-kv-rows { padding:10px 18px; border-bottom:1px solid var(--border); }
|
|
160
|
+
.networkfyi-kv-row { display:flex; justify-content:space-between; align-items:baseline; padding:4px 0; border-bottom:1px dotted var(--border); }
|
|
161
|
+
.networkfyi-kv-row:last-child { border-bottom:none; }
|
|
162
|
+
.networkfyi-kv-label { font-size:11px; color:var(--muted); }
|
|
163
|
+
.networkfyi-kv-value { font-size:11px; font-weight:600; color:var(--text); }
|
|
164
|
+
|
|
165
|
+
/* Card shared: pill tags */
|
|
166
|
+
.networkfyi-pills { display:flex; flex-wrap:wrap; gap:4px; padding:10px 18px; border-bottom:1px solid var(--border); }
|
|
167
|
+
.networkfyi-pill { padding:2px 8px; border-radius:10px; font-size:11px; font-weight:500; background:color-mix(in srgb, var(--accent) 10%, var(--bg)); color:var(--accent); }
|
|
168
|
+
|
|
169
|
+
/* Card shared: section label */
|
|
170
|
+
.networkfyi-section-label { font-size:10px; text-transform:uppercase; letter-spacing:0.05em; color:var(--accent); font-weight:600; margin-bottom:3px; }
|
|
171
|
+
|
|
172
|
+
/* Card shared: description */
|
|
173
|
+
.networkfyi-desc { padding:10px 18px; font-size:14px; color:var(--muted); line-height:1.5; border-bottom:1px solid var(--border); }
|
|
174
|
+
|
|
175
|
+
/* Card shared: view link */
|
|
176
|
+
.networkfyi-view-link { display:block; text-align:center; padding:10px 18px; border-bottom:1px solid var(--border); }
|
|
177
|
+
.networkfyi-view-link a { color:var(--link); text-decoration:none; font-size:12px; font-weight:500; display:inline-flex; align-items:center; gap:4px; }
|
|
178
|
+
.networkfyi-view-link a:hover { text-decoration:underline; }
|
|
179
|
+
.networkfyi-view-link svg { width:12px; height:12px; }
|
|
180
|
+
|
|
181
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
182
|
+
Domain: code/status display (large number)
|
|
183
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
184
|
+
.networkfyi-code-display { padding:14px 18px; text-align:center; border-bottom:1px solid var(--border); }
|
|
185
|
+
.networkfyi-code-big { font-size:36px; font-weight:800; color:var(--accent); line-height:1; font-family:ui-monospace, 'SF Mono', monospace; }
|
|
186
|
+
.networkfyi-code-name { font-size:13px; color:var(--text); font-weight:600; margin-top:4px; }
|
|
187
|
+
.networkfyi-code-protocol { font-size:11px; color:var(--muted); margin-top:2px; }
|
|
188
|
+
|
|
189
|
+
/* Domain: speed bar visualization */
|
|
190
|
+
.networkfyi-speed-bar-wrap { padding:10px 18px; border-bottom:1px solid var(--border); }
|
|
191
|
+
.networkfyi-speed-bar-track { width:100%; height:8px; background:var(--surface); border-radius:4px; overflow:hidden; }
|
|
192
|
+
.networkfyi-speed-bar-fill { height:100%; border-radius:4px; transition:width 0.3s; }
|
|
193
|
+
.networkfyi-speed-bar-label { font-size:11px; color:var(--muted); margin-top:4px; display:flex; justify-content:space-between; }
|
|
194
|
+
|
|
195
|
+
/* Domain: connector arrow display */
|
|
196
|
+
.networkfyi-connector-arrow { display:flex; align-items:center; justify-content:center; gap:8px; padding:12px 18px; border-bottom:1px solid var(--border); font-size:13px; font-weight:600; color:var(--text); }
|
|
197
|
+
.networkfyi-connector-arrow-icon { color:var(--accent); font-size:16px; }
|
|
198
|
+
|
|
199
|
+
/* Domain: compatibility result */
|
|
200
|
+
.networkfyi-compat-result { padding:14px 18px; text-align:center; border-bottom:1px solid var(--border); }
|
|
201
|
+
.networkfyi-compat-status { font-size:14px; font-weight:700; margin-bottom:4px; }
|
|
202
|
+
.networkfyi-compat-detail { font-size:12px; color:var(--muted); }
|
|
203
|
+
|
|
204
|
+
/* Domain: scenario card */
|
|
205
|
+
.networkfyi-scenario-header { padding:12px 18px; border-bottom:1px solid var(--border); }
|
|
206
|
+
.networkfyi-scenario-title { font-size:14px; font-weight:700; color:var(--text); margin:0 0 6px 0; }
|
|
207
|
+
.networkfyi-scenario-meta { display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
|
|
208
|
+
|
|
209
|
+
/* Domain: form inputs (compatibility tool) */
|
|
210
|
+
.networkfyi-tool-form { padding:12px 18px; border-bottom:1px solid var(--border); }
|
|
211
|
+
.networkfyi-tool-row { display:flex; gap:6px; align-items:center; margin-bottom:6px; }
|
|
212
|
+
.networkfyi-tool-row:last-child { margin-bottom:0; }
|
|
213
|
+
.networkfyi-tool-input { flex:1; padding:6px 10px; border:1px solid var(--input-border); border-radius:6px; background:var(--input-bg); color:var(--text); font-size:13px; font-family:inherit; outline:none; }
|
|
214
|
+
.networkfyi-tool-input:focus { border-color:var(--input-focus); box-shadow:0 0 0 2px color-mix(in srgb, var(--input-focus) 20%, transparent); }
|
|
215
|
+
.networkfyi-tool-label { font-size:11px; color:var(--muted); min-width:72px; }
|
|
216
|
+
.networkfyi-tool-btn { background:var(--accent); color:#fff; border:none; border-radius:6px; padding:7px 14px; font-size:13px; font-weight:500; cursor:pointer; font-family:inherit; transition:opacity 0.15s; }
|
|
217
|
+
.networkfyi-tool-btn:hover { opacity:0.9; }
|
|
218
|
+
|
|
219
|
+
/* Inline widget host */
|
|
220
|
+
:host([data-inline]) {
|
|
221
|
+
display: inline-flex;
|
|
222
|
+
align-items: center;
|
|
223
|
+
gap: 4px;
|
|
224
|
+
}
|
|
225
|
+
`;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// src/styles/clean.ts
|
|
229
|
+
function getCleanCSS() {
|
|
230
|
+
return `
|
|
231
|
+
/* Clean: subtle top accent border instead of gradient header */
|
|
232
|
+
.networkfyi-header {
|
|
233
|
+
border-top: 3px solid var(--accent);
|
|
234
|
+
border-radius: 8px 8px 0 0;
|
|
235
|
+
padding: 14px 18px;
|
|
236
|
+
display: flex;
|
|
237
|
+
align-items: flex-start;
|
|
238
|
+
gap: 12px;
|
|
239
|
+
background: color-mix(in srgb, var(--accent) 5%, var(--surface));
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
.networkfyi-header-title {
|
|
243
|
+
font-size: 15px;
|
|
244
|
+
font-weight: 700;
|
|
245
|
+
color: var(--text);
|
|
246
|
+
margin: 0 0 4px 0;
|
|
247
|
+
line-height: 1.3;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.networkfyi-header-subtitle {
|
|
251
|
+
font-size: 12px;
|
|
252
|
+
color: var(--muted);
|
|
253
|
+
margin: 0;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/* Icon area \u2014 smaller, muted */
|
|
257
|
+
.networkfyi-img {
|
|
258
|
+
width: 44px;
|
|
259
|
+
height: 44px;
|
|
260
|
+
border-radius: 8px;
|
|
261
|
+
background: color-mix(in srgb, var(--accent) 12%, var(--bg));
|
|
262
|
+
flex-shrink: 0;
|
|
263
|
+
display: flex;
|
|
264
|
+
align-items: center;
|
|
265
|
+
justify-content: center;
|
|
266
|
+
overflow: hidden;
|
|
267
|
+
font-size: 20px;
|
|
268
|
+
color: var(--accent);
|
|
269
|
+
font-weight: 700;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.networkfyi-img img {
|
|
273
|
+
width: 100%;
|
|
274
|
+
height: 100%;
|
|
275
|
+
object-fit: cover;
|
|
276
|
+
border-radius: 8px;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/* Body area */
|
|
280
|
+
.networkfyi-body {
|
|
281
|
+
padding: 14px 18px;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/* Key-value rows */
|
|
285
|
+
.networkfyi-row {
|
|
286
|
+
display: flex;
|
|
287
|
+
justify-content: space-between;
|
|
288
|
+
align-items: flex-start;
|
|
289
|
+
gap: 12px;
|
|
290
|
+
padding: 6px 0;
|
|
291
|
+
border-bottom: 1px solid var(--border);
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.networkfyi-row:last-child {
|
|
295
|
+
border-bottom: none;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.networkfyi-label {
|
|
299
|
+
font-size: 12px;
|
|
300
|
+
font-weight: 500;
|
|
301
|
+
color: var(--muted);
|
|
302
|
+
white-space: nowrap;
|
|
303
|
+
flex-shrink: 0;
|
|
304
|
+
min-width: 30%;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.networkfyi-value {
|
|
308
|
+
font-size: 13px;
|
|
309
|
+
color: var(--text);
|
|
310
|
+
text-align: right;
|
|
311
|
+
word-break: break-word;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/* Section title */
|
|
315
|
+
.networkfyi-section-title {
|
|
316
|
+
font-size: 11px;
|
|
317
|
+
font-weight: 600;
|
|
318
|
+
color: var(--muted);
|
|
319
|
+
text-transform: uppercase;
|
|
320
|
+
letter-spacing: 0.06em;
|
|
321
|
+
margin: 0 0 8px 0;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/* Tags \u2014 subtle pill badges */
|
|
325
|
+
.networkfyi-tag {
|
|
326
|
+
display: inline-block;
|
|
327
|
+
font-size: 11px;
|
|
328
|
+
font-weight: 500;
|
|
329
|
+
padding: 2px 8px;
|
|
330
|
+
border-radius: 4px;
|
|
331
|
+
background: var(--badge-bg);
|
|
332
|
+
color: var(--badge-text);
|
|
333
|
+
margin: 2px 3px 2px 0;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/* Link */
|
|
337
|
+
.networkfyi-link {
|
|
338
|
+
font-size: 13px;
|
|
339
|
+
font-weight: 500;
|
|
340
|
+
color: var(--link);
|
|
341
|
+
text-decoration: none;
|
|
342
|
+
display: inline-flex;
|
|
343
|
+
align-items: center;
|
|
344
|
+
gap: 4px;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.networkfyi-link:hover {
|
|
348
|
+
text-decoration: underline;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.networkfyi-link svg {
|
|
352
|
+
width: 12px;
|
|
353
|
+
height: 12px;
|
|
354
|
+
flex-shrink: 0;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
/* Footer link row */
|
|
358
|
+
.networkfyi-footer-link {
|
|
359
|
+
display: flex;
|
|
360
|
+
align-items: center;
|
|
361
|
+
justify-content: space-between;
|
|
362
|
+
padding: 10px 18px;
|
|
363
|
+
border-top: 1px solid var(--border);
|
|
364
|
+
gap: 8px;
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
368
|
+
Card shared: stats row (horizontal flex)
|
|
369
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
370
|
+
.networkfyi-stats-row { display:flex; gap:10px; padding:8px 16px; border-bottom:1px solid var(--border); }
|
|
371
|
+
.networkfyi-stat { text-align:center; flex:1; }
|
|
372
|
+
.networkfyi-stat-value { font-size:16px; font-weight:700; color:var(--accent); }
|
|
373
|
+
.networkfyi-stat-label { font-size:9px; color:var(--muted); text-transform:uppercase; letter-spacing:0.03em; }
|
|
374
|
+
|
|
375
|
+
/* Card shared: stats grid (2x2 boxes) */
|
|
376
|
+
.networkfyi-stats-grid { display:grid; grid-template-columns:1fr 1fr; gap:6px; padding:8px 16px; border-bottom:1px solid var(--border); }
|
|
377
|
+
.networkfyi-stat-box { padding:5px 7px; background:var(--surface); border-radius:6px; }
|
|
378
|
+
.networkfyi-stat-box-label { font-size:9px; color:var(--muted); text-transform:uppercase; }
|
|
379
|
+
.networkfyi-stat-box-value { font-size:12px; font-weight:700; color:var(--text); margin-top:1px; }
|
|
380
|
+
|
|
381
|
+
/* Card shared: key-value dotted rows */
|
|
382
|
+
.networkfyi-kv-rows { padding:8px 16px; border-bottom:1px solid var(--border); }
|
|
383
|
+
.networkfyi-kv-row { display:flex; justify-content:space-between; align-items:baseline; padding:3px 0; border-bottom:1px dotted var(--border); }
|
|
384
|
+
.networkfyi-kv-row:last-child { border-bottom:none; }
|
|
385
|
+
.networkfyi-kv-label { font-size:11px; color:var(--muted); }
|
|
386
|
+
.networkfyi-kv-value { font-size:11px; font-weight:600; color:var(--text); }
|
|
387
|
+
|
|
388
|
+
/* Card shared: pill tags */
|
|
389
|
+
.networkfyi-pills { display:flex; flex-wrap:wrap; gap:4px; padding:8px 16px; border-bottom:1px solid var(--border); }
|
|
390
|
+
.networkfyi-pill { padding:2px 7px; border-radius:4px; font-size:11px; font-weight:500; background:var(--badge-bg); color:var(--badge-text); }
|
|
391
|
+
|
|
392
|
+
/* Card shared: section label */
|
|
393
|
+
.networkfyi-section-label { font-size:10px; text-transform:uppercase; letter-spacing:0.05em; color:var(--accent); font-weight:600; margin-bottom:3px; }
|
|
394
|
+
|
|
395
|
+
/* Card shared: description */
|
|
396
|
+
.networkfyi-desc { padding:8px 16px; font-size:13px; color:var(--muted); line-height:1.5; border-bottom:1px solid var(--border); }
|
|
397
|
+
|
|
398
|
+
/* Card shared: view link */
|
|
399
|
+
.networkfyi-view-link { display:block; text-align:center; padding:8px 16px; border-bottom:1px solid var(--border); }
|
|
400
|
+
.networkfyi-view-link a { color:var(--link); text-decoration:none; font-size:12px; font-weight:500; display:inline-flex; align-items:center; gap:4px; }
|
|
401
|
+
.networkfyi-view-link a:hover { text-decoration:underline; }
|
|
402
|
+
.networkfyi-view-link svg { width:12px; height:12px; }
|
|
403
|
+
|
|
404
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
405
|
+
Domain: code/status display (large number)
|
|
406
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
407
|
+
.networkfyi-code-display { padding:12px 16px; text-align:center; border-bottom:1px solid var(--border); }
|
|
408
|
+
.networkfyi-code-big { font-size:28px; font-weight:700; color:var(--accent); line-height:1; font-family:ui-monospace, 'SF Mono', monospace; }
|
|
409
|
+
.networkfyi-code-name { font-size:12px; color:var(--text); font-weight:600; margin-top:3px; }
|
|
410
|
+
.networkfyi-code-protocol { font-size:10px; color:var(--muted); margin-top:2px; }
|
|
411
|
+
|
|
412
|
+
/* Domain: speed bar visualization */
|
|
413
|
+
.networkfyi-speed-bar-wrap { padding:8px 16px; border-bottom:1px solid var(--border); }
|
|
414
|
+
.networkfyi-speed-bar-track { width:100%; height:6px; background:var(--surface); border-radius:3px; overflow:hidden; }
|
|
415
|
+
.networkfyi-speed-bar-fill { height:100%; border-radius:3px; transition:width 0.3s; }
|
|
416
|
+
.networkfyi-speed-bar-label { font-size:10px; color:var(--muted); margin-top:3px; display:flex; justify-content:space-between; }
|
|
417
|
+
|
|
418
|
+
/* Domain: connector arrow display */
|
|
419
|
+
.networkfyi-connector-arrow { display:flex; align-items:center; justify-content:center; gap:6px; padding:10px 16px; border-bottom:1px solid var(--border); font-size:12px; font-weight:600; color:var(--text); }
|
|
420
|
+
.networkfyi-connector-arrow-icon { color:var(--accent); font-size:14px; }
|
|
421
|
+
|
|
422
|
+
/* Domain: compatibility result */
|
|
423
|
+
.networkfyi-compat-result { padding:12px 16px; text-align:center; border-bottom:1px solid var(--border); }
|
|
424
|
+
.networkfyi-compat-status { font-size:13px; font-weight:700; margin-bottom:3px; }
|
|
425
|
+
.networkfyi-compat-detail { font-size:11px; color:var(--muted); }
|
|
426
|
+
|
|
427
|
+
/* Domain: scenario card */
|
|
428
|
+
.networkfyi-scenario-header { padding:10px 16px; border-bottom:1px solid var(--border); }
|
|
429
|
+
.networkfyi-scenario-title { font-size:13px; font-weight:700; color:var(--text); margin:0 0 5px 0; }
|
|
430
|
+
.networkfyi-scenario-meta { display:flex; gap:5px; align-items:center; flex-wrap:wrap; }
|
|
431
|
+
|
|
432
|
+
/* Domain: form inputs (compatibility tool) */
|
|
433
|
+
.networkfyi-tool-form { padding:10px 16px; border-bottom:1px solid var(--border); }
|
|
434
|
+
.networkfyi-tool-row { display:flex; gap:6px; align-items:center; margin-bottom:5px; }
|
|
435
|
+
.networkfyi-tool-row:last-child { margin-bottom:0; }
|
|
436
|
+
.networkfyi-tool-input { flex:1; padding:5px 8px; border:1px solid var(--input-border); border-radius:4px; background:var(--input-bg); color:var(--text); font-size:12px; font-family:inherit; outline:none; }
|
|
437
|
+
.networkfyi-tool-input:focus { border-color:var(--input-focus); box-shadow:0 0 0 2px color-mix(in srgb, var(--input-focus) 20%, transparent); }
|
|
438
|
+
.networkfyi-tool-label { font-size:10px; color:var(--muted); min-width:64px; }
|
|
439
|
+
.networkfyi-tool-btn { background:var(--accent); color:#fff; border:none; border-radius:4px; padding:6px 12px; font-size:12px; font-weight:500; cursor:pointer; font-family:inherit; transition:opacity 0.15s; }
|
|
440
|
+
.networkfyi-tool-btn:hover { opacity:0.9; }
|
|
441
|
+
|
|
442
|
+
/* Clean: copy button \u2014 minimal style */
|
|
443
|
+
.networkfyi-copy-btn {
|
|
444
|
+
background: var(--surface);
|
|
445
|
+
color: var(--muted);
|
|
446
|
+
border: 1px solid var(--border);
|
|
447
|
+
border-radius: 4px;
|
|
448
|
+
padding: 3px 8px;
|
|
449
|
+
font-size: 11px;
|
|
450
|
+
cursor: pointer;
|
|
451
|
+
display: inline-flex;
|
|
452
|
+
align-items: center;
|
|
453
|
+
gap: 3px;
|
|
454
|
+
transition: all 0.15s;
|
|
455
|
+
font-family: inherit;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.networkfyi-copy-btn:hover {
|
|
459
|
+
background: var(--copy-bg);
|
|
460
|
+
border-color: var(--input-focus);
|
|
461
|
+
color: var(--text);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
.networkfyi-copy-btn svg {
|
|
465
|
+
width: 10px;
|
|
466
|
+
height: 10px;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/* Inline widget host */
|
|
470
|
+
:host([data-inline]) {
|
|
471
|
+
display: inline-flex;
|
|
472
|
+
align-items: center;
|
|
473
|
+
gap: 4px;
|
|
474
|
+
}
|
|
475
|
+
`;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// src/themes.ts
|
|
479
|
+
function getStyleCSS(style) {
|
|
480
|
+
switch (style) {
|
|
481
|
+
case "clean":
|
|
482
|
+
return getCleanCSS();
|
|
483
|
+
case "modern":
|
|
484
|
+
default:
|
|
485
|
+
return getModernCSS();
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
function getThemeCSS(accent, style = "modern") {
|
|
489
|
+
return `
|
|
490
|
+
:host {
|
|
491
|
+
display: block;
|
|
492
|
+
--site-accent: ${accent};
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
496
|
+
Size variants
|
|
497
|
+
compact=280px, default=420px, large=720px
|
|
498
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
499
|
+
.networkfyi-widget {
|
|
500
|
+
box-sizing: border-box;
|
|
501
|
+
min-width: 240px;
|
|
502
|
+
max-width: 420px;
|
|
503
|
+
border-radius: 8px;
|
|
504
|
+
overflow: hidden;
|
|
505
|
+
border: 1px solid var(--border);
|
|
506
|
+
background: var(--bg);
|
|
507
|
+
color: var(--text);
|
|
508
|
+
font-size: 14px;
|
|
509
|
+
line-height: 1.6;
|
|
510
|
+
transition: border-color 0.2s;
|
|
511
|
+
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.networkfyi-widget:hover {
|
|
515
|
+
border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
.networkfyi-widget[data-size="compact"] {
|
|
519
|
+
max-width: 280px;
|
|
520
|
+
font-size: 13px;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
.networkfyi-widget[data-size="default"] {
|
|
524
|
+
max-width: 420px;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.networkfyi-widget[data-size="large"] {
|
|
528
|
+
max-width: 720px;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
532
|
+
Light theme (default)
|
|
533
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
534
|
+
.networkfyi-widget[data-theme="light"] {
|
|
535
|
+
--bg: #fff;
|
|
536
|
+
--text: #1e293b;
|
|
537
|
+
--border: #e2e8f0;
|
|
538
|
+
--accent: var(--site-accent);
|
|
539
|
+
--muted: #64748b;
|
|
540
|
+
--surface: #f8fafc;
|
|
541
|
+
--badge-bg: #f1f5f9;
|
|
542
|
+
--badge-text: #374151;
|
|
543
|
+
--link: var(--site-accent);
|
|
544
|
+
--copy-bg: #f3f4f6;
|
|
545
|
+
--copy-hover: #e5e7eb;
|
|
546
|
+
--input-bg: #ffffff;
|
|
547
|
+
--input-border: #d1d5db;
|
|
548
|
+
--input-focus: var(--site-accent);
|
|
549
|
+
--shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
553
|
+
Dark theme
|
|
554
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
555
|
+
.networkfyi-widget[data-theme="dark"] {
|
|
556
|
+
--bg: #1a1a1a;
|
|
557
|
+
--text: #f3f4f6;
|
|
558
|
+
--border: #374151;
|
|
559
|
+
--accent: var(--site-accent);
|
|
560
|
+
--muted: #9ca3af;
|
|
561
|
+
--surface: #111827;
|
|
562
|
+
--badge-bg: #374151;
|
|
563
|
+
--badge-text: #d1d5db;
|
|
564
|
+
--link: color-mix(in srgb, var(--site-accent) 80%, #fff);
|
|
565
|
+
--copy-bg: #374151;
|
|
566
|
+
--copy-hover: #4b5563;
|
|
567
|
+
--input-bg: #111111;
|
|
568
|
+
--input-border: #4b5563;
|
|
569
|
+
--input-focus: var(--site-accent);
|
|
570
|
+
--shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
574
|
+
Sepia theme
|
|
575
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
576
|
+
.networkfyi-widget[data-theme="sepia"] {
|
|
577
|
+
--bg: #f5f0e8;
|
|
578
|
+
--text: #3d3529;
|
|
579
|
+
--border: #d4c5a9;
|
|
580
|
+
--accent: var(--site-accent);
|
|
581
|
+
--muted: #8b7d6b;
|
|
582
|
+
--surface: #ede8df;
|
|
583
|
+
--badge-bg: #e8e0d0;
|
|
584
|
+
--badge-text: #5c4f3d;
|
|
585
|
+
--link: color-mix(in srgb, var(--site-accent) 70%, #3d3529);
|
|
586
|
+
--copy-bg: #e8e0d0;
|
|
587
|
+
--copy-hover: #ddd4c0;
|
|
588
|
+
--input-bg: #f5f0e8;
|
|
589
|
+
--input-border: #c4b49a;
|
|
590
|
+
--input-focus: var(--site-accent);
|
|
591
|
+
--shadow: 0 1px 3px rgba(61, 53, 41, 0.12);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.networkfyi-widget *, .networkfyi-widget *::before, .networkfyi-widget *::after {
|
|
595
|
+
box-sizing: border-box;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
599
|
+
Loading state
|
|
600
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
601
|
+
.networkfyi-loading {
|
|
602
|
+
padding: 20px 16px;
|
|
603
|
+
text-align: center;
|
|
604
|
+
color: var(--muted);
|
|
605
|
+
font-size: 13px;
|
|
606
|
+
display: flex;
|
|
607
|
+
align-items: center;
|
|
608
|
+
justify-content: center;
|
|
609
|
+
gap: 8px;
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
.networkfyi-spinner {
|
|
613
|
+
width: 16px;
|
|
614
|
+
height: 16px;
|
|
615
|
+
border: 2px solid var(--border);
|
|
616
|
+
border-top-color: var(--accent);
|
|
617
|
+
border-radius: 50%;
|
|
618
|
+
animation: networkfyi-spin 0.7s linear infinite;
|
|
619
|
+
display: inline-block;
|
|
620
|
+
flex-shrink: 0;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
@keyframes networkfyi-spin {
|
|
624
|
+
to { transform: rotate(360deg); }
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
628
|
+
Error state
|
|
629
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
630
|
+
.networkfyi-error {
|
|
631
|
+
padding: 16px;
|
|
632
|
+
color: var(--muted);
|
|
633
|
+
font-size: 13px;
|
|
634
|
+
text-align: center;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
.networkfyi-error p {
|
|
638
|
+
margin: 0 0 8px 0;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
.networkfyi-error a {
|
|
642
|
+
color: var(--link);
|
|
643
|
+
text-decoration: none;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
.networkfyi-error a:hover {
|
|
647
|
+
text-decoration: underline;
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
651
|
+
Badge (generic)
|
|
652
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
653
|
+
.networkfyi-badge {
|
|
654
|
+
display: inline-block;
|
|
655
|
+
font-size: 10px;
|
|
656
|
+
font-weight: 600;
|
|
657
|
+
padding: 2px 7px;
|
|
658
|
+
border-radius: 4px;
|
|
659
|
+
background: var(--badge-bg);
|
|
660
|
+
color: var(--badge-text);
|
|
661
|
+
text-transform: uppercase;
|
|
662
|
+
letter-spacing: 0.04em;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
666
|
+
Search inputs
|
|
667
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
668
|
+
.networkfyi-search-wrap {
|
|
669
|
+
padding: 12px 16px;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
.networkfyi-search-form {
|
|
673
|
+
display: flex;
|
|
674
|
+
gap: 8px;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
.networkfyi-search-input {
|
|
678
|
+
flex: 1;
|
|
679
|
+
padding: 8px 12px;
|
|
680
|
+
border: 1px solid var(--input-border);
|
|
681
|
+
border-radius: 6px;
|
|
682
|
+
background: var(--input-bg);
|
|
683
|
+
color: var(--text);
|
|
684
|
+
font-size: 13px;
|
|
685
|
+
font-family: inherit;
|
|
686
|
+
outline: none;
|
|
687
|
+
transition: border-color 0.15s;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
.networkfyi-search-input:focus {
|
|
691
|
+
border-color: var(--input-focus);
|
|
692
|
+
box-shadow: 0 0 0 2px color-mix(in srgb, var(--input-focus) 20%, transparent);
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.networkfyi-search-input::placeholder {
|
|
696
|
+
color: var(--muted);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
.networkfyi-search-btn {
|
|
700
|
+
background: var(--accent);
|
|
701
|
+
color: #fff;
|
|
702
|
+
border: none;
|
|
703
|
+
border-radius: 6px;
|
|
704
|
+
padding: 8px 14px;
|
|
705
|
+
font-size: 13px;
|
|
706
|
+
font-weight: 500;
|
|
707
|
+
cursor: pointer;
|
|
708
|
+
font-family: inherit;
|
|
709
|
+
transition: opacity 0.15s;
|
|
710
|
+
white-space: nowrap;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.networkfyi-search-btn:hover {
|
|
714
|
+
opacity: 0.9;
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
.networkfyi-search-results {
|
|
718
|
+
padding: 0 16px 12px;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
.networkfyi-result-item {
|
|
722
|
+
padding: 8px 0;
|
|
723
|
+
border-bottom: 1px solid var(--border);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
.networkfyi-result-item:last-child {
|
|
727
|
+
border-bottom: none;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.networkfyi-result-title {
|
|
731
|
+
font-size: 13px;
|
|
732
|
+
font-weight: 600;
|
|
733
|
+
color: var(--text);
|
|
734
|
+
margin: 0 0 3px 0;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.networkfyi-result-meta {
|
|
738
|
+
font-size: 11px;
|
|
739
|
+
color: var(--muted);
|
|
740
|
+
display: flex;
|
|
741
|
+
align-items: center;
|
|
742
|
+
gap: 6px;
|
|
743
|
+
flex-wrap: wrap;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
747
|
+
Powered by footer
|
|
748
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
749
|
+
.networkfyi-powered {
|
|
750
|
+
display: block;
|
|
751
|
+
text-align: center;
|
|
752
|
+
padding: 8px 16px;
|
|
753
|
+
font-size: 11px;
|
|
754
|
+
color: var(--muted);
|
|
755
|
+
border-top: 1px solid var(--border);
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.networkfyi-powered a {
|
|
759
|
+
color: var(--link);
|
|
760
|
+
text-decoration: none;
|
|
761
|
+
font-weight: 500;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.networkfyi-powered a:hover {
|
|
765
|
+
text-decoration: underline;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
769
|
+
Copy button
|
|
770
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
771
|
+
.networkfyi-copy-btn {
|
|
772
|
+
background: var(--copy-bg);
|
|
773
|
+
color: var(--text);
|
|
774
|
+
border: none;
|
|
775
|
+
border-radius: 5px;
|
|
776
|
+
padding: 4px 9px;
|
|
777
|
+
font-size: 11px;
|
|
778
|
+
cursor: pointer;
|
|
779
|
+
display: inline-flex;
|
|
780
|
+
align-items: center;
|
|
781
|
+
gap: 4px;
|
|
782
|
+
transition: background 0.15s;
|
|
783
|
+
font-family: inherit;
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.networkfyi-copy-btn:hover {
|
|
787
|
+
background: var(--copy-hover);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.networkfyi-copy-btn svg {
|
|
791
|
+
width: 11px;
|
|
792
|
+
height: 11px;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
796
|
+
Monospace (for values, codes, IPs)
|
|
797
|
+
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
798
|
+
.networkfyi-mono {
|
|
799
|
+
font-family: ui-monospace, 'SF Mono', 'Cascadia Code', 'Consolas', monospace;
|
|
800
|
+
font-size: 13px;
|
|
801
|
+
}
|
|
802
|
+
|
|
803
|
+
${getStyleCSS(style)}
|
|
804
|
+
`;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// src/shadow.ts
|
|
808
|
+
function createShadow(el, config) {
|
|
809
|
+
const widgetStyle = el.dataset.styleVariant || "modern";
|
|
810
|
+
const shadow = el.attachShadow({ mode: "open" });
|
|
811
|
+
const style = document.createElement("style");
|
|
812
|
+
style.textContent = getThemeCSS(config.accent, widgetStyle);
|
|
813
|
+
shadow.appendChild(style);
|
|
814
|
+
return shadow;
|
|
815
|
+
}
|
|
816
|
+
function resolveTheme(el) {
|
|
817
|
+
const raw = el.dataset.theme || "light";
|
|
818
|
+
if (raw === "auto") {
|
|
819
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
820
|
+
}
|
|
821
|
+
return raw;
|
|
822
|
+
}
|
|
823
|
+
function createWidgetRoot(shadow, el, extraClass) {
|
|
824
|
+
const theme = resolveTheme(el);
|
|
825
|
+
const size = el.dataset.size || "default";
|
|
826
|
+
const div = document.createElement("div");
|
|
827
|
+
div.className = ["networkfyi-widget", extraClass].filter(Boolean).join(" ");
|
|
828
|
+
div.setAttribute("data-theme", theme);
|
|
829
|
+
div.setAttribute("data-size", size);
|
|
830
|
+
shadow.appendChild(div);
|
|
831
|
+
if (el.dataset.theme === "auto") {
|
|
832
|
+
window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change", (e) => {
|
|
833
|
+
div.setAttribute("data-theme", e.matches ? "dark" : "light");
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
return div;
|
|
837
|
+
}
|
|
838
|
+
function renderLoading(container) {
|
|
839
|
+
container.innerHTML = `
|
|
840
|
+
<div class="networkfyi-loading">
|
|
841
|
+
<span class="networkfyi-spinner"></span>
|
|
842
|
+
Loading\u2026
|
|
843
|
+
</div>
|
|
844
|
+
`;
|
|
845
|
+
}
|
|
846
|
+
function renderError(container, message, config) {
|
|
847
|
+
container.innerHTML = `
|
|
848
|
+
<div class="networkfyi-error">
|
|
849
|
+
<p>${message}</p>
|
|
850
|
+
<a href="https://${config.domain}" target="_blank" rel="noopener">
|
|
851
|
+
Visit ${config.name}
|
|
852
|
+
</a>
|
|
853
|
+
</div>
|
|
854
|
+
`;
|
|
855
|
+
}
|
|
856
|
+
var externalLinkIcon = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15 3 21 3 21 9"/><line x1="10" y1="14" x2="21" y2="3"/></svg>`;
|
|
857
|
+
function poweredByHTML(config) {
|
|
858
|
+
return `<span class="networkfyi-powered">Powered by <a href="https://${config.domain}" target="_blank" rel="noopener">${config.name}</a></span>`;
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
// src/api.ts
|
|
862
|
+
var CACHE_TTL_MS = 5 * 60 * 1e3;
|
|
863
|
+
function cacheKey(url) {
|
|
864
|
+
return `networkfyi_embed_${url}`;
|
|
865
|
+
}
|
|
866
|
+
function getFromCache(url) {
|
|
867
|
+
try {
|
|
868
|
+
const raw = sessionStorage.getItem(cacheKey(url));
|
|
869
|
+
if (!raw) return null;
|
|
870
|
+
const entry = JSON.parse(raw);
|
|
871
|
+
if (Date.now() - entry.ts > CACHE_TTL_MS) {
|
|
872
|
+
sessionStorage.removeItem(cacheKey(url));
|
|
873
|
+
return null;
|
|
874
|
+
}
|
|
875
|
+
return entry.data;
|
|
876
|
+
} catch (e) {
|
|
877
|
+
return null;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function setInCache(url, data) {
|
|
881
|
+
try {
|
|
882
|
+
const entry = { data, ts: Date.now() };
|
|
883
|
+
sessionStorage.setItem(cacheKey(url), JSON.stringify(entry));
|
|
884
|
+
} catch (e) {
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
async function fetchAPI(baseUrl, path, params) {
|
|
888
|
+
const base = baseUrl.endsWith("/") ? baseUrl : baseUrl + "/";
|
|
889
|
+
const relativePath = path.startsWith("/") ? path.slice(1) : path;
|
|
890
|
+
const url = new URL(relativePath, base);
|
|
891
|
+
if (params) {
|
|
892
|
+
Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
|
|
893
|
+
}
|
|
894
|
+
const urlStr = url.toString();
|
|
895
|
+
const cached = getFromCache(urlStr);
|
|
896
|
+
if (cached !== null) return cached;
|
|
897
|
+
const response = await fetch(urlStr, {
|
|
898
|
+
headers: { Accept: "application/json" }
|
|
899
|
+
});
|
|
900
|
+
if (!response.ok) {
|
|
901
|
+
throw new Error(`API error ${response.status}: ${urlStr}`);
|
|
902
|
+
}
|
|
903
|
+
const data = await response.json();
|
|
904
|
+
setInCache(urlStr, data);
|
|
905
|
+
return data;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// src/cards/shared.ts
|
|
909
|
+
function esc(s) {
|
|
910
|
+
if (!s) return "";
|
|
911
|
+
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
912
|
+
}
|
|
913
|
+
function kvRow(label, value) {
|
|
914
|
+
if (value === null || value === void 0 || value === "") return "";
|
|
915
|
+
return `<div class="networkfyi-kv-row"><span class="networkfyi-kv-label">${esc(label)}</span><span class="networkfyi-kv-value">${esc(String(value))}</span></div>`;
|
|
916
|
+
}
|
|
917
|
+
function badge(text, bg, fg = "#fff") {
|
|
918
|
+
return `<span class="networkfyi-badge" style="background:${bg};color:${fg}">${esc(text)}</span>`;
|
|
919
|
+
}
|
|
920
|
+
function renderGlossaryCard(data, config) {
|
|
921
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
922
|
+
const name = String((_c = (_b = (_a = data.name) != null ? _a : data.term) != null ? _b : data.slug) != null ? _c : "");
|
|
923
|
+
const definition = String((_d = data.definition) != null ? _d : "");
|
|
924
|
+
const extended = String((_f = (_e = data.extended_definition) != null ? _e : data.extended_description) != null ? _f : "");
|
|
925
|
+
const categoryLabel2 = String((_h = (_g = data.category_name) != null ? _g : data.category) != null ? _h : "");
|
|
926
|
+
const slug = String((_i = data.slug) != null ? _i : "");
|
|
927
|
+
const glossaryBase = config.site === "cablefyi" ? "terms" : "glossary";
|
|
928
|
+
const termUrl = `https://${config.domain}/${glossaryBase}/${esc(slug)}/`;
|
|
929
|
+
const glossaryUrl = `https://${config.domain}/glossary/`;
|
|
930
|
+
const relatedTerms = data.related_terms;
|
|
931
|
+
const relatedPills = relatedTerms && relatedTerms.length > 0 ? `<div class="networkfyi-pills">${relatedTerms.map(
|
|
932
|
+
(rt) => `<a class="networkfyi-pill" href="https://${config.domain}/${glossaryBase}/${esc(rt.slug)}/" target="_blank" rel="noopener" style="text-decoration:none;color:inherit;">${esc(rt.name)}</a>`
|
|
933
|
+
).join("")}</div>` : "";
|
|
934
|
+
return `
|
|
935
|
+
<div class="networkfyi-header">
|
|
936
|
+
<div>
|
|
937
|
+
<div class="networkfyi-header-title">${esc(name)}</div>
|
|
938
|
+
${categoryLabel2 ? `<span class="networkfyi-badge" style="background:${config.accent};color:#fff;margin-top:4px;display:inline-block;">${esc(categoryLabel2)}</span>` : ""}
|
|
939
|
+
</div>
|
|
940
|
+
</div>
|
|
941
|
+
<div class="networkfyi-body" style="font-size:0.9rem;line-height:1.5;">
|
|
942
|
+
${esc(definition)}
|
|
943
|
+
</div>
|
|
944
|
+
${extended ? `<div style="padding:0 18px 10px;font-size:0.85rem;color:var(--muted);line-height:1.5;">${esc(extended)}</div>` : ""}
|
|
945
|
+
${relatedPills}
|
|
946
|
+
<div class="networkfyi-view-link"><a href="${termUrl}" target="_blank" rel="noopener">${esc(name)} ${externalLinkIcon}</a></div>
|
|
947
|
+
<div class="networkfyi-view-link"><a href="${glossaryUrl}" target="_blank" rel="noopener">Full glossary on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
948
|
+
${poweredByHTML(config)}
|
|
949
|
+
`;
|
|
950
|
+
}
|
|
951
|
+
function renderFAQCard(faqs, config) {
|
|
952
|
+
if (!faqs || !faqs.length) return `<div class="networkfyi-body">No FAQs available.</div>${poweredByHTML(config)}`;
|
|
953
|
+
const items = faqs.map(
|
|
954
|
+
(faq) => `
|
|
955
|
+
<details class="networkfyi-faq-item" style="border-bottom:1px solid var(--border);padding:10px 18px;">
|
|
956
|
+
<summary style="cursor:pointer;font-size:0.9rem;font-weight:600;color:var(--text);list-style:none;display:flex;justify-content:space-between;align-items:center;">
|
|
957
|
+
${esc(faq.question)}
|
|
958
|
+
<span style="flex-shrink:0;margin-left:8px;font-size:0.75rem;color:var(--muted);">+</span>
|
|
959
|
+
</summary>
|
|
960
|
+
<div style="margin-top:8px;font-size:0.85rem;color:var(--muted);line-height:1.5;">
|
|
961
|
+
${esc(faq.answer)}
|
|
962
|
+
</div>
|
|
963
|
+
</details>
|
|
964
|
+
`
|
|
965
|
+
).join("");
|
|
966
|
+
return `
|
|
967
|
+
<div class="networkfyi-header">
|
|
968
|
+
<div>
|
|
969
|
+
<div class="networkfyi-header-title">Frequently Asked Questions</div>
|
|
970
|
+
<div class="networkfyi-header-subtitle">${faqs.length} questions</div>
|
|
971
|
+
</div>
|
|
972
|
+
</div>
|
|
973
|
+
${items}
|
|
974
|
+
${poweredByHTML(config)}
|
|
975
|
+
`;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
// src/cards/cable.ts
|
|
979
|
+
function renderCableCard(data, config) {
|
|
980
|
+
var _a, _b, _c, _d, _e, _f;
|
|
981
|
+
const name = String((_a = data.name) != null ? _a : "");
|
|
982
|
+
const slug = String((_b = data.slug) != null ? _b : "");
|
|
983
|
+
const description = String((_c = data.description) != null ? _c : "");
|
|
984
|
+
const connA = String((_d = data.connector_a) != null ? _d : "");
|
|
985
|
+
const connB = String((_e = data.connector_b) != null ? _e : "");
|
|
986
|
+
const maxRate = data.max_data_rate_gbps;
|
|
987
|
+
const maxRes = String((_f = data.max_video_resolution) != null ? _f : "");
|
|
988
|
+
const maxPower = data.max_power_delivery_watts;
|
|
989
|
+
const maxLen = data.max_recommended_length_m;
|
|
990
|
+
const standards = data.supported_standards;
|
|
991
|
+
const cableUrl = `https://${config.domain}/cables/${esc(slug)}/`;
|
|
992
|
+
const connectorDisplay = connA && connB ? `<div class="networkfyi-connector-arrow">
|
|
993
|
+
<span>${esc(connA)}</span>
|
|
994
|
+
<span class="networkfyi-connector-arrow-icon">\u2194</span>
|
|
995
|
+
<span>${esc(connB)}</span>
|
|
996
|
+
</div>` : "";
|
|
997
|
+
const standardsPills = standards && standards.length > 0 ? `<div class="networkfyi-pills">${standards.map((s) => `<span class="networkfyi-pill">${esc(s)}</span>`).join("")}</div>` : "";
|
|
998
|
+
return `
|
|
999
|
+
<div class="networkfyi-header">
|
|
1000
|
+
<div class="networkfyi-img">\u{1F50C}</div>
|
|
1001
|
+
<div>
|
|
1002
|
+
<div class="networkfyi-header-title">${esc(name)}</div>
|
|
1003
|
+
<div class="networkfyi-header-subtitle">Cable</div>
|
|
1004
|
+
</div>
|
|
1005
|
+
</div>
|
|
1006
|
+
${connectorDisplay}
|
|
1007
|
+
<div class="networkfyi-kv-rows">
|
|
1008
|
+
${maxRate !== null && maxRate !== void 0 ? kvRow("Max Data Rate", `${maxRate} Gbps`) : ""}
|
|
1009
|
+
${maxPower !== null && maxPower !== void 0 ? kvRow("Max Power", `${maxPower}W`) : ""}
|
|
1010
|
+
${maxRes ? kvRow("Max Resolution", maxRes) : ""}
|
|
1011
|
+
${maxLen !== null && maxLen !== void 0 ? kvRow("Max Length", `${maxLen}m`) : ""}
|
|
1012
|
+
</div>
|
|
1013
|
+
${description ? `<div class="networkfyi-desc">${esc(description.length > 200 ? description.slice(0, 200) + "..." : description)}</div>` : ""}
|
|
1014
|
+
${standardsPills}
|
|
1015
|
+
<div class="networkfyi-view-link"><a href="${cableUrl}" target="_blank" rel="noopener">View on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
1016
|
+
${poweredByHTML(config)}
|
|
1017
|
+
`;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
// src/compute/status.ts
|
|
1021
|
+
function statusCategory(code) {
|
|
1022
|
+
if (code >= 100 && code < 200) return "informational";
|
|
1023
|
+
if (code >= 200 && code < 300) return "success";
|
|
1024
|
+
if (code >= 300 && code < 400) return "redirection";
|
|
1025
|
+
if (code >= 400 && code < 500) return "client-error";
|
|
1026
|
+
if (code >= 500 && code < 600) return "server-error";
|
|
1027
|
+
return "unknown";
|
|
1028
|
+
}
|
|
1029
|
+
function categoryColor(category) {
|
|
1030
|
+
switch (category) {
|
|
1031
|
+
case "informational":
|
|
1032
|
+
return "#3B82F6";
|
|
1033
|
+
// blue
|
|
1034
|
+
case "success":
|
|
1035
|
+
return "#10B981";
|
|
1036
|
+
// green
|
|
1037
|
+
case "redirection":
|
|
1038
|
+
return "#F59E0B";
|
|
1039
|
+
// amber
|
|
1040
|
+
case "client-error":
|
|
1041
|
+
return "#EF4444";
|
|
1042
|
+
// red
|
|
1043
|
+
case "server-error":
|
|
1044
|
+
return "#7C3AED";
|
|
1045
|
+
// violet
|
|
1046
|
+
default:
|
|
1047
|
+
return "#6B7280";
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
function categoryLabel(category) {
|
|
1051
|
+
switch (category) {
|
|
1052
|
+
case "informational":
|
|
1053
|
+
return "Info";
|
|
1054
|
+
case "success":
|
|
1055
|
+
return "Success";
|
|
1056
|
+
case "redirection":
|
|
1057
|
+
return "Redirect";
|
|
1058
|
+
case "client-error":
|
|
1059
|
+
return "Client Error";
|
|
1060
|
+
case "server-error":
|
|
1061
|
+
return "Server Error";
|
|
1062
|
+
default:
|
|
1063
|
+
return "Unknown";
|
|
1064
|
+
}
|
|
1065
|
+
}
|
|
1066
|
+
var ASN_CATEGORY_COLORS = {
|
|
1067
|
+
cloud: "#3B82F6",
|
|
1068
|
+
isp: "#10B981",
|
|
1069
|
+
cdn: "#F59E0B",
|
|
1070
|
+
enterprise: "#6366F1",
|
|
1071
|
+
hosting: "#EC4899",
|
|
1072
|
+
exchange: "#14B8A6",
|
|
1073
|
+
education: "#8B5CF6",
|
|
1074
|
+
government: "#EF4444"
|
|
1075
|
+
};
|
|
1076
|
+
function asnCategoryColor(category) {
|
|
1077
|
+
return ASN_CATEGORY_COLORS[category.toLowerCase()] || "#6B7280";
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
// src/cards/asn.ts
|
|
1081
|
+
function renderASNCard(data, config) {
|
|
1082
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1083
|
+
const number = data.number;
|
|
1084
|
+
const name = String((_a = data.name) != null ? _a : "");
|
|
1085
|
+
const org = String((_b = data.org) != null ? _b : "");
|
|
1086
|
+
const countryCode = String((_c = data.country_code) != null ? _c : "");
|
|
1087
|
+
const category = String((_d = data.category) != null ? _d : "");
|
|
1088
|
+
const website = String((_e = data.website) != null ? _e : "");
|
|
1089
|
+
const description = String((_f = data.description) != null ? _f : "");
|
|
1090
|
+
const prefixCount = data.prefix_count;
|
|
1091
|
+
const asnUrl = `https://${config.domain}/asn/AS${number}/`;
|
|
1092
|
+
const catColor = asnCategoryColor(category);
|
|
1093
|
+
return `
|
|
1094
|
+
<div class="networkfyi-header">
|
|
1095
|
+
<div class="networkfyi-img" style="font-size:16px;">AS</div>
|
|
1096
|
+
<div>
|
|
1097
|
+
<div class="networkfyi-header-title">AS${esc(String(number))}</div>
|
|
1098
|
+
<div class="networkfyi-header-subtitle">${esc(name || org)}</div>
|
|
1099
|
+
</div>
|
|
1100
|
+
</div>
|
|
1101
|
+
<div class="networkfyi-stats-row">
|
|
1102
|
+
<div class="networkfyi-stat">
|
|
1103
|
+
<div class="networkfyi-stat-value">${esc(String(number))}</div>
|
|
1104
|
+
<div class="networkfyi-stat-label">ASN</div>
|
|
1105
|
+
</div>
|
|
1106
|
+
${prefixCount !== null && prefixCount !== void 0 ? `<div class="networkfyi-stat">
|
|
1107
|
+
<div class="networkfyi-stat-value">${prefixCount.toLocaleString()}</div>
|
|
1108
|
+
<div class="networkfyi-stat-label">Prefixes</div>
|
|
1109
|
+
</div>` : ""}
|
|
1110
|
+
${countryCode ? `<div class="networkfyi-stat">
|
|
1111
|
+
<div class="networkfyi-stat-value">${esc(countryCode)}</div>
|
|
1112
|
+
<div class="networkfyi-stat-label">Country</div>
|
|
1113
|
+
</div>` : ""}
|
|
1114
|
+
</div>
|
|
1115
|
+
<div class="networkfyi-kv-rows">
|
|
1116
|
+
${org ? kvRow("Organization", org) : ""}
|
|
1117
|
+
${category ? `<div class="networkfyi-kv-row"><span class="networkfyi-kv-label">Category</span><span class="networkfyi-kv-value">${badge(category, catColor)}</span></div>` : ""}
|
|
1118
|
+
${website ? kvRow("Website", website) : ""}
|
|
1119
|
+
</div>
|
|
1120
|
+
${description ? `<div class="networkfyi-desc">${esc(description.length > 200 ? description.slice(0, 200) + "..." : description)}</div>` : ""}
|
|
1121
|
+
<div class="networkfyi-view-link"><a href="${asnUrl}" target="_blank" rel="noopener">View on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
1122
|
+
${poweredByHTML(config)}
|
|
1123
|
+
`;
|
|
1124
|
+
}
|
|
1125
|
+
function renderISPCard(data, config) {
|
|
1126
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1127
|
+
const name = String((_a = data.name) != null ? _a : "");
|
|
1128
|
+
const slug = String((_b = data.slug) != null ? _b : "");
|
|
1129
|
+
const countryCode = String((_c = data.country_code) != null ? _c : "");
|
|
1130
|
+
const website = String((_d = data.website) != null ? _d : "");
|
|
1131
|
+
const description = String((_e = data.description) != null ? _e : "");
|
|
1132
|
+
const ispType = String((_f = data.isp_type) != null ? _f : "");
|
|
1133
|
+
const asnCount = data.asn_count;
|
|
1134
|
+
const ipBlockCount = data.ip_block_count;
|
|
1135
|
+
const ispUrl = `https://${config.domain}/isp/${esc(slug)}/`;
|
|
1136
|
+
return `
|
|
1137
|
+
<div class="networkfyi-header">
|
|
1138
|
+
<div class="networkfyi-img">\u{1F310}</div>
|
|
1139
|
+
<div>
|
|
1140
|
+
<div class="networkfyi-header-title">${esc(name)}</div>
|
|
1141
|
+
<div class="networkfyi-header-subtitle">${esc(ispType || "ISP")}</div>
|
|
1142
|
+
</div>
|
|
1143
|
+
</div>
|
|
1144
|
+
<div class="networkfyi-stats-row">
|
|
1145
|
+
${asnCount !== null && asnCount !== void 0 ? `<div class="networkfyi-stat">
|
|
1146
|
+
<div class="networkfyi-stat-value">${asnCount.toLocaleString()}</div>
|
|
1147
|
+
<div class="networkfyi-stat-label">ASNs</div>
|
|
1148
|
+
</div>` : ""}
|
|
1149
|
+
${ipBlockCount !== null && ipBlockCount !== void 0 ? `<div class="networkfyi-stat">
|
|
1150
|
+
<div class="networkfyi-stat-value">${ipBlockCount.toLocaleString()}</div>
|
|
1151
|
+
<div class="networkfyi-stat-label">IP Blocks</div>
|
|
1152
|
+
</div>` : ""}
|
|
1153
|
+
${countryCode ? `<div class="networkfyi-stat">
|
|
1154
|
+
<div class="networkfyi-stat-value">${esc(countryCode)}</div>
|
|
1155
|
+
<div class="networkfyi-stat-label">Country</div>
|
|
1156
|
+
</div>` : ""}
|
|
1157
|
+
</div>
|
|
1158
|
+
<div class="networkfyi-kv-rows">
|
|
1159
|
+
${ispType ? kvRow("Type", ispType) : ""}
|
|
1160
|
+
${website ? kvRow("Website", website) : ""}
|
|
1161
|
+
</div>
|
|
1162
|
+
${description ? `<div class="networkfyi-desc">${esc(description.length > 200 ? description.slice(0, 200) + "..." : description)}</div>` : ""}
|
|
1163
|
+
<div class="networkfyi-view-link"><a href="${ispUrl}" target="_blank" rel="noopener">View on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
1164
|
+
${poweredByHTML(config)}
|
|
1165
|
+
`;
|
|
1166
|
+
}
|
|
1167
|
+
function renderIPRangeCard(data, config) {
|
|
1168
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
1169
|
+
const slug = String((_a = data.slug) != null ? _a : "");
|
|
1170
|
+
const cidr = String((_b = data.cidr) != null ? _b : "");
|
|
1171
|
+
const networkAddr = String((_c = data.network_address) != null ? _c : "");
|
|
1172
|
+
const broadcastAddr = String((_d = data.broadcast_address) != null ? _d : "");
|
|
1173
|
+
const prefixLen = data.prefix_length;
|
|
1174
|
+
const hostCount = data.host_count;
|
|
1175
|
+
const version = data.version;
|
|
1176
|
+
const countryCode = String((_e = data.country_code) != null ? _e : "");
|
|
1177
|
+
const asnData = data.asn;
|
|
1178
|
+
const rangeUrl = `https://${config.domain}/ip-range/${esc(slug)}/`;
|
|
1179
|
+
const versionLabel = version === 4 ? "IPv4" : version === 6 ? "IPv6" : "";
|
|
1180
|
+
return `
|
|
1181
|
+
<div class="networkfyi-header">
|
|
1182
|
+
<div class="networkfyi-img" style="font-size:14px;">IP</div>
|
|
1183
|
+
<div>
|
|
1184
|
+
<div class="networkfyi-header-title networkfyi-mono">${esc(cidr)}</div>
|
|
1185
|
+
<div class="networkfyi-header-subtitle">${esc(versionLabel || "IP Range")}</div>
|
|
1186
|
+
</div>
|
|
1187
|
+
</div>
|
|
1188
|
+
<div class="networkfyi-kv-rows">
|
|
1189
|
+
${networkAddr ? kvRow("Network", networkAddr) : ""}
|
|
1190
|
+
${broadcastAddr ? kvRow("Broadcast", broadcastAddr) : ""}
|
|
1191
|
+
${prefixLen !== null && prefixLen !== void 0 ? kvRow("Prefix Length", `/${prefixLen}`) : ""}
|
|
1192
|
+
${hostCount !== null && hostCount !== void 0 ? kvRow("Host Count", hostCount.toLocaleString()) : ""}
|
|
1193
|
+
${versionLabel ? kvRow("Version", versionLabel) : ""}
|
|
1194
|
+
${countryCode ? kvRow("Country", countryCode) : ""}
|
|
1195
|
+
${asnData ? kvRow("ASN", `AS${String((_g = (_f = asnData.number) != null ? _f : asnData.name) != null ? _g : "")}`) : ""}
|
|
1196
|
+
</div>
|
|
1197
|
+
<div class="networkfyi-view-link"><a href="${rangeUrl}" target="_blank" rel="noopener">View on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
1198
|
+
${poweredByHTML(config)}
|
|
1199
|
+
`;
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
// src/cards/code.ts
|
|
1203
|
+
function renderStatusCodeCard(data, config) {
|
|
1204
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1205
|
+
const code = data.code;
|
|
1206
|
+
const name = String((_a = data.name) != null ? _a : "");
|
|
1207
|
+
const slug = String((_b = data.slug) != null ? _b : "");
|
|
1208
|
+
const description = String((_c = data.description) != null ? _c : "");
|
|
1209
|
+
const whenYouSeeIt = String((_d = data.when_you_see_it) != null ? _d : "");
|
|
1210
|
+
const protocol = data.protocol;
|
|
1211
|
+
const category = data.category;
|
|
1212
|
+
const relatedCodes = data.related_codes;
|
|
1213
|
+
const protocolName = protocol ? String((_e = protocol.name) != null ? _e : "") : "";
|
|
1214
|
+
const protocolSlug = protocol ? String((_f = protocol.slug) != null ? _f : "") : "";
|
|
1215
|
+
const cat = statusCategory(code);
|
|
1216
|
+
const color = categoryColor(cat);
|
|
1217
|
+
const catLabel = categoryLabel(cat);
|
|
1218
|
+
const codeUrl = protocolSlug ? `https://${config.domain}/${esc(protocolSlug)}/${esc(slug)}/` : `https://${config.domain}/codes/${esc(slug)}/`;
|
|
1219
|
+
return `
|
|
1220
|
+
<div class="networkfyi-header">
|
|
1221
|
+
<div class="networkfyi-img" style="background:${color};font-size:18px;">${code}</div>
|
|
1222
|
+
<div>
|
|
1223
|
+
<div class="networkfyi-header-title">${esc(name)}</div>
|
|
1224
|
+
<div class="networkfyi-header-subtitle">${esc(protocolName)} ${badge(catLabel, color)}</div>
|
|
1225
|
+
</div>
|
|
1226
|
+
</div>
|
|
1227
|
+
<div class="networkfyi-code-display">
|
|
1228
|
+
<div class="networkfyi-code-big" style="color:${color}">${code}</div>
|
|
1229
|
+
<div class="networkfyi-code-name">${esc(name)}</div>
|
|
1230
|
+
${protocolName ? `<div class="networkfyi-code-protocol">${esc(protocolName)}</div>` : ""}
|
|
1231
|
+
</div>
|
|
1232
|
+
${description ? `<div class="networkfyi-desc">${esc(description.length > 200 ? description.slice(0, 200) + "..." : description)}</div>` : ""}
|
|
1233
|
+
${whenYouSeeIt ? `<div style="padding:10px 18px;border-bottom:1px solid var(--border);">
|
|
1234
|
+
<div class="networkfyi-section-label">When You See It</div>
|
|
1235
|
+
<div style="font-size:0.85rem;color:var(--muted);line-height:1.5;">${esc(whenYouSeeIt.length > 150 ? whenYouSeeIt.slice(0, 150) + "..." : whenYouSeeIt)}</div>
|
|
1236
|
+
</div>` : ""}
|
|
1237
|
+
${relatedCodes && relatedCodes.length > 0 ? `<div class="networkfyi-pills">${relatedCodes.slice(0, 5).map((rc) => {
|
|
1238
|
+
var _a2;
|
|
1239
|
+
const rcCode = rc.code;
|
|
1240
|
+
const rcName = String((_a2 = rc.name) != null ? _a2 : "");
|
|
1241
|
+
const rcColor = categoryColor(statusCategory(rcCode));
|
|
1242
|
+
return badge(`${rcCode} ${rcName}`, rcColor);
|
|
1243
|
+
}).join(" ")}</div>` : ""}
|
|
1244
|
+
<div class="networkfyi-view-link"><a href="${codeUrl}" target="_blank" rel="noopener">View on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
1245
|
+
${poweredByHTML(config)}
|
|
1246
|
+
`;
|
|
1247
|
+
}
|
|
1248
|
+
|
|
1249
|
+
// src/widgets/entity.ts
|
|
1250
|
+
function getEntityPath(config, slug) {
|
|
1251
|
+
switch (config.site) {
|
|
1252
|
+
case "cablefyi":
|
|
1253
|
+
return `cable/${slug}/`;
|
|
1254
|
+
case "ipfyi":
|
|
1255
|
+
return `asn/${slug}/`;
|
|
1256
|
+
case "statuscodefyi":
|
|
1257
|
+
return `code/${slug}/`;
|
|
1258
|
+
default:
|
|
1259
|
+
return `${config.entitySlug}/${slug}/`;
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
function initEntityWidget(el, config) {
|
|
1263
|
+
var _a;
|
|
1264
|
+
const dataset = el.dataset;
|
|
1265
|
+
const slug = (_a = dataset.slug) != null ? _a : "";
|
|
1266
|
+
if (!slug) {
|
|
1267
|
+
const shadow2 = createShadow(el, config);
|
|
1268
|
+
const container2 = createWidgetRoot(shadow2, el, "networkfyi-entity-widget");
|
|
1269
|
+
renderError(container2, "Missing data-slug attribute.", config);
|
|
1270
|
+
return;
|
|
1271
|
+
}
|
|
1272
|
+
const shadow = createShadow(el, config);
|
|
1273
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-entity-widget");
|
|
1274
|
+
renderLoading(container);
|
|
1275
|
+
const path = getEntityPath(config, slug);
|
|
1276
|
+
fetchAPI(config.apiBase, path).then((data) => {
|
|
1277
|
+
var _a2;
|
|
1278
|
+
let html;
|
|
1279
|
+
switch (config.site) {
|
|
1280
|
+
case "cablefyi":
|
|
1281
|
+
html = renderCableCard(data, config);
|
|
1282
|
+
break;
|
|
1283
|
+
case "ipfyi":
|
|
1284
|
+
html = renderASNCard(data, config);
|
|
1285
|
+
break;
|
|
1286
|
+
case "statuscodefyi":
|
|
1287
|
+
html = renderStatusCodeCard(data, config);
|
|
1288
|
+
break;
|
|
1289
|
+
default: {
|
|
1290
|
+
const name = String((_a2 = data.name) != null ? _a2 : slug);
|
|
1291
|
+
const entityUrl = `https://${config.domain}/${config.entitySlug}/${esc(slug)}/`;
|
|
1292
|
+
html = `
|
|
1293
|
+
<div style="padding:16px;">
|
|
1294
|
+
<div style="font-size:1rem;font-weight:600;margin-bottom:8px;">${esc(name)}</div>
|
|
1295
|
+
<a href="${esc(entityUrl)}" target="_blank" rel="noopener"
|
|
1296
|
+
style="color:${config.accent};text-decoration:none;font-size:0.85rem;">
|
|
1297
|
+
View on ${esc(config.name)} ${externalLinkIcon}
|
|
1298
|
+
</a>
|
|
1299
|
+
</div>
|
|
1300
|
+
`;
|
|
1301
|
+
break;
|
|
1302
|
+
}
|
|
1303
|
+
}
|
|
1304
|
+
container.innerHTML = html;
|
|
1305
|
+
}).catch(() => {
|
|
1306
|
+
renderError(container, `Unable to load "${esc(slug)}". Please try again later.`, config);
|
|
1307
|
+
});
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// src/widgets/compare.ts
|
|
1311
|
+
function initCompareWidget(el, config) {
|
|
1312
|
+
var _a, _b;
|
|
1313
|
+
const dataset = el.dataset;
|
|
1314
|
+
const slugA = (_a = dataset.slugA) != null ? _a : "";
|
|
1315
|
+
const slugB = (_b = dataset.slugB) != null ? _b : "";
|
|
1316
|
+
if (!slugA || !slugB) {
|
|
1317
|
+
const shadow2 = createShadow(el, config);
|
|
1318
|
+
const container2 = createWidgetRoot(shadow2, el, "networkfyi-compare-widget");
|
|
1319
|
+
renderError(container2, "Missing data-slug-a and data-slug-b attributes.", config);
|
|
1320
|
+
return;
|
|
1321
|
+
}
|
|
1322
|
+
const shadow = createShadow(el, config);
|
|
1323
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-compare-widget");
|
|
1324
|
+
renderLoading(container);
|
|
1325
|
+
fetchAPI(config.apiBase, "compare/", { slug1: slugA, slug2: slugB }).then((data) => {
|
|
1326
|
+
var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
1327
|
+
const nameA = String((_b2 = (_a2 = data.name_a) != null ? _a2 : data.slug_a) != null ? _b2 : slugA);
|
|
1328
|
+
const nameB = String((_d = (_c = data.name_b) != null ? _c : data.slug_b) != null ? _d : slugB);
|
|
1329
|
+
const differences = data.differences;
|
|
1330
|
+
const summary = String((_e = data.summary) != null ? _e : "");
|
|
1331
|
+
const compareUrl = `https://${config.domain}/compare/?slug1=${encodeURIComponent(slugA)}&slug2=${encodeURIComponent(slugB)}`;
|
|
1332
|
+
let diffRows = "";
|
|
1333
|
+
if (differences && differences.length > 0) {
|
|
1334
|
+
diffRows = `<div class="networkfyi-kv-rows">`;
|
|
1335
|
+
for (const diff of differences.slice(0, 8)) {
|
|
1336
|
+
const label = String((_g = (_f = diff.field) != null ? _f : diff.label) != null ? _g : "");
|
|
1337
|
+
const valA = String((_i = (_h = diff.value_a) != null ? _h : diff.a) != null ? _i : "");
|
|
1338
|
+
const valB = String((_k = (_j = diff.value_b) != null ? _j : diff.b) != null ? _k : "");
|
|
1339
|
+
diffRows += `
|
|
1340
|
+
<div class="networkfyi-kv-row">
|
|
1341
|
+
<span class="networkfyi-kv-label">${esc(label)}</span>
|
|
1342
|
+
<span class="networkfyi-kv-value">${esc(valA)} vs ${esc(valB)}</span>
|
|
1343
|
+
</div>`;
|
|
1344
|
+
}
|
|
1345
|
+
diffRows += `</div>`;
|
|
1346
|
+
}
|
|
1347
|
+
container.innerHTML = `
|
|
1348
|
+
<div class="networkfyi-header">
|
|
1349
|
+
<div>
|
|
1350
|
+
<div class="networkfyi-header-title">${esc(nameA)} vs ${esc(nameB)}</div>
|
|
1351
|
+
<div class="networkfyi-header-subtitle">Comparison</div>
|
|
1352
|
+
</div>
|
|
1353
|
+
</div>
|
|
1354
|
+
<div class="networkfyi-stats-row">
|
|
1355
|
+
<div class="networkfyi-stat">
|
|
1356
|
+
<div class="networkfyi-stat-value" style="font-size:14px;">${esc(nameA)}</div>
|
|
1357
|
+
<div class="networkfyi-stat-label">A</div>
|
|
1358
|
+
</div>
|
|
1359
|
+
<div class="networkfyi-stat">
|
|
1360
|
+
<div class="networkfyi-stat-value" style="font-size:14px;">${esc(nameB)}</div>
|
|
1361
|
+
<div class="networkfyi-stat-label">B</div>
|
|
1362
|
+
</div>
|
|
1363
|
+
</div>
|
|
1364
|
+
${diffRows}
|
|
1365
|
+
${summary ? `<div class="networkfyi-desc">${esc(summary)}</div>` : ""}
|
|
1366
|
+
<div class="networkfyi-view-link"><a href="${esc(compareUrl)}" target="_blank" rel="noopener">Compare on ${esc(config.name)} ${externalLinkIcon}</a></div>
|
|
1367
|
+
${poweredByHTML(config)}
|
|
1368
|
+
`;
|
|
1369
|
+
}).catch(() => {
|
|
1370
|
+
renderError(container, "Unable to load comparison data.", config);
|
|
1371
|
+
});
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
// src/rich-snippets.ts
|
|
1375
|
+
function injectDefinedTerm(data, domain, siteName) {
|
|
1376
|
+
if (document.querySelector('script[data-networkfyi-snippet="term"]')) return;
|
|
1377
|
+
const jsonLd = {
|
|
1378
|
+
"@context": "https://schema.org",
|
|
1379
|
+
"@type": "DefinedTerm",
|
|
1380
|
+
name: data.name,
|
|
1381
|
+
description: data.definition,
|
|
1382
|
+
inDefinedTermSet: {
|
|
1383
|
+
"@type": "DefinedTermSet",
|
|
1384
|
+
name: `${siteName} Glossary`,
|
|
1385
|
+
url: `https://${domain}/glossary/`
|
|
1386
|
+
}
|
|
1387
|
+
};
|
|
1388
|
+
const script = document.createElement("script");
|
|
1389
|
+
script.type = "application/ld+json";
|
|
1390
|
+
script.setAttribute("data-networkfyi-snippet", "term");
|
|
1391
|
+
script.textContent = JSON.stringify(jsonLd);
|
|
1392
|
+
document.head.appendChild(script);
|
|
1393
|
+
}
|
|
1394
|
+
function injectFAQPage(faqs, domain, _siteName) {
|
|
1395
|
+
if (document.querySelector('script[data-networkfyi-snippet="faq"]')) return;
|
|
1396
|
+
const jsonLd = {
|
|
1397
|
+
"@context": "https://schema.org",
|
|
1398
|
+
"@type": "FAQPage",
|
|
1399
|
+
mainEntity: faqs.map((faq) => ({
|
|
1400
|
+
"@type": "Question",
|
|
1401
|
+
name: faq.question,
|
|
1402
|
+
acceptedAnswer: {
|
|
1403
|
+
"@type": "Answer",
|
|
1404
|
+
text: faq.answer
|
|
1405
|
+
}
|
|
1406
|
+
})),
|
|
1407
|
+
url: `https://${domain}/`
|
|
1408
|
+
};
|
|
1409
|
+
const script = document.createElement("script");
|
|
1410
|
+
script.type = "application/ld+json";
|
|
1411
|
+
script.setAttribute("data-networkfyi-snippet", "faq");
|
|
1412
|
+
script.textContent = JSON.stringify(jsonLd);
|
|
1413
|
+
document.head.appendChild(script);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/widgets/glossary.ts
|
|
1417
|
+
function initGlossaryWidget(el, config) {
|
|
1418
|
+
var _a;
|
|
1419
|
+
const dataset = el.dataset;
|
|
1420
|
+
const slug = (_a = dataset.slug) != null ? _a : "";
|
|
1421
|
+
if (!slug) {
|
|
1422
|
+
const shadow2 = createShadow(el, config);
|
|
1423
|
+
const container2 = createWidgetRoot(shadow2, el, "networkfyi-glossary-widget");
|
|
1424
|
+
renderError(container2, "Missing data-slug attribute.", config);
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
const shadow = createShadow(el, config);
|
|
1428
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-glossary-widget");
|
|
1429
|
+
renderLoading(container);
|
|
1430
|
+
const glossaryPath = `term/${slug}/`;
|
|
1431
|
+
fetchAPI(config.apiBase, glossaryPath).then((data) => {
|
|
1432
|
+
var _a2, _b, _c;
|
|
1433
|
+
container.innerHTML = renderGlossaryCard(data, config);
|
|
1434
|
+
if (el.dataset.noSnippet !== "true") {
|
|
1435
|
+
const name = String((_b = (_a2 = data.name) != null ? _a2 : data.term) != null ? _b : slug);
|
|
1436
|
+
const definition = String((_c = data.definition) != null ? _c : "");
|
|
1437
|
+
injectDefinedTerm({ name, definition }, config.domain, config.name);
|
|
1438
|
+
}
|
|
1439
|
+
}).catch(() => {
|
|
1440
|
+
renderError(
|
|
1441
|
+
container,
|
|
1442
|
+
`Unable to load glossary term "${esc(slug)}".`,
|
|
1443
|
+
config
|
|
1444
|
+
);
|
|
1445
|
+
});
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// src/widgets/search.ts
|
|
1449
|
+
var TYPE_LABELS = {
|
|
1450
|
+
cable: "Cable",
|
|
1451
|
+
connector: "Connector",
|
|
1452
|
+
standard: "Standard",
|
|
1453
|
+
asn: "ASN",
|
|
1454
|
+
isp: "ISP",
|
|
1455
|
+
"ip-range": "IP Range",
|
|
1456
|
+
code: "Status Code",
|
|
1457
|
+
protocol: "Protocol",
|
|
1458
|
+
scenario: "Scenario",
|
|
1459
|
+
spec: "Spec",
|
|
1460
|
+
glossary: "Glossary",
|
|
1461
|
+
term: "Glossary",
|
|
1462
|
+
guide: "Guide",
|
|
1463
|
+
faq: "FAQ"
|
|
1464
|
+
};
|
|
1465
|
+
var SEARCH_ICON = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="14" height="14"><circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/></svg>`;
|
|
1466
|
+
function initSearchWidget(el, config) {
|
|
1467
|
+
var _a;
|
|
1468
|
+
const dataset = el.dataset;
|
|
1469
|
+
const placeholder = (_a = dataset.placeholder) != null ? _a : `Search ${config.entityName}...`;
|
|
1470
|
+
const shadow = createShadow(el, config);
|
|
1471
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-search-widget");
|
|
1472
|
+
let isOpen = false;
|
|
1473
|
+
let query = "";
|
|
1474
|
+
let results = [];
|
|
1475
|
+
let selectedIndex = -1;
|
|
1476
|
+
let debounceTimer = null;
|
|
1477
|
+
container.innerHTML = `
|
|
1478
|
+
<div class="networkfyi-search-wrap">
|
|
1479
|
+
<div class="networkfyi-search-form" style="position:relative;display:flex;align-items:center;">
|
|
1480
|
+
<span style="position:absolute;left:10px;color:var(--muted);pointer-events:none;">${SEARCH_ICON}</span>
|
|
1481
|
+
<input
|
|
1482
|
+
class="networkfyi-search-input"
|
|
1483
|
+
type="search"
|
|
1484
|
+
autocomplete="off"
|
|
1485
|
+
spellcheck="false"
|
|
1486
|
+
placeholder="${esc(placeholder)}"
|
|
1487
|
+
aria-label="Search ${esc(config.name)}"
|
|
1488
|
+
aria-autocomplete="list"
|
|
1489
|
+
aria-expanded="false"
|
|
1490
|
+
role="combobox"
|
|
1491
|
+
style="padding-left:32px;"
|
|
1492
|
+
>
|
|
1493
|
+
</div>
|
|
1494
|
+
<div class="networkfyi-search-dropdown" role="listbox" hidden
|
|
1495
|
+
style="margin-top:4px;border:1px solid var(--border);border-radius:6px;background:var(--bg);box-shadow:var(--shadow);max-height:280px;overflow-y:auto;"></div>
|
|
1496
|
+
</div>
|
|
1497
|
+
${poweredByHTML(config)}
|
|
1498
|
+
`;
|
|
1499
|
+
const input = container.querySelector(".networkfyi-search-input");
|
|
1500
|
+
const dropdown = container.querySelector(".networkfyi-search-dropdown");
|
|
1501
|
+
function getAllItems() {
|
|
1502
|
+
return Array.from(dropdown.querySelectorAll(".networkfyi-result-item"));
|
|
1503
|
+
}
|
|
1504
|
+
function setSelected(idx) {
|
|
1505
|
+
const items = getAllItems();
|
|
1506
|
+
items.forEach((item, i) => {
|
|
1507
|
+
if (i === idx) {
|
|
1508
|
+
item.style.background = `color-mix(in srgb, ${config.accent} 10%, var(--bg))`;
|
|
1509
|
+
} else {
|
|
1510
|
+
item.style.background = "";
|
|
1511
|
+
}
|
|
1512
|
+
});
|
|
1513
|
+
selectedIndex = idx;
|
|
1514
|
+
}
|
|
1515
|
+
function openDropdown() {
|
|
1516
|
+
isOpen = true;
|
|
1517
|
+
dropdown.hidden = false;
|
|
1518
|
+
input.setAttribute("aria-expanded", "true");
|
|
1519
|
+
}
|
|
1520
|
+
function closeDropdown() {
|
|
1521
|
+
isOpen = false;
|
|
1522
|
+
dropdown.hidden = true;
|
|
1523
|
+
input.setAttribute("aria-expanded", "false");
|
|
1524
|
+
selectedIndex = -1;
|
|
1525
|
+
}
|
|
1526
|
+
function renderDropdown() {
|
|
1527
|
+
var _a2, _b, _c, _d;
|
|
1528
|
+
if (results.length === 0) {
|
|
1529
|
+
dropdown.innerHTML = `<div style="padding:12px 14px;font-size:0.85rem;color:var(--muted);">No results for <strong>${esc(query)}</strong></div>`;
|
|
1530
|
+
return;
|
|
1531
|
+
}
|
|
1532
|
+
let html = "";
|
|
1533
|
+
for (const item of results) {
|
|
1534
|
+
const typeLabel = item.type ? (_a2 = TYPE_LABELS[item.type]) != null ? _a2 : item.type : null;
|
|
1535
|
+
const itemDesc = (_d = (_c = (_b = item.description) != null ? _b : item.excerpt) != null ? _c : item.subtitle) != null ? _d : "";
|
|
1536
|
+
const href = item.url ? item.url.startsWith("http") ? item.url : `https://${config.domain}${item.url}` : `https://${config.domain}/${config.entitySlug}/${esc(item.slug || "")}/`;
|
|
1537
|
+
html += `
|
|
1538
|
+
<a class="networkfyi-result-item"
|
|
1539
|
+
href="${esc(href)}" target="_blank" rel="noopener" role="option" tabindex="-1"
|
|
1540
|
+
style="display:block;padding:8px 14px;text-decoration:none;color:var(--text);border-bottom:1px solid var(--border);transition:background 0.1s;">
|
|
1541
|
+
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;">
|
|
1542
|
+
<span style="font-size:0.875rem;font-weight:500;">${esc(item.name)}</span>
|
|
1543
|
+
${typeLabel ? `<span class="networkfyi-badge" style="flex-shrink:0;">${esc(typeLabel)}</span>` : ""}
|
|
1544
|
+
</div>
|
|
1545
|
+
${itemDesc ? `<div style="font-size:0.75rem;color:var(--muted);margin-top:2px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${esc(itemDesc)}</div>` : ""}
|
|
1546
|
+
</a>
|
|
1547
|
+
`;
|
|
1548
|
+
}
|
|
1549
|
+
dropdown.innerHTML = html;
|
|
1550
|
+
}
|
|
1551
|
+
async function doSearch(q) {
|
|
1552
|
+
var _a2;
|
|
1553
|
+
if (!q.trim()) {
|
|
1554
|
+
closeDropdown();
|
|
1555
|
+
return;
|
|
1556
|
+
}
|
|
1557
|
+
const searchUrl = `${config.apiBase}search/?q=${encodeURIComponent(q)}&limit=10`;
|
|
1558
|
+
try {
|
|
1559
|
+
const response = await fetch(searchUrl, { headers: { Accept: "application/json" } });
|
|
1560
|
+
if (!response.ok) throw new Error(`Search failed: ${response.status}`);
|
|
1561
|
+
const data = await response.json();
|
|
1562
|
+
results = (_a2 = data.results) != null ? _a2 : [];
|
|
1563
|
+
} catch (e) {
|
|
1564
|
+
results = [];
|
|
1565
|
+
}
|
|
1566
|
+
renderDropdown();
|
|
1567
|
+
openDropdown();
|
|
1568
|
+
setSelected(-1);
|
|
1569
|
+
}
|
|
1570
|
+
input.addEventListener("input", () => {
|
|
1571
|
+
query = input.value;
|
|
1572
|
+
if (debounceTimer !== null) clearTimeout(debounceTimer);
|
|
1573
|
+
if (!query.trim()) {
|
|
1574
|
+
closeDropdown();
|
|
1575
|
+
return;
|
|
1576
|
+
}
|
|
1577
|
+
debounceTimer = setTimeout(() => {
|
|
1578
|
+
void doSearch(query);
|
|
1579
|
+
}, 300);
|
|
1580
|
+
});
|
|
1581
|
+
input.addEventListener("keydown", (e) => {
|
|
1582
|
+
if (!isOpen) return;
|
|
1583
|
+
const items = getAllItems();
|
|
1584
|
+
const total = items.length;
|
|
1585
|
+
if (e.key === "ArrowDown") {
|
|
1586
|
+
e.preventDefault();
|
|
1587
|
+
setSelected(selectedIndex < total - 1 ? selectedIndex + 1 : 0);
|
|
1588
|
+
} else if (e.key === "ArrowUp") {
|
|
1589
|
+
e.preventDefault();
|
|
1590
|
+
setSelected(selectedIndex > 0 ? selectedIndex - 1 : total - 1);
|
|
1591
|
+
} else if (e.key === "Enter") {
|
|
1592
|
+
e.preventDefault();
|
|
1593
|
+
if (selectedIndex >= 0 && items[selectedIndex]) {
|
|
1594
|
+
items[selectedIndex].click();
|
|
1595
|
+
} else {
|
|
1596
|
+
window.open(`https://${config.domain}${config.searchPath}?q=${encodeURIComponent(query)}`, "_blank", "noopener");
|
|
1597
|
+
}
|
|
1598
|
+
} else if (e.key === "Escape") {
|
|
1599
|
+
closeDropdown();
|
|
1600
|
+
input.blur();
|
|
1601
|
+
}
|
|
1602
|
+
});
|
|
1603
|
+
document.addEventListener("click", (e) => {
|
|
1604
|
+
if (isOpen && !el.contains(e.target)) closeDropdown();
|
|
1605
|
+
});
|
|
1606
|
+
input.addEventListener("focus", () => {
|
|
1607
|
+
input.style.borderColor = config.accent;
|
|
1608
|
+
input.style.boxShadow = `0 0 0 2px color-mix(in srgb, ${config.accent} 20%, transparent)`;
|
|
1609
|
+
});
|
|
1610
|
+
input.addEventListener("blur", () => {
|
|
1611
|
+
input.style.borderColor = "";
|
|
1612
|
+
input.style.boxShadow = "";
|
|
1613
|
+
});
|
|
1614
|
+
}
|
|
1615
|
+
|
|
1616
|
+
// src/widgets/faq.ts
|
|
1617
|
+
function initFAQWidget(el, config) {
|
|
1618
|
+
var _a;
|
|
1619
|
+
const dataset = el.dataset;
|
|
1620
|
+
const slug = (_a = dataset.slug) != null ? _a : "";
|
|
1621
|
+
if (!slug) {
|
|
1622
|
+
const shadow2 = createShadow(el, config);
|
|
1623
|
+
const container2 = createWidgetRoot(shadow2, el, "networkfyi-faq-widget");
|
|
1624
|
+
renderError(container2, "Missing data-slug attribute.", config);
|
|
1625
|
+
return;
|
|
1626
|
+
}
|
|
1627
|
+
const shadow = createShadow(el, config);
|
|
1628
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-faq-widget");
|
|
1629
|
+
renderLoading(container);
|
|
1630
|
+
const faqPath = `faqs/?topic=${encodeURIComponent(slug)}`;
|
|
1631
|
+
fetchAPI(config.apiBase, faqPath).then((data) => {
|
|
1632
|
+
let faqs;
|
|
1633
|
+
if (data.faqs && Array.isArray(data.faqs)) {
|
|
1634
|
+
faqs = data.faqs;
|
|
1635
|
+
} else if (data.results && Array.isArray(data.results)) {
|
|
1636
|
+
faqs = data.results;
|
|
1637
|
+
} else if (data.question && data.answer) {
|
|
1638
|
+
faqs = [{ question: String(data.question), answer: String(data.answer) }];
|
|
1639
|
+
} else {
|
|
1640
|
+
faqs = [];
|
|
1641
|
+
}
|
|
1642
|
+
container.innerHTML = renderFAQCard(faqs, config);
|
|
1643
|
+
if (el.dataset.noSnippet !== "true" && faqs.length > 0) {
|
|
1644
|
+
injectFAQPage(faqs, config.domain, config.name);
|
|
1645
|
+
}
|
|
1646
|
+
}).catch(() => {
|
|
1647
|
+
renderError(container, `Unable to load FAQs for "${esc(slug)}".`, config);
|
|
1648
|
+
});
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
// src/tools/isp.ts
|
|
1652
|
+
function initISPTool(el, config) {
|
|
1653
|
+
var _a;
|
|
1654
|
+
const slug = (_a = el.dataset.slug) != null ? _a : "";
|
|
1655
|
+
if (!slug) {
|
|
1656
|
+
const shadow2 = createShadow(el, config);
|
|
1657
|
+
const container2 = createWidgetRoot(shadow2, el, "networkfyi-isp-widget");
|
|
1658
|
+
renderError(container2, "Missing data-slug attribute.", config);
|
|
1659
|
+
return;
|
|
1660
|
+
}
|
|
1661
|
+
const shadow = createShadow(el, config);
|
|
1662
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-isp-widget");
|
|
1663
|
+
renderLoading(container);
|
|
1664
|
+
fetchAPI(config.apiBase, `isp/${slug}/`).then((data) => {
|
|
1665
|
+
container.innerHTML = renderISPCard(data, config);
|
|
1666
|
+
}).catch(() => {
|
|
1667
|
+
renderError(container, `Unable to load ISP "${esc(slug)}".`, config);
|
|
1668
|
+
});
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// src/tools/ip-range.ts
|
|
1672
|
+
function initIPRangeTool(el, config) {
|
|
1673
|
+
var _a;
|
|
1674
|
+
const slug = (_a = el.dataset.slug) != null ? _a : "";
|
|
1675
|
+
if (!slug) {
|
|
1676
|
+
const shadow2 = createShadow(el, config);
|
|
1677
|
+
const container2 = createWidgetRoot(shadow2, el, "networkfyi-ip-range-widget");
|
|
1678
|
+
renderError(container2, "Missing data-slug attribute.", config);
|
|
1679
|
+
return;
|
|
1680
|
+
}
|
|
1681
|
+
const shadow = createShadow(el, config);
|
|
1682
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-ip-range-widget");
|
|
1683
|
+
renderLoading(container);
|
|
1684
|
+
fetchAPI(config.apiBase, `ip-range/${slug}/`).then((data) => {
|
|
1685
|
+
container.innerHTML = renderIPRangeCard(data, config);
|
|
1686
|
+
}).catch(() => {
|
|
1687
|
+
renderError(container, `Unable to load IP range "${esc(slug)}".`, config);
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
// src/inline/asn-badge.ts
|
|
1692
|
+
function initASNBadgeInline(el, config) {
|
|
1693
|
+
var _a, _b;
|
|
1694
|
+
const category = (_a = el.dataset.category) != null ? _a : "";
|
|
1695
|
+
const label = ((_b = el.textContent) == null ? void 0 : _b.trim()) || category;
|
|
1696
|
+
el.setAttribute("data-inline", "");
|
|
1697
|
+
const shadow = createShadow(el, config);
|
|
1698
|
+
const container = createWidgetRoot(shadow, el, "networkfyi-inline");
|
|
1699
|
+
container.setAttribute("data-theme", el.dataset.theme || "light");
|
|
1700
|
+
const color = asnCategoryColor(category);
|
|
1701
|
+
container.innerHTML = `
|
|
1702
|
+
<span class="networkfyi-badge" style="background:${color};color:#fff;font-size:11px;padding:2px 8px;">
|
|
1703
|
+
${esc(label)}
|
|
1704
|
+
</span>
|
|
1705
|
+
`;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
// src/_entry_ipfyi.ts
|
|
1709
|
+
function initWidget(el, type, config) {
|
|
1710
|
+
const widgetStyle = el.dataset.styleVariant || "modern";
|
|
1711
|
+
void widgetStyle;
|
|
1712
|
+
switch (type) {
|
|
1713
|
+
case "entity":
|
|
1714
|
+
initEntityWidget(el, config);
|
|
1715
|
+
break;
|
|
1716
|
+
case "compare":
|
|
1717
|
+
initCompareWidget(el, config);
|
|
1718
|
+
break;
|
|
1719
|
+
case "glossary":
|
|
1720
|
+
initGlossaryWidget(el, config);
|
|
1721
|
+
break;
|
|
1722
|
+
case "search":
|
|
1723
|
+
initSearchWidget(el, config);
|
|
1724
|
+
break;
|
|
1725
|
+
case "faq":
|
|
1726
|
+
initFAQWidget(el, config);
|
|
1727
|
+
break;
|
|
1728
|
+
case "isp":
|
|
1729
|
+
initISPTool(el, config);
|
|
1730
|
+
break;
|
|
1731
|
+
case "ip-range":
|
|
1732
|
+
initIPRangeTool(el, config);
|
|
1733
|
+
break;
|
|
1734
|
+
case "asn-badge":
|
|
1735
|
+
initASNBadgeInline(el, config);
|
|
1736
|
+
break;
|
|
1737
|
+
default:
|
|
1738
|
+
break;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
function lazyInit(el, callback) {
|
|
1742
|
+
if ("IntersectionObserver" in window) {
|
|
1743
|
+
const observer = new IntersectionObserver((entries) => {
|
|
1744
|
+
entries.forEach((entry) => {
|
|
1745
|
+
if (entry.isIntersecting) {
|
|
1746
|
+
observer.unobserve(el);
|
|
1747
|
+
callback();
|
|
1748
|
+
}
|
|
1749
|
+
});
|
|
1750
|
+
}, { rootMargin: "200px" });
|
|
1751
|
+
observer.observe(el);
|
|
1752
|
+
} else {
|
|
1753
|
+
callback();
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
function processElement(el, config) {
|
|
1757
|
+
if (el.shadowRoot) return;
|
|
1758
|
+
const dataKey = config.attribute.replace("data-", "");
|
|
1759
|
+
const camelKey = dataKey.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
1760
|
+
const widgetType = el.dataset[camelKey];
|
|
1761
|
+
if (!widgetType) return;
|
|
1762
|
+
lazyInit(el, () => {
|
|
1763
|
+
if (!el.shadowRoot) initWidget(el, widgetType, config);
|
|
1764
|
+
});
|
|
1765
|
+
}
|
|
1766
|
+
function initAll(config) {
|
|
1767
|
+
document.querySelectorAll(`[${config.attribute}]`).forEach((el) => processElement(el, config));
|
|
1768
|
+
}
|
|
1769
|
+
(function bootstrap() {
|
|
1770
|
+
const config = '{"site":"ipfyi","name":"IPFYI","domain":"ipfyi.com","accent":"#334155","attribute":"data-ipfyi","apiBase":"https://ipfyi.com/api/v1/","searchPath":"/search/","entityName":"Networks","entitySlug":"asn"}';
|
|
1771
|
+
if (document.readyState === "loading") {
|
|
1772
|
+
document.addEventListener("DOMContentLoaded", () => initAll(config));
|
|
1773
|
+
} else {
|
|
1774
|
+
initAll(config);
|
|
1775
|
+
}
|
|
1776
|
+
const observer = new MutationObserver((mutations) => {
|
|
1777
|
+
mutations.forEach((mutation) => {
|
|
1778
|
+
mutation.addedNodes.forEach((node) => {
|
|
1779
|
+
var _a;
|
|
1780
|
+
if (node.nodeType !== Node.ELEMENT_NODE) return;
|
|
1781
|
+
const el = node;
|
|
1782
|
+
if (el.hasAttribute(config.attribute)) processElement(el, config);
|
|
1783
|
+
(_a = el.querySelectorAll) == null ? void 0 : _a.call(el, `[${config.attribute}]`).forEach((child) => processElement(child, config));
|
|
1784
|
+
});
|
|
1785
|
+
});
|
|
1786
|
+
});
|
|
1787
|
+
observer.observe(document.body || document.documentElement, { childList: true, subtree: true });
|
|
1788
|
+
})();
|
|
1789
|
+
function makeWidgetElement(widgetType, initFn, domainAttrs) {
|
|
1790
|
+
const observed = [...domainAttrs, "theme", "style-variant", "size"];
|
|
1791
|
+
return class extends HTMLElement {
|
|
1792
|
+
static get observedAttributes() {
|
|
1793
|
+
return observed;
|
|
1794
|
+
}
|
|
1795
|
+
connectedCallback() {
|
|
1796
|
+
if (this.shadowRoot) return;
|
|
1797
|
+
this._syncDataAttrs();
|
|
1798
|
+
initFn(this, '{"site":"ipfyi","name":"IPFYI","domain":"ipfyi.com","accent":"#334155","attribute":"data-ipfyi","apiBase":"https://ipfyi.com/api/v1/","searchPath":"/search/","entityName":"Networks","entitySlug":"asn"}');
|
|
1799
|
+
}
|
|
1800
|
+
attributeChangedCallback(_name, oldVal, newVal) {
|
|
1801
|
+
if (oldVal === newVal || !this.shadowRoot) return;
|
|
1802
|
+
const shadow = this.shadowRoot;
|
|
1803
|
+
while (shadow.firstChild) shadow.firstChild.remove();
|
|
1804
|
+
this._syncDataAttrs();
|
|
1805
|
+
initFn(this, '{"site":"ipfyi","name":"IPFYI","domain":"ipfyi.com","accent":"#334155","attribute":"data-ipfyi","apiBase":"https://ipfyi.com/api/v1/","searchPath":"/search/","entityName":"Networks","entitySlug":"asn"}');
|
|
1806
|
+
}
|
|
1807
|
+
_syncDataAttrs() {
|
|
1808
|
+
const attrKey = '{"site":"ipfyi","name":"IPFYI","domain":"ipfyi.com","accent":"#334155","attribute":"data-ipfyi","apiBase":"https://ipfyi.com/api/v1/","searchPath":"/search/","entityName":"Networks","entitySlug":"asn"}'.attribute.replace("data-", "");
|
|
1809
|
+
this.dataset[attrKey] = widgetType;
|
|
1810
|
+
for (const a of domainAttrs) {
|
|
1811
|
+
const val = this.getAttribute(a);
|
|
1812
|
+
if (val !== null) this.dataset[a] = val;
|
|
1813
|
+
}
|
|
1814
|
+
const theme = this.getAttribute("theme");
|
|
1815
|
+
if (theme !== null) this.dataset.theme = theme;
|
|
1816
|
+
const styleVariant = this.getAttribute("style-variant");
|
|
1817
|
+
if (styleVariant !== null) this.dataset.styleVariant = styleVariant;
|
|
1818
|
+
const size = this.getAttribute("size");
|
|
1819
|
+
if (size !== null) this.dataset.size = size;
|
|
1820
|
+
}
|
|
1821
|
+
};
|
|
1822
|
+
}
|
|
1823
|
+
(function registerElements() {
|
|
1824
|
+
if (typeof customElements === "undefined") return;
|
|
1825
|
+
const site = '{"site":"ipfyi","name":"IPFYI","domain":"ipfyi.com","accent":"#334155","attribute":"data-ipfyi","apiBase":"https://ipfyi.com/api/v1/","searchPath":"/search/","entityName":"Networks","entitySlug":"asn"}'.site;
|
|
1826
|
+
const defs = [
|
|
1827
|
+
[`${site}-entity`, initEntityWidget, ["slug"]],
|
|
1828
|
+
[`${site}-compare`, initCompareWidget, ["slug-a", "slug-b"]],
|
|
1829
|
+
[`${site}-glossary`, initGlossaryWidget, ["slug"]],
|
|
1830
|
+
[`${site}-search`, initSearchWidget, ["placeholder"]],
|
|
1831
|
+
[`${site}-faq`, initFAQWidget, ["slug"]],
|
|
1832
|
+
[`${site}-isp`, initISPTool, ["slug"]],
|
|
1833
|
+
[`${site}-ip-range`, initIPRangeTool, ["slug"]]
|
|
1834
|
+
];
|
|
1835
|
+
for (const [tagName, initFn, attrs] of defs) {
|
|
1836
|
+
if (!customElements.get(tagName)) {
|
|
1837
|
+
const widgetType = tagName.slice(site.length + 1);
|
|
1838
|
+
customElements.define(tagName, makeWidgetElement(widgetType, initFn, attrs));
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
})();
|