planefyi-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 +192 -0
- package/dist/embed.esm.js +1385 -0
- package/dist/embed.min.js +546 -0
- package/dist/index.d.ts +27 -0
- package/package.json +43 -0
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
/* planefyi-embed v1.0.0 | MIT | https://widget.planefyi.com */
|
|
2
|
+
"use strict";(()=>{function tt(){return`
|
|
3
|
+
/* Modern: gradient accent header */
|
|
4
|
+
.transportfyi-header {
|
|
5
|
+
background: linear-gradient(135deg, var(--accent), color-mix(in srgb, var(--accent) 70%, #000));
|
|
6
|
+
border-radius: 12px 12px 0 0;
|
|
7
|
+
padding: 16px 20px;
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: flex-start;
|
|
10
|
+
gap: 14px;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
.transportfyi-header-title {
|
|
14
|
+
font-size: 15px; font-weight: 700; color: #fff; margin: 0 0 4px 0; line-height: 1.3;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
.transportfyi-header-subtitle {
|
|
18
|
+
font-size: 12px; color: rgba(255, 255, 255, 0.8); margin: 0;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.transportfyi-img {
|
|
22
|
+
width: 56px; height: 56px; border-radius: 8px; object-fit: cover;
|
|
23
|
+
background: rgba(255, 255, 255, 0.15); flex-shrink: 0;
|
|
24
|
+
display: flex; align-items: center; justify-content: center; overflow: hidden;
|
|
25
|
+
font-size: 24px; color: #fff; font-weight: 700;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.transportfyi-img img { width: 100%; height: 100%; object-fit: cover; border-radius: 8px; }
|
|
29
|
+
|
|
30
|
+
.transportfyi-body { padding: 16px 20px; }
|
|
31
|
+
|
|
32
|
+
/* Key-value rows */
|
|
33
|
+
.transportfyi-row {
|
|
34
|
+
display: flex; justify-content: space-between; align-items: flex-start; gap: 12px;
|
|
35
|
+
padding: 8px 0; border-bottom: 1px solid var(--border);
|
|
36
|
+
}
|
|
37
|
+
.transportfyi-row:last-child { border-bottom: none; }
|
|
38
|
+
|
|
39
|
+
.transportfyi-label { font-size: 12px; color: var(--muted); flex-shrink: 0; }
|
|
40
|
+
.transportfyi-value { font-size: 13px; font-weight: 600; color: var(--text); text-align: right; word-break: break-word; }
|
|
41
|
+
|
|
42
|
+
.transportfyi-kv-rows { padding: 4px 20px 8px; }
|
|
43
|
+
.transportfyi-kv-row {
|
|
44
|
+
display: flex; justify-content: space-between; padding: 6px 0;
|
|
45
|
+
border-bottom: 1px solid var(--border); font-size: 13px;
|
|
46
|
+
}
|
|
47
|
+
.transportfyi-kv-row:last-child { border-bottom: none; }
|
|
48
|
+
.transportfyi-kv-label { color: var(--muted); font-size: 12px; }
|
|
49
|
+
.transportfyi-kv-value { font-weight: 600; color: var(--text); text-align: right; }
|
|
50
|
+
|
|
51
|
+
/* Description text */
|
|
52
|
+
.transportfyi-desc {
|
|
53
|
+
padding: 0 20px 12px; font-size: 13px; color: var(--muted); line-height: 1.5;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/* View link */
|
|
57
|
+
.transportfyi-view-link { padding: 8px 20px; border-top: 1px solid var(--border); text-align: center; }
|
|
58
|
+
.transportfyi-view-link a {
|
|
59
|
+
color: var(--link); text-decoration: none; font-size: 13px; font-weight: 500;
|
|
60
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
61
|
+
}
|
|
62
|
+
.transportfyi-view-link a:hover { text-decoration: underline; }
|
|
63
|
+
.transportfyi-view-link svg { width: 12px; height: 12px; }
|
|
64
|
+
|
|
65
|
+
/* Pills */
|
|
66
|
+
.transportfyi-pills { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px 20px; }
|
|
67
|
+
.transportfyi-pill {
|
|
68
|
+
display: inline-block; font-size: 11px; padding: 3px 10px; border-radius: 12px;
|
|
69
|
+
background: var(--surface); color: var(--text); border: 1px solid var(--border);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* Code badges (IATA/ICAO) */
|
|
73
|
+
.transportfyi-code {
|
|
74
|
+
font-family: ui-monospace, 'SF Mono', monospace; font-weight: 700; font-size: 18px;
|
|
75
|
+
color: #fff; letter-spacing: 0.05em;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/* Stat grid (for airport/station stats) */
|
|
79
|
+
.transportfyi-stat-grid {
|
|
80
|
+
display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
|
|
81
|
+
background: var(--border); margin: 0;
|
|
82
|
+
}
|
|
83
|
+
.transportfyi-stat-cell {
|
|
84
|
+
background: var(--bg); padding: 10px 12px; text-align: center;
|
|
85
|
+
}
|
|
86
|
+
.transportfyi-stat-num { font-size: 16px; font-weight: 700; color: var(--text); }
|
|
87
|
+
.transportfyi-stat-label { font-size: 10px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 2px; }
|
|
88
|
+
`}function et(){return`
|
|
89
|
+
/* Clean: flat header with accent left bar */
|
|
90
|
+
.transportfyi-header {
|
|
91
|
+
border-left: 4px solid var(--accent);
|
|
92
|
+
padding: 14px 16px;
|
|
93
|
+
display: flex;
|
|
94
|
+
align-items: flex-start;
|
|
95
|
+
gap: 12px;
|
|
96
|
+
background: var(--surface);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.transportfyi-header-title {
|
|
100
|
+
font-size: 14px; font-weight: 700; color: var(--text); margin: 0 0 3px 0; line-height: 1.3;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.transportfyi-header-subtitle {
|
|
104
|
+
font-size: 12px; color: var(--muted); margin: 0;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.transportfyi-img {
|
|
108
|
+
width: 44px; height: 44px; border-radius: 6px; object-fit: cover;
|
|
109
|
+
background: var(--badge-bg); flex-shrink: 0;
|
|
110
|
+
display: flex; align-items: center; justify-content: center; overflow: hidden;
|
|
111
|
+
font-size: 20px; color: var(--accent); font-weight: 700;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.transportfyi-img img { width: 100%; height: 100%; object-fit: cover; border-radius: 6px; }
|
|
115
|
+
|
|
116
|
+
.transportfyi-body { padding: 12px 16px; }
|
|
117
|
+
|
|
118
|
+
.transportfyi-row {
|
|
119
|
+
display: flex; justify-content: space-between; align-items: flex-start; gap: 10px;
|
|
120
|
+
padding: 6px 0; border-bottom: 1px solid var(--border);
|
|
121
|
+
}
|
|
122
|
+
.transportfyi-row:last-child { border-bottom: none; }
|
|
123
|
+
.transportfyi-label { font-size: 12px; color: var(--muted); flex-shrink: 0; }
|
|
124
|
+
.transportfyi-value { font-size: 12px; font-weight: 600; color: var(--text); text-align: right; }
|
|
125
|
+
|
|
126
|
+
.transportfyi-kv-rows { padding: 4px 16px 6px; }
|
|
127
|
+
.transportfyi-kv-row {
|
|
128
|
+
display: flex; justify-content: space-between; padding: 5px 0;
|
|
129
|
+
border-bottom: 1px solid var(--border); font-size: 12px;
|
|
130
|
+
}
|
|
131
|
+
.transportfyi-kv-row:last-child { border-bottom: none; }
|
|
132
|
+
.transportfyi-kv-label { color: var(--muted); }
|
|
133
|
+
.transportfyi-kv-value { font-weight: 600; color: var(--text); text-align: right; }
|
|
134
|
+
|
|
135
|
+
.transportfyi-desc { padding: 0 16px 10px; font-size: 12px; color: var(--muted); line-height: 1.5; }
|
|
136
|
+
|
|
137
|
+
.transportfyi-view-link { padding: 6px 16px; border-top: 1px solid var(--border); text-align: center; }
|
|
138
|
+
.transportfyi-view-link a {
|
|
139
|
+
color: var(--link); text-decoration: none; font-size: 12px; font-weight: 500;
|
|
140
|
+
display: inline-flex; align-items: center; gap: 4px;
|
|
141
|
+
}
|
|
142
|
+
.transportfyi-view-link a:hover { text-decoration: underline; }
|
|
143
|
+
.transportfyi-view-link svg { width: 11px; height: 11px; }
|
|
144
|
+
|
|
145
|
+
.transportfyi-pills { display: flex; flex-wrap: wrap; gap: 4px; padding: 6px 16px; }
|
|
146
|
+
.transportfyi-pill {
|
|
147
|
+
display: inline-block; font-size: 10px; padding: 2px 8px; border-radius: 3px;
|
|
148
|
+
background: var(--surface); color: var(--text); border: 1px solid var(--border);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.transportfyi-code {
|
|
152
|
+
font-family: ui-monospace, 'SF Mono', monospace; font-weight: 700; font-size: 16px;
|
|
153
|
+
color: var(--accent); letter-spacing: 0.05em;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.transportfyi-stat-grid {
|
|
157
|
+
display: grid; grid-template-columns: repeat(3, 1fr); gap: 1px;
|
|
158
|
+
background: var(--border); margin: 0;
|
|
159
|
+
}
|
|
160
|
+
.transportfyi-stat-cell { background: var(--bg); padding: 8px 10px; text-align: center; }
|
|
161
|
+
.transportfyi-stat-num { font-size: 14px; font-weight: 700; color: var(--text); }
|
|
162
|
+
.transportfyi-stat-label { font-size: 9px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; margin-top: 2px; }
|
|
163
|
+
`}function ht(t){switch(t){case"clean":return et();case"modern":default:return tt()}}function rt(t,e="modern"){return`
|
|
164
|
+
:host {
|
|
165
|
+
display: block;
|
|
166
|
+
--site-accent: ${t};
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.transportfyi-widget {
|
|
170
|
+
box-sizing: border-box;
|
|
171
|
+
min-width: 240px;
|
|
172
|
+
max-width: 420px;
|
|
173
|
+
border-radius: 8px;
|
|
174
|
+
overflow: hidden;
|
|
175
|
+
border: 1px solid var(--border);
|
|
176
|
+
background: var(--bg);
|
|
177
|
+
color: var(--text);
|
|
178
|
+
font-size: 14px;
|
|
179
|
+
line-height: 1.6;
|
|
180
|
+
transition: border-color 0.2s;
|
|
181
|
+
font-family: system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.transportfyi-widget:hover {
|
|
185
|
+
border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
.transportfyi-widget[data-size="compact"] { max-width: 280px; font-size: 13px; }
|
|
189
|
+
.transportfyi-widget[data-size="default"] { max-width: 420px; }
|
|
190
|
+
.transportfyi-widget[data-size="large"] { max-width: 720px; }
|
|
191
|
+
|
|
192
|
+
/* Light theme */
|
|
193
|
+
.transportfyi-widget[data-theme="light"] {
|
|
194
|
+
--bg: #fff; --text: #1e293b; --border: #e2e8f0; --accent: var(--site-accent);
|
|
195
|
+
--muted: #64748b; --surface: #f8fafc; --badge-bg: #f1f5f9; --badge-text: #374151;
|
|
196
|
+
--link: var(--site-accent); --copy-bg: #f3f4f6; --copy-hover: #e5e7eb;
|
|
197
|
+
--input-bg: #ffffff; --input-border: #d1d5db; --input-focus: var(--site-accent);
|
|
198
|
+
--shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/* Dark theme */
|
|
202
|
+
.transportfyi-widget[data-theme="dark"] {
|
|
203
|
+
--bg: #1a1a1a; --text: #f3f4f6; --border: #374151; --accent: var(--site-accent);
|
|
204
|
+
--muted: #9ca3af; --surface: #111827; --badge-bg: #374151; --badge-text: #d1d5db;
|
|
205
|
+
--link: color-mix(in srgb, var(--site-accent) 80%, #fff); --copy-bg: #374151; --copy-hover: #4b5563;
|
|
206
|
+
--input-bg: #111111; --input-border: #4b5563; --input-focus: var(--site-accent);
|
|
207
|
+
--shadow: 0 1px 3px rgba(0, 0, 0, 0.4);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/* Sepia theme */
|
|
211
|
+
.transportfyi-widget[data-theme="sepia"] {
|
|
212
|
+
--bg: #f5f0e8; --text: #3d3529; --border: #d4c5a9; --accent: var(--site-accent);
|
|
213
|
+
--muted: #8b7d6b; --surface: #ede8df; --badge-bg: #e8e0d0; --badge-text: #5c4f3d;
|
|
214
|
+
--link: color-mix(in srgb, var(--site-accent) 70%, #3d3529); --copy-bg: #e8e0d0; --copy-hover: #ddd4c0;
|
|
215
|
+
--input-bg: #f5f0e8; --input-border: #c4b49a; --input-focus: var(--site-accent);
|
|
216
|
+
--shadow: 0 1px 3px rgba(61, 53, 41, 0.12);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.transportfyi-widget *, .transportfyi-widget *::before, .transportfyi-widget *::after { box-sizing: border-box; }
|
|
220
|
+
|
|
221
|
+
/* Loading */
|
|
222
|
+
.transportfyi-loading {
|
|
223
|
+
padding: 20px 16px; text-align: center; color: var(--muted); font-size: 13px;
|
|
224
|
+
display: flex; align-items: center; justify-content: center; gap: 8px;
|
|
225
|
+
}
|
|
226
|
+
.transportfyi-spinner {
|
|
227
|
+
width: 16px; height: 16px; border: 2px solid var(--border); border-top-color: var(--accent);
|
|
228
|
+
border-radius: 50%; animation: transportfyi-spin 0.7s linear infinite; display: inline-block; flex-shrink: 0;
|
|
229
|
+
}
|
|
230
|
+
@keyframes transportfyi-spin { to { transform: rotate(360deg); } }
|
|
231
|
+
|
|
232
|
+
/* Error */
|
|
233
|
+
.transportfyi-error { padding: 16px; color: var(--muted); font-size: 13px; text-align: center; }
|
|
234
|
+
.transportfyi-error p { margin: 0 0 8px 0; }
|
|
235
|
+
.transportfyi-error a { color: var(--link); text-decoration: none; }
|
|
236
|
+
.transportfyi-error a:hover { text-decoration: underline; }
|
|
237
|
+
|
|
238
|
+
/* Badge */
|
|
239
|
+
.transportfyi-badge {
|
|
240
|
+
display: inline-block; font-size: 10px; font-weight: 600; padding: 2px 7px;
|
|
241
|
+
border-radius: 4px; background: var(--badge-bg); color: var(--badge-text);
|
|
242
|
+
text-transform: uppercase; letter-spacing: 0.04em;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/* Search */
|
|
246
|
+
.transportfyi-search-wrap { padding: 12px 16px; }
|
|
247
|
+
.transportfyi-search-form { display: flex; gap: 8px; }
|
|
248
|
+
.transportfyi-search-input {
|
|
249
|
+
flex: 1; padding: 8px 12px; border: 1px solid var(--input-border); border-radius: 6px;
|
|
250
|
+
background: var(--input-bg); color: var(--text); font-size: 13px; font-family: inherit;
|
|
251
|
+
outline: none; transition: border-color 0.15s;
|
|
252
|
+
}
|
|
253
|
+
.transportfyi-search-input:focus { border-color: var(--input-focus); box-shadow: 0 0 0 2px color-mix(in srgb, var(--input-focus) 20%, transparent); }
|
|
254
|
+
.transportfyi-search-input::placeholder { color: var(--muted); }
|
|
255
|
+
.transportfyi-search-btn {
|
|
256
|
+
background: var(--accent); color: #fff; border: none; border-radius: 6px; padding: 8px 14px;
|
|
257
|
+
font-size: 13px; font-weight: 500; cursor: pointer; font-family: inherit;
|
|
258
|
+
transition: opacity 0.15s; white-space: nowrap;
|
|
259
|
+
}
|
|
260
|
+
.transportfyi-search-btn:hover { opacity: 0.9; }
|
|
261
|
+
.transportfyi-search-results { padding: 0 16px 12px; }
|
|
262
|
+
.transportfyi-result-item { padding: 8px 0; border-bottom: 1px solid var(--border); }
|
|
263
|
+
.transportfyi-result-item:last-child { border-bottom: none; }
|
|
264
|
+
.transportfyi-result-title { font-size: 13px; font-weight: 600; color: var(--text); margin: 0 0 3px 0; }
|
|
265
|
+
.transportfyi-result-meta { font-size: 11px; color: var(--muted); display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
|
|
266
|
+
|
|
267
|
+
/* Powered by footer */
|
|
268
|
+
.transportfyi-powered {
|
|
269
|
+
display: block; text-align: center; padding: 8px 16px; font-size: 11px; color: var(--muted);
|
|
270
|
+
border-top: 1px solid var(--border);
|
|
271
|
+
}
|
|
272
|
+
.transportfyi-powered a { color: var(--link); text-decoration: none; font-weight: 500; }
|
|
273
|
+
.transportfyi-powered a:hover { text-decoration: underline; }
|
|
274
|
+
|
|
275
|
+
/* Copy button */
|
|
276
|
+
.transportfyi-copy-btn {
|
|
277
|
+
background: var(--copy-bg); color: var(--text); border: none; border-radius: 5px;
|
|
278
|
+
padding: 4px 9px; font-size: 11px; cursor: pointer; display: inline-flex;
|
|
279
|
+
align-items: center; gap: 4px; transition: background 0.15s; font-family: inherit;
|
|
280
|
+
}
|
|
281
|
+
.transportfyi-copy-btn:hover { background: var(--copy-hover); }
|
|
282
|
+
.transportfyi-copy-btn svg { width: 11px; height: 11px; }
|
|
283
|
+
|
|
284
|
+
/* Mono */
|
|
285
|
+
.transportfyi-mono { font-family: ui-monospace, 'SF Mono', 'Cascadia Code', 'Consolas', monospace; font-size: 13px; }
|
|
286
|
+
|
|
287
|
+
/* Spec bar (for aircraft specs visualization) */
|
|
288
|
+
.transportfyi-spec-bar-wrap { padding: 0 18px 12px; }
|
|
289
|
+
.transportfyi-spec-bar { display: flex; flex-direction: column; gap: 8px; }
|
|
290
|
+
.transportfyi-spec-bar-item { display: flex; align-items: center; gap: 8px; }
|
|
291
|
+
.transportfyi-spec-bar-label { font-size: 11px; color: var(--muted); min-width: 60px; text-align: right; }
|
|
292
|
+
.transportfyi-spec-bar-track { flex: 1; height: 8px; background: var(--surface); border-radius: 4px; overflow: hidden; }
|
|
293
|
+
.transportfyi-spec-bar-fill { height: 100%; background: var(--accent); border-radius: 4px; transition: width 0.3s ease; }
|
|
294
|
+
.transportfyi-spec-bar-value { font-size: 11px; color: var(--text); min-width: 50px; font-weight: 600; }
|
|
295
|
+
|
|
296
|
+
/* Amenity icons */
|
|
297
|
+
.transportfyi-amenities { display: flex; gap: 6px; flex-wrap: wrap; padding: 4px 0; }
|
|
298
|
+
.transportfyi-amenity {
|
|
299
|
+
display: inline-flex; align-items: center; gap: 4px; font-size: 11px; padding: 3px 8px;
|
|
300
|
+
border-radius: 12px; background: var(--surface); color: var(--muted); border: 1px solid var(--border);
|
|
301
|
+
}
|
|
302
|
+
.transportfyi-amenity svg { width: 12px; height: 12px; }
|
|
303
|
+
.transportfyi-amenity--active { background: color-mix(in srgb, var(--accent) 10%, var(--bg)); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 30%, var(--border)); }
|
|
304
|
+
|
|
305
|
+
${ht(e)}
|
|
306
|
+
`}function C(t,e){let r=t.dataset.styleVariant||"modern",i=t.attachShadow({mode:"open"}),o=document.createElement("style");return o.textContent=rt(e.accent,r),i.appendChild(o),i}function vt(t){let e=t.dataset.theme||"light";return e==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e}function T(t,e,r){let i=vt(e),o=e.dataset.size||"default",a=document.createElement("div");return a.className=["transportfyi-widget",r].filter(Boolean).join(" "),a.setAttribute("data-theme",i),a.setAttribute("data-size",o),t.appendChild(a),e.dataset.theme==="auto"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",l=>{a.setAttribute("data-theme",l.matches?"dark":"light")}),a}function H(t){t.innerHTML=`
|
|
307
|
+
<div class="transportfyi-loading">
|
|
308
|
+
<span class="transportfyi-spinner"></span>
|
|
309
|
+
Loading\u2026
|
|
310
|
+
</div>
|
|
311
|
+
`}function M(t,e,r){t.innerHTML=`
|
|
312
|
+
<div class="transportfyi-error">
|
|
313
|
+
<p>${e}</p>
|
|
314
|
+
<a href="https://${r.domain}" target="_blank" rel="noopener">
|
|
315
|
+
Visit ${r.name}
|
|
316
|
+
</a>
|
|
317
|
+
</div>
|
|
318
|
+
`}var k='<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>';function w(t){return`<span class="transportfyi-powered">Powered by <a href="https://${t.domain}" target="_blank" rel="noopener">${t.name}</a></span>`}function I(t){return`transportfyi_embed_${t}`}function xt(t){try{let e=sessionStorage.getItem(I(t));if(!e)return null;let r=JSON.parse(e);return Date.now()-r.ts>3e5?(sessionStorage.removeItem(I(t)),null):r.data}catch(e){return null}}function bt(t,e){try{let r={data:e,ts:Date.now()};sessionStorage.setItem(I(t),JSON.stringify(r))}catch(r){}}async function S(t,e,r){let i=t.endsWith("/")?t:t+"/",o=e.startsWith("/")?e.slice(1):e,a=new URL(o,i);r&&Object.entries(r).forEach(([c,f])=>a.searchParams.set(c,f));let l=a.toString(),d=xt(l);if(d!==null)return d;let p=await fetch(l,{headers:{Accept:"application/json"}});if(!p.ok)throw new Error(`API error ${p.status}: ${l}`);let s=await p.json();return bt(l,s),s}function n(t){return t?t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}function $(t,e){return e==null||e===""?"":`<div class="transportfyi-kv-row"><span class="transportfyi-kv-label">${n(t)}</span><span class="transportfyi-kv-value">${n(String(e))}</span></div>`}function u(t){return t==null?"":t.toLocaleString("en-US")}function L(t,e){return`<div class="transportfyi-stat-cell"><div class="transportfyi-stat-num">${n(String(t))}</div><div class="transportfyi-stat-label">${n(e)}</div></div>`}function nt(t){return{large_airport:"Large Airport",medium_airport:"Medium Airport",small_airport:"Small Airport",heliport:"Heliport",seaplane_base:"Seaplane Base",closed:"Closed",balloonport:"Balloonport"}[t]||t}function it(t){return{major:"Major Station",regional:"Regional Station",suburban:"Suburban Station",local:"Local Station",metro:"Metro Station",tram:"Tram Stop",heritage:"Heritage Station"}[t]||t}function ot(t,e){var s,c,f,g,m,h,y,x,v;let r=String((f=(c=(s=t.term)!=null?s:t.name)!=null?c:t.slug)!=null?f:""),i=String((h=(m=(g=t.definition)!=null?g:t.short_description)!=null?m:t.short_definition)!=null?h:""),o=t.abbreviation?String(t.abbreviation):"",a=String((x=(y=t.category_name)!=null?y:t.category)!=null?x:""),l=String((v=t.slug)!=null?v:""),d;e.site==="airportfyi"?d=`https://${e.domain}/glossary/${n(l)}/`:d=`https://${e.domain}/glossary/${n(l)}/`;let p=`https://${e.domain}/glossary/`;return`
|
|
319
|
+
<div class="transportfyi-header">
|
|
320
|
+
<div>
|
|
321
|
+
<div class="transportfyi-header-title">${n(r)}${o?` <span class="transportfyi-badge" style="background:${e.accent};color:#fff">${n(o)}</span>`:""}</div>
|
|
322
|
+
${a?`<div class="transportfyi-header-subtitle">${n(a)}</div>`:""}
|
|
323
|
+
</div>
|
|
324
|
+
</div>
|
|
325
|
+
<div class="transportfyi-body" style="font-size:0.9rem;line-height:1.5;">
|
|
326
|
+
${n(i)}
|
|
327
|
+
</div>
|
|
328
|
+
<div class="transportfyi-view-link"><a href="${d}" target="_blank" rel="noopener">${n(r)} ${k}</a></div>
|
|
329
|
+
<div class="transportfyi-view-link"><a href="${p}" target="_blank" rel="noopener">Full glossary on ${n(e.name)} ${k}</a></div>
|
|
330
|
+
${w(e)}
|
|
331
|
+
`}function at(t,e){if(!t||!t.length)return`<div class="transportfyi-body">No FAQs available.</div>${w(e)}`;let r=t.map(i=>`
|
|
332
|
+
<details class="transportfyi-faq-item" style="border-bottom:1px solid var(--border);padding:10px 18px;">
|
|
333
|
+
<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;">
|
|
334
|
+
${n(i.question)}
|
|
335
|
+
<span style="flex-shrink:0;margin-left:8px;font-size:0.75rem;color:var(--muted);">+</span>
|
|
336
|
+
</summary>
|
|
337
|
+
<div style="margin-top:8px;font-size:0.85rem;color:var(--muted);line-height:1.5;">
|
|
338
|
+
${n(i.answer)}
|
|
339
|
+
</div>
|
|
340
|
+
</details>
|
|
341
|
+
`).join("");return`
|
|
342
|
+
<div class="transportfyi-header">
|
|
343
|
+
<div>
|
|
344
|
+
<div class="transportfyi-header-title">Frequently Asked Questions</div>
|
|
345
|
+
<div class="transportfyi-header-subtitle">${t.length} questions</div>
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
${r}
|
|
349
|
+
${w(e)}
|
|
350
|
+
`}function st(t,e){var y,x,v,_,b,E,z,A;let r=String((y=t.name)!=null?y:""),i=String((x=t.iata_code)!=null?x:""),o=String((_=(v=t.ident)!=null?v:t.icao_code)!=null?_:""),a=String((b=t.type)!=null?b:""),l=String((E=t.country_name)!=null?E:""),d=String((z=t.region_name)!=null?z:""),p=String((A=t.municipality)!=null?A:""),s=t.elevation_ft!=null?Number(t.elevation_ft):null,c=t.runway_count!=null?Number(t.runway_count):0,f=t.airline_count!=null?Number(t.airline_count):0,g=t.destination_count!=null?Number(t.destination_count):0,m=i?`https://${e.domain}/${n(i)}/`:`https://${e.domain}/`,h=nt(a);return`
|
|
351
|
+
<div class="transportfyi-header">
|
|
352
|
+
<div class="transportfyi-img">
|
|
353
|
+
<span class="transportfyi-code">${n(i||"?")}</span>
|
|
354
|
+
</div>
|
|
355
|
+
<div>
|
|
356
|
+
<div class="transportfyi-header-title">${n(r)}</div>
|
|
357
|
+
<div class="transportfyi-header-subtitle">
|
|
358
|
+
${n(p||l)}${o?` \xB7 ICAO: ${n(o)}`:""}
|
|
359
|
+
</div>
|
|
360
|
+
</div>
|
|
361
|
+
</div>
|
|
362
|
+
${a?`<div style="padding:8px 20px 0;"><span class="transportfyi-badge" style="background:${e.accent};color:#fff">${n(h)}</span></div>`:""}
|
|
363
|
+
<div class="transportfyi-stat-grid">
|
|
364
|
+
${L(u(c)||"0","Runways")}
|
|
365
|
+
${L(u(f)||"0","Airlines")}
|
|
366
|
+
${L(u(g)||"0","Destinations")}
|
|
367
|
+
</div>
|
|
368
|
+
<div class="transportfyi-kv-rows">
|
|
369
|
+
${$("Country",l)}
|
|
370
|
+
${$("Region",d)}
|
|
371
|
+
${s!=null?$("Elevation",`${u(s)} ft`):""}
|
|
372
|
+
</div>
|
|
373
|
+
<div class="transportfyi-view-link"><a href="${m}" target="_blank" rel="noopener">View on ${n(e.name)} ${k}</a></div>
|
|
374
|
+
${w(e)}
|
|
375
|
+
`}function lt(t,e){var m,h,y,x,v,_;let r=String((m=t.name)!=null?m:""),i=String((h=t.slug)!=null?h:""),o=String((y=t.iata_code)!=null?y:""),a=String((x=t.icao_code)!=null?x:""),l=String((v=t.callsign)!=null?v:""),d=String((_=t.country_name)!=null?_:""),p=!!t.is_active,s=t.route_count!=null?Number(t.route_count):0,c=t.destination_count!=null?Number(t.destination_count):0,f=t.country_count!=null?Number(t.country_count):0,g=`https://${e.domain}/${n(i)}/`;return`
|
|
376
|
+
<div class="transportfyi-header">
|
|
377
|
+
<div class="transportfyi-img">
|
|
378
|
+
<span class="transportfyi-code">${n(o||"?")}</span>
|
|
379
|
+
</div>
|
|
380
|
+
<div>
|
|
381
|
+
<div class="transportfyi-header-title">${n(r)}</div>
|
|
382
|
+
<div class="transportfyi-header-subtitle">${n(d)}${a?` \xB7 ICAO: ${n(a)}`:""}</div>
|
|
383
|
+
</div>
|
|
384
|
+
</div>
|
|
385
|
+
<div style="padding:8px 20px 0;display:flex;gap:6px;flex-wrap:wrap;">
|
|
386
|
+
${p?'<span class="transportfyi-badge" style="background:#16a34a;color:#fff">Active</span>':'<span class="transportfyi-badge" style="background:#dc2626;color:#fff">Inactive</span>'}
|
|
387
|
+
${l?`<span class="transportfyi-badge">${n(l)}</span>`:""}
|
|
388
|
+
</div>
|
|
389
|
+
<div class="transportfyi-stat-grid">
|
|
390
|
+
${L(u(s)||"0","Routes")}
|
|
391
|
+
${L(u(c)||"0","Destinations")}
|
|
392
|
+
${L(u(f)||"0","Countries")}
|
|
393
|
+
</div>
|
|
394
|
+
<div class="transportfyi-view-link"><a href="${g}" target="_blank" rel="noopener">View on ${n(e.name)} ${k}</a></div>
|
|
395
|
+
${w(e)}
|
|
396
|
+
`}function B(t,e,r,i){let o=Math.min(100,Math.round(e/r*100));return`
|
|
397
|
+
<div class="transportfyi-spec-bar-item">
|
|
398
|
+
<span class="transportfyi-spec-bar-label">${n(t)}</span>
|
|
399
|
+
<div class="transportfyi-spec-bar-track">
|
|
400
|
+
<div class="transportfyi-spec-bar-fill" style="width:${o}%"></div>
|
|
401
|
+
</div>
|
|
402
|
+
<span class="transportfyi-spec-bar-value">${u(e)} ${n(i)}</span>
|
|
403
|
+
</div>
|
|
404
|
+
`}function wt(t){let e={in_production:"#16a34a",in_service:"#3b82f6",retired:"#9ca3af",development:"#d97706",limited:"#8b5cf6"},r={in_production:"In Production",in_service:"In Service",retired:"Retired",development:"In Development",limited:"Limited"},i=e[t]||"#6b7280",o=r[t]||t;return`<span class="transportfyi-badge" style="background:${i};color:#fff">${n(o)}</span>`}function pt(t,e){var N,G,V,Q,K,J,X,Y,Z;let r=String((N=t.name)!=null?N:""),i=String((G=t.slug)!=null?G:""),o=String((V=t.iata_code)!=null?V:""),a=String((Q=t.icao_code)!=null?Q:""),l=String((K=t.manufacturer_name)!=null?K:""),d=String((J=t.family_name)!=null?J:""),p=String((X=t.status)!=null?X:""),s=t.range_km!=null?Number(t.range_km):0,c=t.max_speed_kmh!=null?Number(t.max_speed_kmh):0,f=t.cruise_speed_kmh!=null?Number(t.cruise_speed_kmh):0,g=t.typical_seats!=null?Number(t.typical_seats):0,m=t.max_seats!=null?Number(t.max_seats):0,h=t.length_m!=null?Number(t.length_m):null,y=t.wingspan_m!=null?Number(t.wingspan_m):null,x=t.height_m!=null?Number(t.height_m):null,v=t.engine_count!=null?Number(t.engine_count):null,_=String((Y=t.engine_type)!=null?Y:""),b=String((Z=t.engine_model)!=null?Z:""),E=t.first_flight_date?String(t.first_flight_date).slice(0,4):"",z=t.fleet_count!=null?Number(t.fleet_count):0,A=`https://${e.domain}/${n(i)}/`;return`
|
|
405
|
+
<div class="transportfyi-header">
|
|
406
|
+
<div class="transportfyi-img">
|
|
407
|
+
<span class="transportfyi-code">${n(o||a||"\u2708")}</span>
|
|
408
|
+
</div>
|
|
409
|
+
<div>
|
|
410
|
+
<div class="transportfyi-header-title">${n(r)}</div>
|
|
411
|
+
<div class="transportfyi-header-subtitle">${n(l)}${d?` \xB7 ${n(d)}`:""}</div>
|
|
412
|
+
</div>
|
|
413
|
+
</div>
|
|
414
|
+
<div style="padding:8px 20px 0;display:flex;gap:6px;flex-wrap:wrap;">
|
|
415
|
+
${p?wt(p):""}
|
|
416
|
+
${z>0?`<span class="transportfyi-badge">${u(z)} in fleet</span>`:""}
|
|
417
|
+
</div>
|
|
418
|
+
<div class="transportfyi-spec-bar-wrap">
|
|
419
|
+
<div class="transportfyi-spec-bar">
|
|
420
|
+
${s>0?B("Range",s,18e3,"km"):""}
|
|
421
|
+
${c>0?B("Max Speed",c,1e3,"km/h"):""}
|
|
422
|
+
${g>0?B("Seats",g,600,""):""}
|
|
423
|
+
</div>
|
|
424
|
+
</div>
|
|
425
|
+
<div class="transportfyi-kv-rows">
|
|
426
|
+
${f>0?$("Cruise Speed",`${u(f)} km/h`):""}
|
|
427
|
+
${m>0?$("Max Seats",u(m)):""}
|
|
428
|
+
${h!=null?$("Length",`${h} m`):""}
|
|
429
|
+
${y!=null?$("Wingspan",`${y} m`):""}
|
|
430
|
+
${x!=null?$("Height",`${x} m`):""}
|
|
431
|
+
${v!=null?$("Engines",`${v}\xD7 ${n(_)}`):""}
|
|
432
|
+
${b?$("Engine Model",b):""}
|
|
433
|
+
${E?$("First Flight",E):""}
|
|
434
|
+
</div>
|
|
435
|
+
<div class="transportfyi-view-link"><a href="${A}" target="_blank" rel="noopener">View on ${n(e.name)} ${k}</a></div>
|
|
436
|
+
${w(e)}
|
|
437
|
+
`}var $t='<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="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/></svg>',kt='<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="M20 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v3"/><path d="M2 11v5a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-5a2 2 0 0 0-4 0v2H6v-2a2 2 0 0 0-4 0z"/><path d="M4 18v2"/><path d="M20 18v2"/></svg>',St='<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"><rect x="6" y="7" width="12" height="14" rx="2"/><path d="M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"/><path d="M8 21v1"/><path d="M16 21v1"/></svg>';function j(t,e,r){return`<span class="${r?"transportfyi-amenity transportfyi-amenity--active":"transportfyi-amenity"}">${t} ${n(e)}</span>`}function dt(t,e){var b,E,z,A,N;let r=String((b=t.name)!=null?b:""),i=String((E=t.slug)!=null?E:""),o=String((z=t.type)!=null?z:""),a=String((A=t.country_name)!=null?A:""),l=String((N=t.timezone)!=null?N:""),d=!!t.is_main_station,p=t.platforms!=null?Number(t.platforms):null,s=!!t.has_wifi,c=!!t.has_lounge,f=!!t.has_luggage_storage,g=t.year_opened!=null?Number(t.year_opened):null,m=t.operator_count!=null?Number(t.operator_count):0,h=t.route_count!=null?Number(t.route_count):0,y=t.popularity_score!=null?Number(t.popularity_score):0,x=`https://${e.domain}/station/${n(i)}/`,v=it(o),_=s||c||f;return`
|
|
438
|
+
<div class="transportfyi-header">
|
|
439
|
+
<div class="transportfyi-img">\u{1F689}</div>
|
|
440
|
+
<div>
|
|
441
|
+
<div class="transportfyi-header-title">${n(r)}</div>
|
|
442
|
+
<div class="transportfyi-header-subtitle">${n(a)}</div>
|
|
443
|
+
</div>
|
|
444
|
+
</div>
|
|
445
|
+
<div style="padding:8px 20px 0;display:flex;gap:6px;flex-wrap:wrap;">
|
|
446
|
+
${o?`<span class="transportfyi-badge" style="background:${e.accent};color:#fff">${n(v)}</span>`:""}
|
|
447
|
+
${d?'<span class="transportfyi-badge" style="background:#16a34a;color:#fff">Main Station</span>':""}
|
|
448
|
+
</div>
|
|
449
|
+
<div class="transportfyi-stat-grid">
|
|
450
|
+
${L(u(m)||"0","Operators")}
|
|
451
|
+
${L(u(h)||"0","Routes")}
|
|
452
|
+
${L(p!=null?String(p):"-","Platforms")}
|
|
453
|
+
</div>
|
|
454
|
+
${_?`
|
|
455
|
+
<div style="padding:8px 20px;">
|
|
456
|
+
<div class="transportfyi-amenities">
|
|
457
|
+
${j($t,"WiFi",s)}
|
|
458
|
+
${j(kt,"Lounge",c)}
|
|
459
|
+
${j(St,"Luggage",f)}
|
|
460
|
+
</div>
|
|
461
|
+
</div>
|
|
462
|
+
`:""}
|
|
463
|
+
<div class="transportfyi-kv-rows">
|
|
464
|
+
${$("Timezone",l)}
|
|
465
|
+
${g!=null?$("Opened",String(g)):""}
|
|
466
|
+
${y>0?$("Popularity",String(y)):""}
|
|
467
|
+
</div>
|
|
468
|
+
<div class="transportfyi-view-link"><a href="${x}" target="_blank" rel="noopener">View on ${n(e.name)} ${k}</a></div>
|
|
469
|
+
${w(e)}
|
|
470
|
+
`}function _t(t,e){switch(t.site){case"airportfyi":return`airports/${e}/`;case"airlinefyi":return`airlines/${e}/`;case"planefyi":return`aircraft-types/${e}/`;case"trainfyi":return`stations/${e}/`;default:return`${t.entitySlug}/${e}/`}}function W(t,e){var d;let i=(d=t.dataset.slug)!=null?d:"";if(!i){let p=C(t,e),s=T(p,t,"transportfyi-entity-widget");M(s,"Missing data-slug attribute.",e);return}let o=C(t,e),a=T(o,t,"transportfyi-entity-widget");H(a);let l=_t(e,i);S(e.apiBase,l).then(p=>{var c;let s;switch(e.site){case"airportfyi":s=st(p,e);break;case"airlinefyi":s=lt(p,e);break;case"planefyi":s=pt(p,e);break;case"trainfyi":s=dt(p,e);break;default:{let f=String((c=p.name)!=null?c:i);s=`
|
|
471
|
+
<div style="padding:16px;">
|
|
472
|
+
<div style="font-size:1rem;font-weight:600;margin-bottom:8px;">${n(f)}</div>
|
|
473
|
+
<a href="https://${e.domain}" target="_blank" rel="noopener"
|
|
474
|
+
style="color:${e.accent};text-decoration:none;font-size:0.85rem;">
|
|
475
|
+
View on ${n(e.name)} ${k}
|
|
476
|
+
</a>
|
|
477
|
+
</div>
|
|
478
|
+
`;break}}a.innerHTML=s}).catch(()=>{M(a,`Unable to load "${n(i)}". Please try again later.`,e)})}function ct(t,e){switch(t.site){case"airportfyi":return`airports/${e}/`;case"airlinefyi":return`airlines/${e}/`;case"planefyi":return`aircraft-types/${e}/`;case"trainfyi":return`stations/${e}/`;default:return`${t.entitySlug}/${e}/`}}function ft(t,e){var i,o;let r=String((i=e.slug)!=null?i:"");switch(t.site){case"airportfyi":return`https://${t.domain}/${String((o=e.iata_code)!=null?o:r)}/`;case"trainfyi":return`https://${t.domain}/station/${r}/`;default:return`https://${t.domain}/${r}/`}}function Ct(t){let e=r=>u(Number(r)||0);switch(t.site){case"airportfyi":return[{key:"country_name",label:"Country"},{key:"type",label:"Type"},{key:"runway_count",label:"Runways",fmt:e},{key:"airline_count",label:"Airlines",fmt:e},{key:"destination_count",label:"Destinations",fmt:e},{key:"elevation_ft",label:"Elevation (ft)",fmt:e}];case"airlinefyi":return[{key:"country_name",label:"Country"},{key:"iata_code",label:"IATA"},{key:"route_count",label:"Routes",fmt:e},{key:"destination_count",label:"Destinations",fmt:e},{key:"country_count",label:"Countries",fmt:e}];case"planefyi":return[{key:"manufacturer_name",label:"Manufacturer"},{key:"typical_seats",label:"Seats",fmt:e},{key:"range_km",label:"Range (km)",fmt:e},{key:"max_speed_kmh",label:"Max Speed (km/h)",fmt:e},{key:"wingspan_m",label:"Wingspan (m)"},{key:"engine_count",label:"Engines",fmt:e}];case"trainfyi":return[{key:"country_name",label:"Country"},{key:"type",label:"Type"},{key:"operator_count",label:"Operators",fmt:e},{key:"route_count",label:"Routes",fmt:e},{key:"platforms",label:"Platforms"}];default:return[]}}function P(t,e){var p;let i=((p=t.dataset.slugs)!=null?p:"").split(",").map(s=>s.trim()).filter(Boolean),o=C(t,e),a=T(o,t,"transportfyi-compare-widget");if(i.length<2){M(a,"Missing data-slugs attribute (comma-separated pair).",e);return}H(a);let[l,d]=i;Promise.all([S(e.apiBase,ct(e,l)),S(e.apiBase,ct(e,d))]).then(([s,c])=>{var v,_;let f=String((v=s.name)!=null?v:l),g=String((_=c.name)!=null?_:d),m=ft(e,s),h=ft(e,c),x=Ct(e).map(b=>{var A,N;let E=b.fmt?b.fmt(s[b.key]):String((A=s[b.key])!=null?A:"-"),z=b.fmt?b.fmt(c[b.key]):String((N=c[b.key])!=null?N:"-");return`<tr><td style="color:var(--muted);font-size:12px;padding:6px 8px;">${n(b.label)}</td><td style="font-weight:600;padding:6px 8px;text-align:center;">${n(E)}</td><td style="font-weight:600;padding:6px 8px;text-align:center;">${n(z)}</td></tr>`}).join("");a.innerHTML=`
|
|
479
|
+
<div class="transportfyi-header">
|
|
480
|
+
<div>
|
|
481
|
+
<div class="transportfyi-header-title">${n(f)} vs ${n(g)}</div>
|
|
482
|
+
<div class="transportfyi-header-subtitle">Side-by-side comparison</div>
|
|
483
|
+
</div>
|
|
484
|
+
</div>
|
|
485
|
+
<div style="padding:0 16px 8px;overflow-x:auto;">
|
|
486
|
+
<table style="width:100%;border-collapse:collapse;font-size:13px;">
|
|
487
|
+
<thead><tr>
|
|
488
|
+
<th style="text-align:left;padding:8px;font-size:11px;color:var(--muted);"></th>
|
|
489
|
+
<th style="text-align:center;padding:8px;font-weight:700;">${n(f)}</th>
|
|
490
|
+
<th style="text-align:center;padding:8px;font-weight:700;">${n(g)}</th>
|
|
491
|
+
</tr></thead>
|
|
492
|
+
<tbody>${x}</tbody>
|
|
493
|
+
</table>
|
|
494
|
+
</div>
|
|
495
|
+
<div style="display:flex;gap:8px;padding:8px 16px;">
|
|
496
|
+
<a href="${n(m)}" target="_blank" rel="noopener" style="flex:1;text-align:center;color:var(--link);font-size:12px;text-decoration:none;">${n(f)} ${k}</a>
|
|
497
|
+
<a href="${n(h)}" target="_blank" rel="noopener" style="flex:1;text-align:center;color:var(--link);font-size:12px;text-decoration:none;">${n(g)} ${k}</a>
|
|
498
|
+
</div>
|
|
499
|
+
${w(e)}
|
|
500
|
+
`}).catch(()=>{M(a,"Unable to load comparison data.",e)})}function ut(t,e,r){if(document.querySelector('script[data-transportfyi-snippet="term"]'))return;let i={"@context":"https://schema.org","@type":"DefinedTerm",name:t.name,description:t.definition,inDefinedTermSet:{"@type":"DefinedTermSet",name:`${r} Glossary`,url:`https://${e}/glossary/`}},o=document.createElement("script");o.type="application/ld+json",o.setAttribute("data-transportfyi-snippet","term"),o.textContent=JSON.stringify(i),document.head.appendChild(o)}function gt(t,e,r){if(document.querySelector('script[data-transportfyi-snippet="faq"]'))return;let i={"@context":"https://schema.org","@type":"FAQPage",mainEntity:t.map(a=>({"@type":"Question",name:a.question,acceptedAnswer:{"@type":"Answer",text:a.answer}})),url:`https://${e}/`},o=document.createElement("script");o.type="application/ld+json",o.setAttribute("data-transportfyi-snippet","faq"),o.textContent=JSON.stringify(i),document.head.appendChild(o)}function Tt(t,e){switch(t.site){case"airportfyi":return`glossary-terms/${e}/`;case"airlinefyi":return`glossary/${e}/`;case"planefyi":return`aviation-terms/${e}/`;case"trainfyi":return null;default:return null}}function F(t,e){var d;let r=t.dataset,i=(d=r.slug)!=null?d:"",o=C(t,e),a=T(o,t,"transportfyi-glossary-widget");if(!i){M(a,"Missing data-slug attribute.",e);return}let l=Tt(e,i);if(!l){M(a,`Glossary not available for ${e.name}.`,e);return}H(a),S(e.apiBase,l).then(p=>{var s,c,f,g,m;if(a.innerHTML=ot(p,e),r.noSnippet!=="true"){let h=String((c=(s=p.term)!=null?s:p.name)!=null?c:""),y=String((m=(g=(f=p.definition)!=null?f:p.short_description)!=null?g:p.short_definition)!=null?m:"");h&&y&&ut({name:h,definition:y},e.domain,e.name)}}).catch(()=>{M(a,`Unable to load glossary term "${n(i)}".`,e)})}function Mt(t){switch(t.site){case"airportfyi":return"airports/";case"airlinefyi":return"airlines/";case"planefyi":return"aircraft-types/";case"trainfyi":return"stations/";default:return`${t.entitySlug}/`}}function Lt(t,e){var i,o;let r=String((i=e.slug)!=null?i:"");switch(t.site){case"airportfyi":{let a=String((o=e.iata_code)!=null?o:r);return`https://${t.domain}/${a}/`}case"airlinefyi":return`https://${t.domain}/${r}/`;case"planefyi":return`https://${t.domain}/${r}/`;case"trainfyi":return`https://${t.domain}/station/${r}/`;default:return`https://${t.domain}/${r}/`}}function Et(t,e){var r,i,o,a,l,d,p;switch(t.site){case"airportfyi":{let s=String((r=e.iata_code)!=null?r:""),c=String((i=e.country_name)!=null?i:"");return[s,c].filter(Boolean).join(" \xB7 ")}case"airlinefyi":{let s=String((o=e.iata_code)!=null?o:""),c=String((a=e.country_name)!=null?a:"");return[s,c].filter(Boolean).join(" \xB7 ")}case"planefyi":return String((l=e.manufacturer_name)!=null?l:"");case"trainfyi":{let s=String((d=e.country_name)!=null?d:"");return[String((p=e.type)!=null?p:""),s].filter(Boolean).join(" \xB7 ")}default:return""}}function D(t,e){let i=t.dataset.placeholder||`Search ${e.entityName}...`,o=C(t,e),a=T(o,t,"transportfyi-search-widget");a.innerHTML=`
|
|
501
|
+
<div class="transportfyi-search-wrap">
|
|
502
|
+
<form class="transportfyi-search-form">
|
|
503
|
+
<input type="text" class="transportfyi-search-input" placeholder="${n(i)}" autocomplete="off" />
|
|
504
|
+
<button type="submit" class="transportfyi-search-btn">Search</button>
|
|
505
|
+
</form>
|
|
506
|
+
</div>
|
|
507
|
+
<div class="transportfyi-search-results" style="display:none;"></div>
|
|
508
|
+
${w(e)}
|
|
509
|
+
`;let l=a.querySelector("form"),d=a.querySelector("input"),p=a.querySelector(".transportfyi-search-results");l.addEventListener("submit",s=>{s.preventDefault();let c=d.value.trim();c&&(p.style.display="block",p.innerHTML='<div style="padding:8px 0;color:var(--muted);font-size:12px;">Searching\u2026</div>',S(e.apiBase,Mt(e),{search:c,limit:"5"}).then(f=>{let g=f.results||[];if(!g.length){p.innerHTML=`<div style="padding:8px 0;color:var(--muted);font-size:12px;">No results. <a href="https://${e.domain}${e.searchPath}?q=${encodeURIComponent(c)}" target="_blank" rel="noopener" style="color:var(--link);">Search on ${n(e.name)}</a></div>`;return}p.innerHTML=g.map(m=>{var v,_;let h=String((_=(v=m.name)!=null?v:m.slug)!=null?_:""),y=Lt(e,m),x=Et(e,m);return`
|
|
510
|
+
<div class="transportfyi-result-item">
|
|
511
|
+
<a href="${n(y)}" target="_blank" rel="noopener" class="transportfyi-result-title" style="color:var(--link);text-decoration:none;">${n(h)}</a>
|
|
512
|
+
${x?`<div class="transportfyi-result-meta">${n(x)}</div>`:""}
|
|
513
|
+
</div>
|
|
514
|
+
`}).join("")}).catch(()=>{p.innerHTML=`<div style="padding:8px 0;color:var(--muted);font-size:12px;">Search failed. <a href="https://${e.domain}${e.searchPath}?q=${encodeURIComponent(c)}" target="_blank" rel="noopener" style="color:var(--link);">Try on ${n(e.name)}</a></div>`}))})}function q(t,e){let r=t.dataset,i=C(t,e),o=T(i,t,"transportfyi-faq-widget");H(o),S(e.apiBase,"faqs/",{limit:"10"}).then(a=>{let l=a.results||[];o.innerHTML=at(l,e),r.noSnippet!=="true"&&l.length>0&>(l,e.domain,e.name)}).catch(()=>{M(o,"Unable to load FAQs.",e)})}function R(t,e,r,i,o,a,l){let d=Math.max(e,r,1),p=Math.round(e/d*100),s=Math.round(r/d*100);return`
|
|
515
|
+
<div style="margin-bottom:12px;">
|
|
516
|
+
<div style="font-size:11px;color:var(--muted);margin-bottom:4px;">${n(t)}</div>
|
|
517
|
+
<div style="display:flex;align-items:center;gap:8px;margin-bottom:3px;">
|
|
518
|
+
<span style="font-size:10px;color:var(--muted);min-width:60px;text-align:right;">${n(o)}</span>
|
|
519
|
+
<div style="flex:1;height:6px;background:var(--surface);border-radius:3px;overflow:hidden;">
|
|
520
|
+
<div style="height:100%;width:${p}%;background:${l};border-radius:3px;"></div>
|
|
521
|
+
</div>
|
|
522
|
+
<span style="font-size:11px;font-weight:600;min-width:55px;">${u(e)} ${n(i)}</span>
|
|
523
|
+
</div>
|
|
524
|
+
<div style="display:flex;align-items:center;gap:8px;">
|
|
525
|
+
<span style="font-size:10px;color:var(--muted);min-width:60px;text-align:right;">${n(a)}</span>
|
|
526
|
+
<div style="flex:1;height:6px;background:var(--surface);border-radius:3px;overflow:hidden;">
|
|
527
|
+
<div style="height:100%;width:${s}%;background:color-mix(in srgb, ${l} 50%, var(--muted));border-radius:3px;"></div>
|
|
528
|
+
</div>
|
|
529
|
+
<span style="font-size:11px;font-weight:600;min-width:55px;">${u(r)} ${n(i)}</span>
|
|
530
|
+
</div>
|
|
531
|
+
</div>
|
|
532
|
+
`}function O(t,e){var p;let i=((p=t.dataset.slugs)!=null?p:"").split(",").map(s=>s.trim()).filter(Boolean),o=C(t,e),a=T(o,t,"transportfyi-spec-compare-widget");if(i.length<2){M(a,"Provide data-slugs with two aircraft slugs.",e);return}H(a);let[l,d]=i;Promise.all([S(e.apiBase,`aircraft-types/${l}/`),S(e.apiBase,`aircraft-types/${d}/`)]).then(([s,c])=>{a.innerHTML=`
|
|
533
|
+
<div class="transportfyi-header">
|
|
534
|
+
<div>
|
|
535
|
+
<div class="transportfyi-header-title">Aircraft Spec Compare</div>
|
|
536
|
+
<div class="transportfyi-header-subtitle">${n(s.name)} vs ${n(c.name)}</div>
|
|
537
|
+
</div>
|
|
538
|
+
</div>
|
|
539
|
+
<div style="padding:16px 20px;">
|
|
540
|
+
${R("Range",s.range_km||0,c.range_km||0,"km",s.name,c.name,e.accent)}
|
|
541
|
+
${R("Max Speed",s.max_speed_kmh||0,c.max_speed_kmh||0,"km/h",s.name,c.name,e.accent)}
|
|
542
|
+
${R("Seats",s.typical_seats||0,c.typical_seats||0,"",s.name,c.name,e.accent)}
|
|
543
|
+
${R("Wingspan",Number(s.wingspan_m)||0,Number(c.wingspan_m)||0,"m",s.name,c.name,e.accent)}
|
|
544
|
+
</div>
|
|
545
|
+
${w(e)}
|
|
546
|
+
`}).catch(()=>{M(a,"Unable to load aircraft data.",e)})}function mt(t,e){var a;let r=(a=t.dataset.slug)!=null?a:"";if(!r)return;let i=C(t,e),o=T(i,t);o.style.display="inline-block",o.style.maxWidth="none",o.style.border="none",o.style.borderRadius="4px",S(e.apiBase,`aircraft-types/${r}/`).then(l=>{var f,g,m;let d=Number((f=l.typical_seats)!=null?f:0),p=Number((g=l.max_seats)!=null?g:0),s=String((m=l.name)!=null?m:r),c=p>d?`${u(d)}\u2013${u(p)} seats`:`${u(d)} seats`;o.innerHTML=`<span class="transportfyi-badge" style="background:${e.accent};color:#fff">${n(s)}: ${c}</span>`}).catch(()=>{o.innerHTML=""})}function zt(t,e,r){let i=t.dataset.style||"modern";switch(e){case"entity":W(t,r);break;case"compare":P(t,r);break;case"glossary":F(t,r);break;case"search":D(t,r);break;case"faq":q(t,r);break;case"spec-compare":O(t,r);break;case"seats-badge":mt(t,r);break;default:break}}function At(t,e){if("IntersectionObserver"in window){let r=new IntersectionObserver(i=>{i.forEach(o=>{o.isIntersecting&&(r.unobserve(t),e())})},{rootMargin:"200px"});r.observe(t)}else e()}function U(t,e){if(t.shadowRoot)return;let i=e.attribute.replace("data-","").replace(/-([a-z])/g,(a,l)=>l.toUpperCase()),o=t.dataset[i];o&&At(t,()=>{t.shadowRoot||zt(t,o,e)})}function yt(t){document.querySelectorAll(`[${t.attribute}]`).forEach(e=>U(e,t))}(function(){let e='{"site":"planefyi","name":"PlaneFYI","domain":"planefyi.com","accent":"#0284C7","attribute":"data-planefyi","apiBase":"https://planefyi.com/api/v1/","searchPath":"/search/","entityName":"Aircraft","entitySlug":"aircraft-types"}';document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>yt(e)):yt(e),new MutationObserver(i=>{i.forEach(o=>{o.addedNodes.forEach(a=>{var d;if(a.nodeType!==Node.ELEMENT_NODE)return;let l=a;l.hasAttribute(e.attribute)&&U(l,e),(d=l.querySelectorAll)==null||d.call(l,`[${e.attribute}]`).forEach(p=>U(p,e))})})}).observe(document.body||document.documentElement,{childList:!0,subtree:!0})})();function Ht(t,e,r){let i=[...r,"theme","style-variant","size"];return class extends HTMLElement{static get observedAttributes(){return i}connectedCallback(){this.shadowRoot||(this._syncDataAttrs(),e(this,'{"site":"planefyi","name":"PlaneFYI","domain":"planefyi.com","accent":"#0284C7","attribute":"data-planefyi","apiBase":"https://planefyi.com/api/v1/","searchPath":"/search/","entityName":"Aircraft","entitySlug":"aircraft-types"}'))}attributeChangedCallback(o,a,l){if(a===l||!this.shadowRoot)return;let d=this.shadowRoot;for(;d.firstChild;)d.firstChild.remove();this._syncDataAttrs(),e(this,'{"site":"planefyi","name":"PlaneFYI","domain":"planefyi.com","accent":"#0284C7","attribute":"data-planefyi","apiBase":"https://planefyi.com/api/v1/","searchPath":"/search/","entityName":"Aircraft","entitySlug":"aircraft-types"}')}_syncDataAttrs(){let o='{"site":"planefyi","name":"PlaneFYI","domain":"planefyi.com","accent":"#0284C7","attribute":"data-planefyi","apiBase":"https://planefyi.com/api/v1/","searchPath":"/search/","entityName":"Aircraft","entitySlug":"aircraft-types"}'.attribute.replace("data-","");this.dataset[o]=t;for(let p of r){let s=this.getAttribute(p);s!==null&&(this.dataset[p]=s)}let a=this.getAttribute("theme");a!==null&&(this.dataset.theme=a);let l=this.getAttribute("style-variant");l!==null&&(this.dataset.style=l);let d=this.getAttribute("size");d!==null&&(this.dataset.size=d)}}}(function(){if(typeof customElements=="undefined")return;let e='{"site":"planefyi","name":"PlaneFYI","domain":"planefyi.com","accent":"#0284C7","attribute":"data-planefyi","apiBase":"https://planefyi.com/api/v1/","searchPath":"/search/","entityName":"Aircraft","entitySlug":"aircraft-types"}'.site,r=[[`${e}-entity`,W,["slug"]],[`${e}-compare`,P,["slugs"]],[`${e}-glossary`,F,["slug","letter"]],[`${e}-search`,D,["placeholder","query"]],[`${e}-faq`,q,["slug","category"]],[`${e}-spec-compare`,O,["slug1","slug2"]]];for(let[i,o,a]of r)if(!customElements.get(i)){let l=i.slice(e.length+1);customElements.define(i,Ht(l,o,a))}})();})();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* planefyi-embed — TypeScript declarations
|
|
3
|
+
*
|
|
4
|
+
* The embed script is self-executing. Simply import it to activate widgets.
|
|
5
|
+
* All configuration is provided via data-* attributes on DOM elements.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
export {};
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
interface HTMLElement {
|
|
12
|
+
dataset: DOMStringMap & {
|
|
13
|
+
/** Widget type for PlaneFYI */
|
|
14
|
+
'planefyi'?: 'entity' | 'glossary' | 'faq' | 'search' | 'compare' | 'spec-compare' | 'seats-badge';
|
|
15
|
+
/** Entity slug (e.g. "aircraft-types") */
|
|
16
|
+
slug?: string;
|
|
17
|
+
/** Visual theme */
|
|
18
|
+
theme?: 'light' | 'dark' | 'sepia' | 'auto';
|
|
19
|
+
/** Widget design style */
|
|
20
|
+
style?: 'modern' | 'clean';
|
|
21
|
+
/** Widget size */
|
|
22
|
+
size?: 'default' | 'compact' | 'large';
|
|
23
|
+
/** Search box placeholder text */
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
}
|