trainfyi-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 +184 -0
- package/dist/embed.esm.js +1265 -0
- package/dist/embed.min.js +501 -0
- package/dist/index.d.ts +27 -0
- package/package.json +43 -0
|
@@ -0,0 +1,501 @@
|
|
|
1
|
+
/* trainfyi-embed v1.0.0 | MIT | https://widget.trainfyi.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 gt(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
|
+
${gt(e)}
|
|
306
|
+
`}function _(t,e){let r=t.dataset.styleVariant||"modern",n=t.attachShadow({mode:"open"}),i=document.createElement("style");return i.textContent=rt(e.accent,r),n.appendChild(i),n}function mt(t){let e=t.dataset.theme||"light";return e==="auto"?window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light":e}function C(t,e,r){let n=mt(e),i=e.dataset.size||"default",a=document.createElement("div");return a.className=["transportfyi-widget",r].filter(Boolean).join(" "),a.setAttribute("data-theme",n),a.setAttribute("data-size",i),t.appendChild(a),e.dataset.theme==="auto"&&window.matchMedia("(prefers-color-scheme: dark)").addEventListener("change",s=>{a.setAttribute("data-theme",s.matches?"dark":"light")}),a}function R(t){t.innerHTML=`
|
|
307
|
+
<div class="transportfyi-loading">
|
|
308
|
+
<span class="transportfyi-spinner"></span>
|
|
309
|
+
Loading\u2026
|
|
310
|
+
</div>
|
|
311
|
+
`}function H(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 B(t){return`transportfyi_embed_${t}`}function yt(t){try{let e=sessionStorage.getItem(B(t));if(!e)return null;let r=JSON.parse(e);return Date.now()-r.ts>3e5?(sessionStorage.removeItem(B(t)),null):r.data}catch(e){return null}}function ht(t,e){try{let r={data:e,ts:Date.now()};sessionStorage.setItem(B(t),JSON.stringify(r))}catch(r){}}async function T(t,e,r){let n=t.endsWith("/")?t:t+"/",i=e.startsWith("/")?e.slice(1):e,a=new URL(i,n);r&&Object.entries(r).forEach(([c,f])=>a.searchParams.set(c,f));let s=a.toString(),d=yt(s);if(d!==null)return d;let l=await fetch(s,{headers:{Accept:"application/json"}});if(!l.ok)throw new Error(`API error ${l.status}: ${s}`);let p=await l.json();return ht(s,p),p}function o(t){return t?t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,"""):""}function m(t,e){return e==null||e===""?"":`<div class="transportfyi-kv-row"><span class="transportfyi-kv-label">${o(t)}</span><span class="transportfyi-kv-value">${o(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">${o(String(t))}</div><div class="transportfyi-stat-label">${o(e)}</div></div>`}function I(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 N(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 nt(t,e){if(!t||!t.length)return`<div class="transportfyi-body">No FAQs available.</div>${w(e)}`;let r=t.map(n=>`
|
|
319
|
+
<details class="transportfyi-faq-item" style="border-bottom:1px solid var(--border);padding:10px 18px;">
|
|
320
|
+
<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;">
|
|
321
|
+
${o(n.question)}
|
|
322
|
+
<span style="flex-shrink:0;margin-left:8px;font-size:0.75rem;color:var(--muted);">+</span>
|
|
323
|
+
</summary>
|
|
324
|
+
<div style="margin-top:8px;font-size:0.85rem;color:var(--muted);line-height:1.5;">
|
|
325
|
+
${o(n.answer)}
|
|
326
|
+
</div>
|
|
327
|
+
</details>
|
|
328
|
+
`).join("");return`
|
|
329
|
+
<div class="transportfyi-header">
|
|
330
|
+
<div>
|
|
331
|
+
<div class="transportfyi-header-title">Frequently Asked Questions</div>
|
|
332
|
+
<div class="transportfyi-header-subtitle">${t.length} questions</div>
|
|
333
|
+
</div>
|
|
334
|
+
</div>
|
|
335
|
+
${r}
|
|
336
|
+
${w(e)}
|
|
337
|
+
`}function it(t,e){var $,x,v,b,g,M,E,z;let r=String(($=t.name)!=null?$:""),n=String((x=t.iata_code)!=null?x:""),i=String((b=(v=t.ident)!=null?v:t.icao_code)!=null?b:""),a=String((g=t.type)!=null?g:""),s=String((M=t.country_name)!=null?M:""),d=String((E=t.region_name)!=null?E:""),l=String((z=t.municipality)!=null?z:""),p=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,y=t.destination_count!=null?Number(t.destination_count):0,h=n?`https://${e.domain}/${o(n)}/`:`https://${e.domain}/`,S=I(a);return`
|
|
338
|
+
<div class="transportfyi-header">
|
|
339
|
+
<div class="transportfyi-img">
|
|
340
|
+
<span class="transportfyi-code">${o(n||"?")}</span>
|
|
341
|
+
</div>
|
|
342
|
+
<div>
|
|
343
|
+
<div class="transportfyi-header-title">${o(r)}</div>
|
|
344
|
+
<div class="transportfyi-header-subtitle">
|
|
345
|
+
${o(l||s)}${i?` \xB7 ICAO: ${o(i)}`:""}
|
|
346
|
+
</div>
|
|
347
|
+
</div>
|
|
348
|
+
</div>
|
|
349
|
+
${a?`<div style="padding:8px 20px 0;"><span class="transportfyi-badge" style="background:${e.accent};color:#fff">${o(S)}</span></div>`:""}
|
|
350
|
+
<div class="transportfyi-stat-grid">
|
|
351
|
+
${L(u(c)||"0","Runways")}
|
|
352
|
+
${L(u(f)||"0","Airlines")}
|
|
353
|
+
${L(u(y)||"0","Destinations")}
|
|
354
|
+
</div>
|
|
355
|
+
<div class="transportfyi-kv-rows">
|
|
356
|
+
${m("Country",s)}
|
|
357
|
+
${m("Region",d)}
|
|
358
|
+
${p!=null?m("Elevation",`${u(p)} ft`):""}
|
|
359
|
+
</div>
|
|
360
|
+
<div class="transportfyi-view-link"><a href="${h}" target="_blank" rel="noopener">View on ${o(e.name)} ${k}</a></div>
|
|
361
|
+
${w(e)}
|
|
362
|
+
`}function ot(t,e){var h,S,$,x,v,b;let r=String((h=t.name)!=null?h:""),n=String((S=t.slug)!=null?S:""),i=String(($=t.iata_code)!=null?$:""),a=String((x=t.icao_code)!=null?x:""),s=String((v=t.callsign)!=null?v:""),d=String((b=t.country_name)!=null?b:""),l=!!t.is_active,p=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,y=`https://${e.domain}/${o(n)}/`;return`
|
|
363
|
+
<div class="transportfyi-header">
|
|
364
|
+
<div class="transportfyi-img">
|
|
365
|
+
<span class="transportfyi-code">${o(i||"?")}</span>
|
|
366
|
+
</div>
|
|
367
|
+
<div>
|
|
368
|
+
<div class="transportfyi-header-title">${o(r)}</div>
|
|
369
|
+
<div class="transportfyi-header-subtitle">${o(d)}${a?` \xB7 ICAO: ${o(a)}`:""}</div>
|
|
370
|
+
</div>
|
|
371
|
+
</div>
|
|
372
|
+
<div style="padding:8px 20px 0;display:flex;gap:6px;flex-wrap:wrap;">
|
|
373
|
+
${l?'<span class="transportfyi-badge" style="background:#16a34a;color:#fff">Active</span>':'<span class="transportfyi-badge" style="background:#dc2626;color:#fff">Inactive</span>'}
|
|
374
|
+
${s?`<span class="transportfyi-badge">${o(s)}</span>`:""}
|
|
375
|
+
</div>
|
|
376
|
+
<div class="transportfyi-stat-grid">
|
|
377
|
+
${L(u(p)||"0","Routes")}
|
|
378
|
+
${L(u(c)||"0","Destinations")}
|
|
379
|
+
${L(u(f)||"0","Countries")}
|
|
380
|
+
</div>
|
|
381
|
+
<div class="transportfyi-view-link"><a href="${y}" target="_blank" rel="noopener">View on ${o(e.name)} ${k}</a></div>
|
|
382
|
+
${w(e)}
|
|
383
|
+
`}function j(t,e,r,n){let i=Math.min(100,Math.round(e/r*100));return`
|
|
384
|
+
<div class="transportfyi-spec-bar-item">
|
|
385
|
+
<span class="transportfyi-spec-bar-label">${o(t)}</span>
|
|
386
|
+
<div class="transportfyi-spec-bar-track">
|
|
387
|
+
<div class="transportfyi-spec-bar-fill" style="width:${i}%"></div>
|
|
388
|
+
</div>
|
|
389
|
+
<span class="transportfyi-spec-bar-value">${u(e)} ${o(n)}</span>
|
|
390
|
+
</div>
|
|
391
|
+
`}function vt(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"},n=e[t]||"#6b7280",i=r[t]||t;return`<span class="transportfyi-badge" style="background:${n};color:#fff">${o(i)}</span>`}function at(t,e){var A,V,Q,G,K,J,X,Y,Z;let r=String((A=t.name)!=null?A:""),n=String((V=t.slug)!=null?V:""),i=String((Q=t.iata_code)!=null?Q:""),a=String((G=t.icao_code)!=null?G:""),s=String((K=t.manufacturer_name)!=null?K:""),d=String((J=t.family_name)!=null?J:""),l=String((X=t.status)!=null?X:""),p=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,y=t.typical_seats!=null?Number(t.typical_seats):0,h=t.max_seats!=null?Number(t.max_seats):0,S=t.length_m!=null?Number(t.length_m):null,$=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,b=String((Y=t.engine_type)!=null?Y:""),g=String((Z=t.engine_model)!=null?Z:""),M=t.first_flight_date?String(t.first_flight_date).slice(0,4):"",E=t.fleet_count!=null?Number(t.fleet_count):0,z=`https://${e.domain}/${o(n)}/`;return`
|
|
392
|
+
<div class="transportfyi-header">
|
|
393
|
+
<div class="transportfyi-img">
|
|
394
|
+
<span class="transportfyi-code">${o(i||a||"\u2708")}</span>
|
|
395
|
+
</div>
|
|
396
|
+
<div>
|
|
397
|
+
<div class="transportfyi-header-title">${o(r)}</div>
|
|
398
|
+
<div class="transportfyi-header-subtitle">${o(s)}${d?` \xB7 ${o(d)}`:""}</div>
|
|
399
|
+
</div>
|
|
400
|
+
</div>
|
|
401
|
+
<div style="padding:8px 20px 0;display:flex;gap:6px;flex-wrap:wrap;">
|
|
402
|
+
${l?vt(l):""}
|
|
403
|
+
${E>0?`<span class="transportfyi-badge">${u(E)} in fleet</span>`:""}
|
|
404
|
+
</div>
|
|
405
|
+
<div class="transportfyi-spec-bar-wrap">
|
|
406
|
+
<div class="transportfyi-spec-bar">
|
|
407
|
+
${p>0?j("Range",p,18e3,"km"):""}
|
|
408
|
+
${c>0?j("Max Speed",c,1e3,"km/h"):""}
|
|
409
|
+
${y>0?j("Seats",y,600,""):""}
|
|
410
|
+
</div>
|
|
411
|
+
</div>
|
|
412
|
+
<div class="transportfyi-kv-rows">
|
|
413
|
+
${f>0?m("Cruise Speed",`${u(f)} km/h`):""}
|
|
414
|
+
${h>0?m("Max Seats",u(h)):""}
|
|
415
|
+
${S!=null?m("Length",`${S} m`):""}
|
|
416
|
+
${$!=null?m("Wingspan",`${$} m`):""}
|
|
417
|
+
${x!=null?m("Height",`${x} m`):""}
|
|
418
|
+
${v!=null?m("Engines",`${v}\xD7 ${o(b)}`):""}
|
|
419
|
+
${g?m("Engine Model",g):""}
|
|
420
|
+
${M?m("First Flight",M):""}
|
|
421
|
+
</div>
|
|
422
|
+
<div class="transportfyi-view-link"><a href="${z}" target="_blank" rel="noopener">View on ${o(e.name)} ${k}</a></div>
|
|
423
|
+
${w(e)}
|
|
424
|
+
`}var xt='<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>',bt='<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>',wt='<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 W(t,e,r){return`<span class="${r?"transportfyi-amenity transportfyi-amenity--active":"transportfyi-amenity"}">${t} ${o(e)}</span>`}function st(t,e){var g,M,E,z,A;let r=String((g=t.name)!=null?g:""),n=String((M=t.slug)!=null?M:""),i=String((E=t.type)!=null?E:""),a=String((z=t.country_name)!=null?z:""),s=String((A=t.timezone)!=null?A:""),d=!!t.is_main_station,l=t.platforms!=null?Number(t.platforms):null,p=!!t.has_wifi,c=!!t.has_lounge,f=!!t.has_luggage_storage,y=t.year_opened!=null?Number(t.year_opened):null,h=t.operator_count!=null?Number(t.operator_count):0,S=t.route_count!=null?Number(t.route_count):0,$=t.popularity_score!=null?Number(t.popularity_score):0,x=`https://${e.domain}/station/${o(n)}/`,v=N(i),b=p||c||f;return`
|
|
425
|
+
<div class="transportfyi-header">
|
|
426
|
+
<div class="transportfyi-img">\u{1F689}</div>
|
|
427
|
+
<div>
|
|
428
|
+
<div class="transportfyi-header-title">${o(r)}</div>
|
|
429
|
+
<div class="transportfyi-header-subtitle">${o(a)}</div>
|
|
430
|
+
</div>
|
|
431
|
+
</div>
|
|
432
|
+
<div style="padding:8px 20px 0;display:flex;gap:6px;flex-wrap:wrap;">
|
|
433
|
+
${i?`<span class="transportfyi-badge" style="background:${e.accent};color:#fff">${o(v)}</span>`:""}
|
|
434
|
+
${d?'<span class="transportfyi-badge" style="background:#16a34a;color:#fff">Main Station</span>':""}
|
|
435
|
+
</div>
|
|
436
|
+
<div class="transportfyi-stat-grid">
|
|
437
|
+
${L(u(h)||"0","Operators")}
|
|
438
|
+
${L(u(S)||"0","Routes")}
|
|
439
|
+
${L(l!=null?String(l):"-","Platforms")}
|
|
440
|
+
</div>
|
|
441
|
+
${b?`
|
|
442
|
+
<div style="padding:8px 20px;">
|
|
443
|
+
<div class="transportfyi-amenities">
|
|
444
|
+
${W(xt,"WiFi",p)}
|
|
445
|
+
${W(bt,"Lounge",c)}
|
|
446
|
+
${W(wt,"Luggage",f)}
|
|
447
|
+
</div>
|
|
448
|
+
</div>
|
|
449
|
+
`:""}
|
|
450
|
+
<div class="transportfyi-kv-rows">
|
|
451
|
+
${m("Timezone",s)}
|
|
452
|
+
${y!=null?m("Opened",String(y)):""}
|
|
453
|
+
${$>0?m("Popularity",String($)):""}
|
|
454
|
+
</div>
|
|
455
|
+
<div class="transportfyi-view-link"><a href="${x}" target="_blank" rel="noopener">View on ${o(e.name)} ${k}</a></div>
|
|
456
|
+
${w(e)}
|
|
457
|
+
`}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 F(t,e){var d;let n=(d=t.dataset.slug)!=null?d:"";if(!n){let l=_(t,e),p=C(l,t,"transportfyi-entity-widget");H(p,"Missing data-slug attribute.",e);return}let i=_(t,e),a=C(i,t,"transportfyi-entity-widget");R(a);let s=$t(e,n);T(e.apiBase,s).then(l=>{var c;let p;switch(e.site){case"airportfyi":p=it(l,e);break;case"airlinefyi":p=ot(l,e);break;case"planefyi":p=at(l,e);break;case"trainfyi":p=st(l,e);break;default:{let f=String((c=l.name)!=null?c:n);p=`
|
|
458
|
+
<div style="padding:16px;">
|
|
459
|
+
<div style="font-size:1rem;font-weight:600;margin-bottom:8px;">${o(f)}</div>
|
|
460
|
+
<a href="https://${e.domain}" target="_blank" rel="noopener"
|
|
461
|
+
style="color:${e.accent};text-decoration:none;font-size:0.85rem;">
|
|
462
|
+
View on ${o(e.name)} ${k}
|
|
463
|
+
</a>
|
|
464
|
+
</div>
|
|
465
|
+
`;break}}a.innerHTML=p}).catch(()=>{H(a,`Unable to load "${o(n)}". Please try again later.`,e)})}function lt(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 pt(t,e){var n,i;let r=String((n=e.slug)!=null?n:"");switch(t.site){case"airportfyi":return`https://${t.domain}/${String((i=e.iata_code)!=null?i:r)}/`;case"trainfyi":return`https://${t.domain}/station/${r}/`;default:return`https://${t.domain}/${r}/`}}function kt(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 D(t,e){var l;let n=((l=t.dataset.slugs)!=null?l:"").split(",").map(p=>p.trim()).filter(Boolean),i=_(t,e),a=C(i,t,"transportfyi-compare-widget");if(n.length<2){H(a,"Missing data-slugs attribute (comma-separated pair).",e);return}R(a);let[s,d]=n;Promise.all([T(e.apiBase,lt(e,s)),T(e.apiBase,lt(e,d))]).then(([p,c])=>{var v,b;let f=String((v=p.name)!=null?v:s),y=String((b=c.name)!=null?b:d),h=pt(e,p),S=pt(e,c),x=kt(e).map(g=>{var z,A;let M=g.fmt?g.fmt(p[g.key]):String((z=p[g.key])!=null?z:"-"),E=g.fmt?g.fmt(c[g.key]):String((A=c[g.key])!=null?A:"-");return`<tr><td style="color:var(--muted);font-size:12px;padding:6px 8px;">${o(g.label)}</td><td style="font-weight:600;padding:6px 8px;text-align:center;">${o(M)}</td><td style="font-weight:600;padding:6px 8px;text-align:center;">${o(E)}</td></tr>`}).join("");a.innerHTML=`
|
|
466
|
+
<div class="transportfyi-header">
|
|
467
|
+
<div>
|
|
468
|
+
<div class="transportfyi-header-title">${o(f)} vs ${o(y)}</div>
|
|
469
|
+
<div class="transportfyi-header-subtitle">Side-by-side comparison</div>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
<div style="padding:0 16px 8px;overflow-x:auto;">
|
|
473
|
+
<table style="width:100%;border-collapse:collapse;font-size:13px;">
|
|
474
|
+
<thead><tr>
|
|
475
|
+
<th style="text-align:left;padding:8px;font-size:11px;color:var(--muted);"></th>
|
|
476
|
+
<th style="text-align:center;padding:8px;font-weight:700;">${o(f)}</th>
|
|
477
|
+
<th style="text-align:center;padding:8px;font-weight:700;">${o(y)}</th>
|
|
478
|
+
</tr></thead>
|
|
479
|
+
<tbody>${x}</tbody>
|
|
480
|
+
</table>
|
|
481
|
+
</div>
|
|
482
|
+
<div style="display:flex;gap:8px;padding:8px 16px;">
|
|
483
|
+
<a href="${o(h)}" target="_blank" rel="noopener" style="flex:1;text-align:center;color:var(--link);font-size:12px;text-decoration:none;">${o(f)} ${k}</a>
|
|
484
|
+
<a href="${o(S)}" target="_blank" rel="noopener" style="flex:1;text-align:center;color:var(--link);font-size:12px;text-decoration:none;">${o(y)} ${k}</a>
|
|
485
|
+
</div>
|
|
486
|
+
${w(e)}
|
|
487
|
+
`}).catch(()=>{H(a,"Unable to load comparison data.",e)})}function St(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 _t(t,e){var n,i;let r=String((n=e.slug)!=null?n:"");switch(t.site){case"airportfyi":{let a=String((i=e.iata_code)!=null?i: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 Ct(t,e){var r,n,i,a,s,d,l;switch(t.site){case"airportfyi":{let p=String((r=e.iata_code)!=null?r:""),c=String((n=e.country_name)!=null?n:"");return[p,c].filter(Boolean).join(" \xB7 ")}case"airlinefyi":{let p=String((i=e.iata_code)!=null?i:""),c=String((a=e.country_name)!=null?a:"");return[p,c].filter(Boolean).join(" \xB7 ")}case"planefyi":return String((s=e.manufacturer_name)!=null?s:"");case"trainfyi":{let p=String((d=e.country_name)!=null?d:"");return[String((l=e.type)!=null?l:""),p].filter(Boolean).join(" \xB7 ")}default:return""}}function P(t,e){let n=t.dataset.placeholder||`Search ${e.entityName}...`,i=_(t,e),a=C(i,t,"transportfyi-search-widget");a.innerHTML=`
|
|
488
|
+
<div class="transportfyi-search-wrap">
|
|
489
|
+
<form class="transportfyi-search-form">
|
|
490
|
+
<input type="text" class="transportfyi-search-input" placeholder="${o(n)}" autocomplete="off" />
|
|
491
|
+
<button type="submit" class="transportfyi-search-btn">Search</button>
|
|
492
|
+
</form>
|
|
493
|
+
</div>
|
|
494
|
+
<div class="transportfyi-search-results" style="display:none;"></div>
|
|
495
|
+
${w(e)}
|
|
496
|
+
`;let s=a.querySelector("form"),d=a.querySelector("input"),l=a.querySelector(".transportfyi-search-results");s.addEventListener("submit",p=>{p.preventDefault();let c=d.value.trim();c&&(l.style.display="block",l.innerHTML='<div style="padding:8px 0;color:var(--muted);font-size:12px;">Searching\u2026</div>',T(e.apiBase,St(e),{search:c,limit:"5"}).then(f=>{let y=f.results||[];if(!y.length){l.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 ${o(e.name)}</a></div>`;return}l.innerHTML=y.map(h=>{var v,b;let S=String((b=(v=h.name)!=null?v:h.slug)!=null?b:""),$=_t(e,h),x=Ct(e,h);return`
|
|
497
|
+
<div class="transportfyi-result-item">
|
|
498
|
+
<a href="${o($)}" target="_blank" rel="noopener" class="transportfyi-result-title" style="color:var(--link);text-decoration:none;">${o(S)}</a>
|
|
499
|
+
${x?`<div class="transportfyi-result-meta">${o(x)}</div>`:""}
|
|
500
|
+
</div>
|
|
501
|
+
`}).join("")}).catch(()=>{l.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 ${o(e.name)}</a></div>`}))})}function dt(t,e,r){if(document.querySelector('script[data-transportfyi-snippet="faq"]'))return;let n={"@context":"https://schema.org","@type":"FAQPage",mainEntity:t.map(a=>({"@type":"Question",name:a.question,acceptedAnswer:{"@type":"Answer",text:a.answer}})),url:`https://${e}/`},i=document.createElement("script");i.type="application/ld+json",i.setAttribute("data-transportfyi-snippet","faq"),i.textContent=JSON.stringify(n),document.head.appendChild(i)}function q(t,e){let r=t.dataset,n=_(t,e),i=C(n,t,"transportfyi-faq-widget");R(i),T(e.apiBase,"faqs/",{limit:"10"}).then(a=>{let s=a.results||[];i.innerHTML=nt(s,e),r.noSnippet!=="true"&&s.length>0&&dt(s,e.domain,e.name)}).catch(()=>{H(i,"Unable to load FAQs.",e)})}function Tt(t,e){switch(t.site){case"airportfyi":return`airports/${e}/`;case"trainfyi":return`stations/${e}/`;default:return""}}function ct(t,e){var s;let r=(s=t.dataset.slug)!=null?s:"";if(!r)return;let n=Tt(e,r);if(!n)return;let i=_(t,e),a=C(i,t);a.style.display="inline-block",a.style.maxWidth="none",a.style.border="none",a.style.borderRadius="4px",T(e.apiBase,n).then(d=>{var c;let l=String((c=d.type)!=null?c:""),p=e.site==="airportfyi"?I(l):N(l);a.innerHTML=`<span class="transportfyi-badge" style="background:${e.accent};color:#fff">${o(p)}</span>`}).catch(()=>{a.innerHTML=""})}var O={wifi:"\u{1F4F6}",lounge:"\u{1F6CB}\uFE0F",luggage:"\u{1F9F3}"};function ft(t,e){var a;let r=(a=t.dataset.slug)!=null?a:"";if(!r)return;let n=_(t,e),i=C(n,t);i.style.display="inline-flex",i.style.maxWidth="none",i.style.border="none",i.style.gap="4px",T(e.apiBase,`stations/${r}/`).then(s=>{let d=[];if(s.has_wifi&&d.push(`${O.wifi} WiFi`),s.has_lounge&&d.push(`${O.lounge} Lounge`),s.has_luggage_storage&&d.push(`${O.luggage} Luggage`),!d.length){i.innerHTML="";return}i.innerHTML=d.map(l=>`<span class="transportfyi-badge" style="font-size:10px;">${l}</span>`).join("")}).catch(()=>{i.innerHTML=""})}function Lt(t,e,r){let n=t.dataset.style||"modern";switch(e){case"entity":F(t,r);break;case"compare":D(t,r);break;case"search":P(t,r);break;case"faq":q(t,r);break;case"type-badge":ct(t,r);break;case"amenities":ft(t,r);break;default:break}}function Mt(t,e){if("IntersectionObserver"in window){let r=new IntersectionObserver(n=>{n.forEach(i=>{i.isIntersecting&&(r.unobserve(t),e())})},{rootMargin:"200px"});r.observe(t)}else e()}function U(t,e){if(t.shadowRoot)return;let n=e.attribute.replace("data-","").replace(/-([a-z])/g,(a,s)=>s.toUpperCase()),i=t.dataset[n];i&&Mt(t,()=>{t.shadowRoot||Lt(t,i,e)})}function ut(t){document.querySelectorAll(`[${t.attribute}]`).forEach(e=>U(e,t))}(function(){let e='{"site":"trainfyi","name":"TrainFYI","domain":"trainfyi.com","accent":"#EA580C","attribute":"data-trainfyi","apiBase":"https://trainfyi.com/api/v1/","searchPath":"/search/","entityName":"Stations","entitySlug":"stations"}';document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>ut(e)):ut(e),new MutationObserver(n=>{n.forEach(i=>{i.addedNodes.forEach(a=>{var d;if(a.nodeType!==Node.ELEMENT_NODE)return;let s=a;s.hasAttribute(e.attribute)&&U(s,e),(d=s.querySelectorAll)==null||d.call(s,`[${e.attribute}]`).forEach(l=>U(l,e))})})}).observe(document.body||document.documentElement,{childList:!0,subtree:!0})})();function Et(t,e,r){let n=[...r,"theme","style-variant","size"];return class extends HTMLElement{static get observedAttributes(){return n}connectedCallback(){this.shadowRoot||(this._syncDataAttrs(),e(this,'{"site":"trainfyi","name":"TrainFYI","domain":"trainfyi.com","accent":"#EA580C","attribute":"data-trainfyi","apiBase":"https://trainfyi.com/api/v1/","searchPath":"/search/","entityName":"Stations","entitySlug":"stations"}'))}attributeChangedCallback(i,a,s){if(a===s||!this.shadowRoot)return;let d=this.shadowRoot;for(;d.firstChild;)d.firstChild.remove();this._syncDataAttrs(),e(this,'{"site":"trainfyi","name":"TrainFYI","domain":"trainfyi.com","accent":"#EA580C","attribute":"data-trainfyi","apiBase":"https://trainfyi.com/api/v1/","searchPath":"/search/","entityName":"Stations","entitySlug":"stations"}')}_syncDataAttrs(){let i='{"site":"trainfyi","name":"TrainFYI","domain":"trainfyi.com","accent":"#EA580C","attribute":"data-trainfyi","apiBase":"https://trainfyi.com/api/v1/","searchPath":"/search/","entityName":"Stations","entitySlug":"stations"}'.attribute.replace("data-","");this.dataset[i]=t;for(let l of r){let p=this.getAttribute(l);p!==null&&(this.dataset[l]=p)}let a=this.getAttribute("theme");a!==null&&(this.dataset.theme=a);let s=this.getAttribute("style-variant");s!==null&&(this.dataset.style=s);let d=this.getAttribute("size");d!==null&&(this.dataset.size=d)}}}(function(){if(typeof customElements=="undefined")return;let e='{"site":"trainfyi","name":"TrainFYI","domain":"trainfyi.com","accent":"#EA580C","attribute":"data-trainfyi","apiBase":"https://trainfyi.com/api/v1/","searchPath":"/search/","entityName":"Stations","entitySlug":"stations"}'.site,r=[[`${e}-entity`,F,["slug"]],[`${e}-compare`,D,["slugs"]],[`${e}-search`,P,["placeholder","query"]],[`${e}-faq`,q,["slug","category"]]];for(let[n,i,a]of r)if(!customElements.get(n)){let s=n.slice(e.length+1);customElements.define(n,Et(s,i,a))}})();})();
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* trainfyi-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 TrainFYI */
|
|
14
|
+
'trainfyi'?: 'entity' | 'faq' | 'search' | 'compare' | 'type-badge' | 'amenities';
|
|
15
|
+
/** Entity slug (e.g. "stations") */
|
|
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
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "trainfyi-embed",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Embed TrainFYI widgets — station cards, search, comparisons, amenity badges. 51,425 stations. Zero dependencies, Shadow DOM, 4 themes.",
|
|
5
|
+
"main": "dist/embed.min.js",
|
|
6
|
+
"module": "dist/embed.esm.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist/",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"train",
|
|
15
|
+
"railway",
|
|
16
|
+
"station",
|
|
17
|
+
"rail",
|
|
18
|
+
"operator",
|
|
19
|
+
"transit",
|
|
20
|
+
"route",
|
|
21
|
+
"embed",
|
|
22
|
+
"widget",
|
|
23
|
+
"trainfyi",
|
|
24
|
+
"trainfyi.com",
|
|
25
|
+
"shadow-dom",
|
|
26
|
+
"zero-dependencies",
|
|
27
|
+
"fyipedia",
|
|
28
|
+
"transportfyi"
|
|
29
|
+
],
|
|
30
|
+
"homepage": "https://widget.trainfyi.com",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/fyipedia/trainfyi-embed"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/fyipedia/trainfyi-embed/issues"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"author": "FYIPedia <dev@fyipedia.com>",
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
}
|
|
43
|
+
}
|