@picked/vite-plugin-picked 0.0.1-dev.1772493269328 → 0.0.1-dev.1773363643396
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/dist/cjs/index.js +449 -26
- package/dist/esm/index.js +529 -105
- package/package.json +3 -3
package/dist/cjs/index.js
CHANGED
|
@@ -1,4 +1,438 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("@picked/client/plugins/dynamic-experiences");function
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const m=require("@picked/client/plugins/dynamic-experiences");var h=Object.freeze,R=Object.defineProperty,I=(e,t)=>h(R(e,"raw",{value:h(t||e.slice())})),y;function b(e){const t=JSON.stringify(e),r=e.length>0?e.map(n=>`
|
|
2
|
+
<div class="feature-row">
|
|
3
|
+
<label>
|
|
4
|
+
<input type="checkbox" data-feature-id="${S(n.key)}" checked>
|
|
5
|
+
<span class="feature-name">${w(n.name)}</span>
|
|
6
|
+
<span class="feature-id">${w(n.key)}</span>
|
|
7
|
+
</label>
|
|
8
|
+
<select data-value-for="${S(n.key)}">
|
|
9
|
+
<option value="true" selected>true</option>
|
|
10
|
+
<option value="false">false</option>
|
|
11
|
+
</select>
|
|
12
|
+
</div>`).join(""):'<p class="text no-features">No features configured for this project.</p>';return String.raw(y||(y=I([`<!DOCTYPE html>
|
|
13
|
+
<html lang="en">
|
|
14
|
+
<head>
|
|
15
|
+
<meta charset="UTF-8">
|
|
16
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
17
|
+
<meta name="robots" content="noindex, nofollow">
|
|
18
|
+
<title>Picked</title>
|
|
19
|
+
<style>
|
|
20
|
+
main {
|
|
21
|
+
position: fixed;
|
|
22
|
+
top: 0;
|
|
23
|
+
right: 0;
|
|
24
|
+
bottom: 0;
|
|
25
|
+
left: 0;
|
|
26
|
+
display: grid;
|
|
27
|
+
align-items: center;
|
|
28
|
+
justify-content: center;
|
|
29
|
+
font-family: monospace;
|
|
30
|
+
color: #4A4A4A
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.wrap {
|
|
34
|
+
padding-left: 1.5rem;
|
|
35
|
+
padding-right: 1.5rem;
|
|
36
|
+
max-width: 480px;
|
|
37
|
+
width: 100%;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.title {
|
|
41
|
+
font-size: 1.125rem;
|
|
42
|
+
font-weight: 700;
|
|
43
|
+
margin-bottom: 0;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.text {
|
|
47
|
+
margin-top: .5rem;
|
|
48
|
+
font-size: .875rem
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.text a {
|
|
52
|
+
color: #4A4A4A;
|
|
53
|
+
text-decoration: none;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.text a:hover {
|
|
57
|
+
cursor: pointer;
|
|
58
|
+
text-decoration: underline
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.preview-form {
|
|
62
|
+
margin-top: 2rem;
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
gap: 0.5rem;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.preview-input {
|
|
69
|
+
padding: 0.5rem;
|
|
70
|
+
border: 1px solid #4A4A4A;
|
|
71
|
+
border-radius: 0;
|
|
72
|
+
font-family: monospace;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.preview-button {
|
|
76
|
+
padding: 0.5rem;
|
|
77
|
+
background: #4A4A4A;
|
|
78
|
+
color: white;
|
|
79
|
+
border: none;
|
|
80
|
+
border-radius: 0;
|
|
81
|
+
cursor: pointer;
|
|
82
|
+
font-family: monospace;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.preview-button:hover {
|
|
86
|
+
opacity: 0.9;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.buttons {
|
|
90
|
+
display: grid;
|
|
91
|
+
gap: 0.5em;
|
|
92
|
+
grid-template-columns: 1fr 1fr;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
#copy-status {
|
|
96
|
+
font-size: 1em;
|
|
97
|
+
text-align: right;
|
|
98
|
+
margin-top: 0.5em;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.features-section {
|
|
102
|
+
margin-top: 1.5rem;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.features-label {
|
|
106
|
+
font-weight: 700;
|
|
107
|
+
font-size: .875rem;
|
|
108
|
+
margin-bottom: 0.5rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.feature-row {
|
|
112
|
+
display: flex;
|
|
113
|
+
align-items: center;
|
|
114
|
+
justify-content: space-between;
|
|
115
|
+
gap: 0.5rem;
|
|
116
|
+
padding: 0.25rem 0;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.feature-row label {
|
|
120
|
+
display: flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
gap: 0.5rem;
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
min-width: 0;
|
|
125
|
+
flex: 1;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.feature-name {
|
|
129
|
+
font-size: .875rem;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.feature-id {
|
|
133
|
+
font-size: .75rem;
|
|
134
|
+
color: #888;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.feature-row select {
|
|
138
|
+
font-family: monospace;
|
|
139
|
+
font-size: .75rem;
|
|
140
|
+
padding: 0.125rem 0.25rem;
|
|
141
|
+
border: 1px solid #4A4A4A;
|
|
142
|
+
border-radius: 0;
|
|
143
|
+
background: white;
|
|
144
|
+
flex-shrink: 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.no-features {
|
|
148
|
+
color: #888;
|
|
149
|
+
font-style: italic;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
.url-history {
|
|
153
|
+
margin-top: 0.5rem;
|
|
154
|
+
font-size: .75rem;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
.url-history-item {
|
|
158
|
+
display: flex;
|
|
159
|
+
align-items: center;
|
|
160
|
+
gap: 0.25rem;
|
|
161
|
+
padding: 0.125rem 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.url-history-item button {
|
|
165
|
+
background: none;
|
|
166
|
+
border: none;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
font-family: monospace;
|
|
169
|
+
font-size: .75rem;
|
|
170
|
+
color: #888;
|
|
171
|
+
padding: 0;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.url-history-item button.url-link {
|
|
175
|
+
color: #4A4A4A;
|
|
176
|
+
text-decoration: none;
|
|
177
|
+
text-align: left;
|
|
178
|
+
overflow: hidden;
|
|
179
|
+
text-overflow: ellipsis;
|
|
180
|
+
white-space: nowrap;
|
|
181
|
+
flex: 1;
|
|
182
|
+
min-width: 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.url-history-item button.url-link:hover {
|
|
186
|
+
text-decoration: underline;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
.url-history-item button.url-delete:hover {
|
|
190
|
+
color: #b71c1c;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
@media (min-width: 640px) {
|
|
194
|
+
.title {
|
|
195
|
+
font-size: 1.25rem
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
.text {
|
|
199
|
+
font-size: 1rem
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
</style>
|
|
203
|
+
</head>
|
|
204
|
+
<body>
|
|
205
|
+
|
|
206
|
+
<main>
|
|
207
|
+
<div class="wrap">
|
|
208
|
+
<p class="title">Picked</p>
|
|
209
|
+
<p class="text">
|
|
210
|
+
Learn more at
|
|
211
|
+
<a href="https://picked.app">
|
|
212
|
+
https://picked.app
|
|
213
|
+
</a>
|
|
214
|
+
</p>
|
|
215
|
+
<div class="preview-form">
|
|
216
|
+
<input type="text" id="url-input" pattern="^(https?://)?.+" placeholder="Enter preview URL" required
|
|
217
|
+
class="preview-input">
|
|
218
|
+
<div id="url-history" class="url-history"></div>
|
|
219
|
+
<div class="features-section">
|
|
220
|
+
<p class="features-label">Features</p>
|
|
221
|
+
`,`
|
|
222
|
+
</div>
|
|
223
|
+
<div class="buttons">
|
|
224
|
+
<button type="button" class="preview-button" id="copy-btn">Copy</button>
|
|
225
|
+
<button type="button" class="preview-button" id="preview-btn">Preview</button>
|
|
226
|
+
</div>
|
|
227
|
+
<p class="text" id="copy-status" aria-live="polite" style="visibility:hidden;">
|
|
228
|
+
|
|
229
|
+
</p>
|
|
230
|
+
</div>
|
|
231
|
+
</div>
|
|
232
|
+
|
|
233
|
+
<script>
|
|
234
|
+
var FEATURES = `,`;
|
|
235
|
+
var STORAGE_KEY_URL = 'picked-launcher-url';
|
|
236
|
+
var STORAGE_KEY_HISTORY = 'picked-launcher-history';
|
|
237
|
+
var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
|
|
238
|
+
|
|
239
|
+
function getUrlInput() {
|
|
240
|
+
return document.getElementById('url-input');
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// URL history
|
|
244
|
+
function getHistory() {
|
|
245
|
+
try {
|
|
246
|
+
var raw = localStorage.getItem(STORAGE_KEY_HISTORY);
|
|
247
|
+
if (!raw) return [];
|
|
248
|
+
var parsed = JSON.parse(raw);
|
|
249
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
250
|
+
} catch (e) {
|
|
251
|
+
return [];
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function saveHistory(history) {
|
|
256
|
+
localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function addToHistory(url) {
|
|
260
|
+
var history = getHistory().filter(function(h) { return h !== url; });
|
|
261
|
+
history.unshift(url);
|
|
262
|
+
if (history.length > 10) history = history.slice(0, 10);
|
|
263
|
+
saveHistory(history);
|
|
264
|
+
renderHistory();
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function removeFromHistory(url) {
|
|
268
|
+
var history = getHistory().filter(function(h) { return h !== url; });
|
|
269
|
+
saveHistory(history);
|
|
270
|
+
renderHistory();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function renderHistory() {
|
|
274
|
+
var container = document.getElementById('url-history');
|
|
275
|
+
if (!container) return;
|
|
276
|
+
var history = getHistory();
|
|
277
|
+
if (history.length === 0) {
|
|
278
|
+
container.innerHTML = '';
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
container.innerHTML = history.map(function(url) {
|
|
282
|
+
return '<div class="url-history-item">' +
|
|
283
|
+
'<button type="button" class="url-link" data-history-url="' + escapeAttr(url) + '">' + escapeHtml(url) + '</button>' +
|
|
284
|
+
'<button type="button" class="url-delete" data-history-delete="' + escapeAttr(url) + '">x</button>' +
|
|
285
|
+
'</div>';
|
|
286
|
+
}).join('');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Feature selection persistence
|
|
290
|
+
function getSelections() {
|
|
291
|
+
try {
|
|
292
|
+
var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);
|
|
293
|
+
if (!raw) return {};
|
|
294
|
+
var parsed = JSON.parse(raw);
|
|
295
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : {};
|
|
296
|
+
} catch (e) {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function saveSelections() {
|
|
302
|
+
var selections = {};
|
|
303
|
+
FEATURES.forEach(function(f) {
|
|
304
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
305
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
306
|
+
if (checkbox && select) {
|
|
307
|
+
selections[f.key] = { checked: checkbox.checked, value: select.value };
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function restoreSelections() {
|
|
314
|
+
var selections = getSelections();
|
|
315
|
+
FEATURES.forEach(function(f) {
|
|
316
|
+
var saved = selections[f.key];
|
|
317
|
+
if (!saved) return;
|
|
318
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
319
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
320
|
+
if (checkbox) checkbox.checked = saved.checked;
|
|
321
|
+
if (select) select.value = saved.value;
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function escapeHtml(str) {
|
|
326
|
+
var div = document.createElement('div');
|
|
327
|
+
div.textContent = str;
|
|
328
|
+
return div.innerHTML;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function escapeAttr(str) {
|
|
332
|
+
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function buildTargetUrl(inputValue) {
|
|
336
|
+
var value = inputValue;
|
|
337
|
+
if (!value.startsWith('http://') && !value.startsWith('https://')) {
|
|
338
|
+
value = 'https://' + value;
|
|
339
|
+
}
|
|
340
|
+
var hostname = window.location.hostname;
|
|
341
|
+
var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';
|
|
342
|
+
var target = value;
|
|
343
|
+
var sep = target.includes('?') ? '&' : '?';
|
|
344
|
+
if (subdomain) {
|
|
345
|
+
target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);
|
|
346
|
+
sep = '&';
|
|
347
|
+
}
|
|
348
|
+
FEATURES.forEach(function(f) {
|
|
349
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
350
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
351
|
+
if (checkbox && checkbox.checked && select) {
|
|
352
|
+
target = target + sep + 'picked-feature=' + encodeURIComponent(f.key + ':' + select.value);
|
|
353
|
+
sep = '&';
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
return target;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function showCopyStatus(message, success) {
|
|
360
|
+
var el = document.getElementById('copy-status');
|
|
361
|
+
if (!el) return;
|
|
362
|
+
el.textContent = message;
|
|
363
|
+
el.style.visibility = 'visible';
|
|
364
|
+
el.style.color = success ? '#2e7d32' : '#b71c1c';
|
|
365
|
+
setTimeout(function() {
|
|
366
|
+
el.style.visibility = 'hidden';
|
|
367
|
+
}, 2000);
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Init
|
|
371
|
+
window.addEventListener('load', function() {
|
|
372
|
+
var input = getUrlInput();
|
|
373
|
+
var savedUrl = localStorage.getItem(STORAGE_KEY_URL);
|
|
374
|
+
if (savedUrl && input) {
|
|
375
|
+
input.value = savedUrl;
|
|
376
|
+
}
|
|
377
|
+
renderHistory();
|
|
378
|
+
restoreSelections();
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// Delegate click events
|
|
382
|
+
document.addEventListener('click', function(e) {
|
|
383
|
+
var target = e.target;
|
|
384
|
+
|
|
385
|
+
// History URL click
|
|
386
|
+
var historyUrl = target.getAttribute('data-history-url');
|
|
387
|
+
if (historyUrl) {
|
|
388
|
+
var input = getUrlInput();
|
|
389
|
+
if (input) input.value = historyUrl;
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// History delete click
|
|
394
|
+
var deleteUrl = target.getAttribute('data-history-delete');
|
|
395
|
+
if (deleteUrl) {
|
|
396
|
+
removeFromHistory(deleteUrl);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
// Feature change persistence
|
|
402
|
+
document.addEventListener('change', function(e) {
|
|
403
|
+
var target = e.target;
|
|
404
|
+
if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {
|
|
405
|
+
saveSelections();
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
// Copy button
|
|
410
|
+
document.getElementById('copy-btn').addEventListener('click', function() {
|
|
411
|
+
var input = getUrlInput();
|
|
412
|
+
if (!input || !input.value) return;
|
|
413
|
+
localStorage.setItem(STORAGE_KEY_URL, input.value);
|
|
414
|
+
addToHistory(input.value);
|
|
415
|
+
saveSelections();
|
|
416
|
+
var target = buildTargetUrl(input.value);
|
|
417
|
+
navigator.clipboard.writeText(target).then(function() {
|
|
418
|
+
showCopyStatus('Preview URL copied to clipboard', true);
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
|
|
422
|
+
// Preview button
|
|
423
|
+
document.getElementById('preview-btn').addEventListener('click', function() {
|
|
424
|
+
var input = getUrlInput();
|
|
425
|
+
if (!input || !input.value) return;
|
|
426
|
+
localStorage.setItem(STORAGE_KEY_URL, input.value);
|
|
427
|
+
addToHistory(input.value);
|
|
428
|
+
saveSelections();
|
|
429
|
+
var target = buildTargetUrl(input.value);
|
|
430
|
+
window.location.href = target;
|
|
431
|
+
});
|
|
432
|
+
<\/script>
|
|
433
|
+
</main>
|
|
434
|
+
</body>
|
|
435
|
+
</html>`],[`<!DOCTYPE html>
|
|
2
436
|
<html lang="en">
|
|
3
437
|
<head>
|
|
4
438
|
<meta charset="UTF-8">
|
|
@@ -207,18 +641,7 @@
|
|
|
207
641
|
<div id="url-history" class="url-history"></div>
|
|
208
642
|
<div class="features-section">
|
|
209
643
|
<p class="features-label">Features</p>
|
|
210
|
-
|
|
211
|
-
<div class="feature-row">
|
|
212
|
-
<label>
|
|
213
|
-
<input type="checkbox" data-feature-id="${b(r.id)}" checked>
|
|
214
|
-
<span class="feature-name">${y(r.name)}</span>
|
|
215
|
-
<span class="feature-id">${y(r.id)}</span>
|
|
216
|
-
</label>
|
|
217
|
-
<select data-value-for="${b(r.id)}">
|
|
218
|
-
<option value="true" selected>true</option>
|
|
219
|
-
<option value="false">false</option>
|
|
220
|
-
</select>
|
|
221
|
-
</div>`).join(""):'<p class="text no-features">No features configured for this project.</p>'}
|
|
644
|
+
`,`
|
|
222
645
|
</div>
|
|
223
646
|
<div class="buttons">
|
|
224
647
|
<button type="button" class="preview-button" id="copy-btn">Copy</button>
|
|
@@ -231,7 +654,7 @@
|
|
|
231
654
|
</div>
|
|
232
655
|
|
|
233
656
|
<script>
|
|
234
|
-
var FEATURES =
|
|
657
|
+
var FEATURES = `,`;
|
|
235
658
|
var STORAGE_KEY_URL = 'picked-launcher-url';
|
|
236
659
|
var STORAGE_KEY_HISTORY = 'picked-launcher-history';
|
|
237
660
|
var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
|
|
@@ -301,10 +724,10 @@
|
|
|
301
724
|
function saveSelections() {
|
|
302
725
|
var selections = {};
|
|
303
726
|
FEATURES.forEach(function(f) {
|
|
304
|
-
var checkbox = document.querySelector('input[data-feature-id="' + f.
|
|
305
|
-
var select = document.querySelector('select[data-value-for="' + f.
|
|
727
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
728
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
306
729
|
if (checkbox && select) {
|
|
307
|
-
selections[f.
|
|
730
|
+
selections[f.key] = { checked: checkbox.checked, value: select.value };
|
|
308
731
|
}
|
|
309
732
|
});
|
|
310
733
|
localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
|
|
@@ -313,10 +736,10 @@
|
|
|
313
736
|
function restoreSelections() {
|
|
314
737
|
var selections = getSelections();
|
|
315
738
|
FEATURES.forEach(function(f) {
|
|
316
|
-
var saved = selections[f.
|
|
739
|
+
var saved = selections[f.key];
|
|
317
740
|
if (!saved) return;
|
|
318
|
-
var checkbox = document.querySelector('input[data-feature-id="' + f.
|
|
319
|
-
var select = document.querySelector('select[data-value-for="' + f.
|
|
741
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
742
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
320
743
|
if (checkbox) checkbox.checked = saved.checked;
|
|
321
744
|
if (select) select.value = saved.value;
|
|
322
745
|
});
|
|
@@ -346,10 +769,10 @@
|
|
|
346
769
|
sep = '&';
|
|
347
770
|
}
|
|
348
771
|
FEATURES.forEach(function(f) {
|
|
349
|
-
var checkbox = document.querySelector('input[data-feature-id="' + f.
|
|
350
|
-
var select = document.querySelector('select[data-value-for="' + f.
|
|
772
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
773
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
351
774
|
if (checkbox && checkbox.checked && select) {
|
|
352
|
-
target = target + sep + 'picked-feature=' + encodeURIComponent(f.
|
|
775
|
+
target = target + sep + 'picked-feature=' + encodeURIComponent(f.key + ':' + select.value);
|
|
353
776
|
sep = '&';
|
|
354
777
|
}
|
|
355
778
|
});
|
|
@@ -432,7 +855,7 @@
|
|
|
432
855
|
<\/script>
|
|
433
856
|
</main>
|
|
434
857
|
</body>
|
|
435
|
-
</html>`}function
|
|
858
|
+
</html>`])),r,t)}function w(e){return e.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""")}function S(e){return e.replaceAll("&","&").replaceAll('"',""").replaceAll("<","<").replaceAll(">",">")}const E="picked",L="\x1B[0m";function O(){const e=process.env.NO_COLOR;return e==="1"||e==="true"}function c(e){return t=>O()?t:`${e}${t}${L}`}const x=["debug","info","warn","error","silent"],v={debug:{color:c("\x1B[2m"),log:console.debug,enabled:!1},info:{color:c("\x1B[36m"),log:console.log,enabled:!0},warn:{color:c("\x1B[33m"),log:console.warn,enabled:!0},error:{color:c("\x1B[31m"),log:console.error,enabled:!0},silent:{log:()=>{},enabled:!1}};function H(e,t){const r=new Date().toLocaleTimeString(),n=t?`${E}:${t}`:E;return`${r} [${n}] ${e}`}function g(e,t,r,n){if(!e.enabled)return;const o=H(t,n);e.log(e.color?e.color(o):o),r!==void 0&&e.log(r)}function p(e){const t=v[e],r=new Set;return Object.assign((n,o,i)=>{g(t,n,o,i)},{once(n,o,i){!t.enabled||r.has(n)||(r.add(n),g(t,n,o,i))}})}function $(e){const t=x.indexOf(e);if(t===-1){g(v.error,`invalid log level: ${e}`);return}for(const[r,n]of x.entries())v[n].enabled=r>=t}const s=c("\x1B[34m"),_=c("\x1B[36m");function C(){const e=[` ${s("_")} ${_("_")} _ _ _`,`${s("(_)")} ${_("(_)")} _ __(_)__| |_____ __| |`,` ${s("_")} ${s("_")} | '_ \\ / _| / / -_) _\` |`,`${s("(_)")} ${s("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,` |_|
|
|
436
859
|
`];console.log(e.join(`
|
|
437
|
-
`))}const
|
|
438
|
-
`))}function
|
|
860
|
+
`))}const l={banner:C,debug:p("debug"),info:p("info"),warn:p("warn"),error:p("error"),setLevel:$};function Y(e){return(t,r,n)=>{if(t.method!=="GET"){n();return}const i=(t.url??"").split("?")[0];if(i!=="/"&&i!=="/index.html"){n();return}const a=e();r.setHeader("Content-Type","text/html"),r.statusCode=200,r.end(a)}}function B(e){if(e.length===0)return;const t=Math.max(4,...e.map(a=>a.name.length)),r=Math.max(3,...e.map(a=>a.key.length)),n=` ${"Name".padEnd(t)} ${"Key".padEnd(r)} Status Weight Ver`,o=` ${"─".repeat(t)} ${"─".repeat(r)} ──────── ────── ───`,i=e.map(a=>{const d=a.enabled?"\x1B[32m enabled\x1B[0m":"\x1B[2mdisabled\x1B[0m",u=`${a.weight.toString()}%`.padStart(6),f=`v${a.version.toString()}`;return` ${a.name.padEnd(t)} ${a.key.padEnd(r)} ${d} ${u} ${f}`});console.log([""," Features:","",n,o,...i,""].join(`
|
|
861
|
+
`))}function F(e){try{const t=new URL(e).hostname;return t==="localhost"||t==="127.0.0.1"||t==="::1"}catch{return!1}}function P(e){return new Promise(t=>{setTimeout(t,e)})}async function z(e,t,r){const n=await m.fetchProject(e,t,{headers:r});if(n||!F(e))return n;for(let o=1;o<=A;o++){l.info(`local API not ready, retrying in ${(T/1e3).toString()}s (${o.toString()}/${A.toString()})`),await P(T);const i=await m.fetchProject(e,t,{headers:r});if(i)return i}return null}function N(){return"0.0.1-dev.1773363643396"}const k="https://api.picked.app",j="__PICKED_PROJECT_CONFIG__",A=5,T=2e3;function K(e){const t=e.apiUrl??k;let r=[];return{name:"picked",config:async()=>{l.banner(),l.info(`fetching project config for "${e.projectId}"`),t!==k&&l.warn(`using custom API URL: ${t}`);const n=m.createClientHeaders("vite-plugin",N()),o=performance.now(),i=await z(t,e.projectId,n),a=(performance.now()-o).toFixed(0);if(!i){l.warn(`failed to fetch project config for "${e.projectId}" (${a}ms)`);return}r=i.features;const d=i.features.length,u=i.features.filter(U=>U.enabled).length,f=JSON.stringify(i).length;return l.info(`fetched ${d.toString()} features (${u.toString()} enabled) for "${e.projectId}" in ${a}ms`),B(i.features),l.debug(`config size: ${f.toString()} bytes`),{define:{[j]:JSON.stringify(i)}}},configureServer(n){if(e.disableLauncher)return;n.middlewares.use(Y(()=>b(r)));const o=n.printUrls.bind(n);n.printUrls=()=>{const i=n.resolvedUrls?.local[0];if(i){const a=i.replace(/:(?<port>\d+)\//,(d,u)=>`:\x1B[1m${u}\x1B[22m/`);console.log(` \x1B[32m➜\x1B[0m \x1B[1mPicked\x1B[22m: \x1B[36m${a}\x1B[0m`)}o()}},generateBundle(){e.disableLauncher||this.emitFile({type:"asset",fileName:"index.html",source:b(r)})}}}exports.picked=K;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,7 +1,444 @@
|
|
|
1
|
-
import { createClientHeaders as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import { createClientHeaders as R, fetchProject as g } from "@picked/client/plugins/dynamic-experiences";
|
|
2
|
+
var h = Object.freeze, I = Object.defineProperty, L = (e, t) => h(I(e, "raw", { value: h(t || e.slice()) })), y;
|
|
3
|
+
function b(e) {
|
|
4
|
+
const t = JSON.stringify(e), r = e.length > 0 ? e.map(
|
|
5
|
+
(n) => `
|
|
6
|
+
<div class="feature-row">
|
|
7
|
+
<label>
|
|
8
|
+
<input type="checkbox" data-feature-id="${S(n.key)}" checked>
|
|
9
|
+
<span class="feature-name">${w(n.name)}</span>
|
|
10
|
+
<span class="feature-id">${w(n.key)}</span>
|
|
11
|
+
</label>
|
|
12
|
+
<select data-value-for="${S(n.key)}">
|
|
13
|
+
<option value="true" selected>true</option>
|
|
14
|
+
<option value="false">false</option>
|
|
15
|
+
</select>
|
|
16
|
+
</div>`
|
|
17
|
+
).join("") : '<p class="text no-features">No features configured for this project.</p>';
|
|
18
|
+
return String.raw(y || (y = L([`<!DOCTYPE html>
|
|
19
|
+
<html lang="en">
|
|
20
|
+
<head>
|
|
21
|
+
<meta charset="UTF-8">
|
|
22
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
23
|
+
<meta name="robots" content="noindex, nofollow">
|
|
24
|
+
<title>Picked</title>
|
|
25
|
+
<style>
|
|
26
|
+
main {
|
|
27
|
+
position: fixed;
|
|
28
|
+
top: 0;
|
|
29
|
+
right: 0;
|
|
30
|
+
bottom: 0;
|
|
31
|
+
left: 0;
|
|
32
|
+
display: grid;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
font-family: monospace;
|
|
36
|
+
color: #4A4A4A
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.wrap {
|
|
40
|
+
padding-left: 1.5rem;
|
|
41
|
+
padding-right: 1.5rem;
|
|
42
|
+
max-width: 480px;
|
|
43
|
+
width: 100%;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.title {
|
|
47
|
+
font-size: 1.125rem;
|
|
48
|
+
font-weight: 700;
|
|
49
|
+
margin-bottom: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.text {
|
|
53
|
+
margin-top: .5rem;
|
|
54
|
+
font-size: .875rem
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.text a {
|
|
58
|
+
color: #4A4A4A;
|
|
59
|
+
text-decoration: none;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.text a:hover {
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
text-decoration: underline
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.preview-form {
|
|
68
|
+
margin-top: 2rem;
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: 0.5rem;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.preview-input {
|
|
75
|
+
padding: 0.5rem;
|
|
76
|
+
border: 1px solid #4A4A4A;
|
|
77
|
+
border-radius: 0;
|
|
78
|
+
font-family: monospace;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.preview-button {
|
|
82
|
+
padding: 0.5rem;
|
|
83
|
+
background: #4A4A4A;
|
|
84
|
+
color: white;
|
|
85
|
+
border: none;
|
|
86
|
+
border-radius: 0;
|
|
87
|
+
cursor: pointer;
|
|
88
|
+
font-family: monospace;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.preview-button:hover {
|
|
92
|
+
opacity: 0.9;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.buttons {
|
|
96
|
+
display: grid;
|
|
97
|
+
gap: 0.5em;
|
|
98
|
+
grid-template-columns: 1fr 1fr;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
#copy-status {
|
|
102
|
+
font-size: 1em;
|
|
103
|
+
text-align: right;
|
|
104
|
+
margin-top: 0.5em;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.features-section {
|
|
108
|
+
margin-top: 1.5rem;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.features-label {
|
|
112
|
+
font-weight: 700;
|
|
113
|
+
font-size: .875rem;
|
|
114
|
+
margin-bottom: 0.5rem;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.feature-row {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
justify-content: space-between;
|
|
121
|
+
gap: 0.5rem;
|
|
122
|
+
padding: 0.25rem 0;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.feature-row label {
|
|
126
|
+
display: flex;
|
|
127
|
+
align-items: center;
|
|
128
|
+
gap: 0.5rem;
|
|
129
|
+
cursor: pointer;
|
|
130
|
+
min-width: 0;
|
|
131
|
+
flex: 1;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
.feature-name {
|
|
135
|
+
font-size: .875rem;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.feature-id {
|
|
139
|
+
font-size: .75rem;
|
|
140
|
+
color: #888;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
.feature-row select {
|
|
144
|
+
font-family: monospace;
|
|
145
|
+
font-size: .75rem;
|
|
146
|
+
padding: 0.125rem 0.25rem;
|
|
147
|
+
border: 1px solid #4A4A4A;
|
|
148
|
+
border-radius: 0;
|
|
149
|
+
background: white;
|
|
150
|
+
flex-shrink: 0;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
.no-features {
|
|
154
|
+
color: #888;
|
|
155
|
+
font-style: italic;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
.url-history {
|
|
159
|
+
margin-top: 0.5rem;
|
|
160
|
+
font-size: .75rem;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
.url-history-item {
|
|
164
|
+
display: flex;
|
|
165
|
+
align-items: center;
|
|
166
|
+
gap: 0.25rem;
|
|
167
|
+
padding: 0.125rem 0;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.url-history-item button {
|
|
171
|
+
background: none;
|
|
172
|
+
border: none;
|
|
173
|
+
cursor: pointer;
|
|
174
|
+
font-family: monospace;
|
|
175
|
+
font-size: .75rem;
|
|
176
|
+
color: #888;
|
|
177
|
+
padding: 0;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.url-history-item button.url-link {
|
|
181
|
+
color: #4A4A4A;
|
|
182
|
+
text-decoration: none;
|
|
183
|
+
text-align: left;
|
|
184
|
+
overflow: hidden;
|
|
185
|
+
text-overflow: ellipsis;
|
|
186
|
+
white-space: nowrap;
|
|
187
|
+
flex: 1;
|
|
188
|
+
min-width: 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.url-history-item button.url-link:hover {
|
|
192
|
+
text-decoration: underline;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.url-history-item button.url-delete:hover {
|
|
196
|
+
color: #b71c1c;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
@media (min-width: 640px) {
|
|
200
|
+
.title {
|
|
201
|
+
font-size: 1.25rem
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
.text {
|
|
205
|
+
font-size: 1rem
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
</style>
|
|
209
|
+
</head>
|
|
210
|
+
<body>
|
|
211
|
+
|
|
212
|
+
<main>
|
|
213
|
+
<div class="wrap">
|
|
214
|
+
<p class="title">Picked</p>
|
|
215
|
+
<p class="text">
|
|
216
|
+
Learn more at
|
|
217
|
+
<a href="https://picked.app">
|
|
218
|
+
https://picked.app
|
|
219
|
+
</a>
|
|
220
|
+
</p>
|
|
221
|
+
<div class="preview-form">
|
|
222
|
+
<input type="text" id="url-input" pattern="^(https?://)?.+" placeholder="Enter preview URL" required
|
|
223
|
+
class="preview-input">
|
|
224
|
+
<div id="url-history" class="url-history"></div>
|
|
225
|
+
<div class="features-section">
|
|
226
|
+
<p class="features-label">Features</p>
|
|
227
|
+
`, `
|
|
228
|
+
</div>
|
|
229
|
+
<div class="buttons">
|
|
230
|
+
<button type="button" class="preview-button" id="copy-btn">Copy</button>
|
|
231
|
+
<button type="button" class="preview-button" id="preview-btn">Preview</button>
|
|
232
|
+
</div>
|
|
233
|
+
<p class="text" id="copy-status" aria-live="polite" style="visibility:hidden;">
|
|
234
|
+
|
|
235
|
+
</p>
|
|
236
|
+
</div>
|
|
237
|
+
</div>
|
|
238
|
+
|
|
239
|
+
<script>
|
|
240
|
+
var FEATURES = `, `;
|
|
241
|
+
var STORAGE_KEY_URL = 'picked-launcher-url';
|
|
242
|
+
var STORAGE_KEY_HISTORY = 'picked-launcher-history';
|
|
243
|
+
var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
|
|
244
|
+
|
|
245
|
+
function getUrlInput() {
|
|
246
|
+
return document.getElementById('url-input');
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// URL history
|
|
250
|
+
function getHistory() {
|
|
251
|
+
try {
|
|
252
|
+
var raw = localStorage.getItem(STORAGE_KEY_HISTORY);
|
|
253
|
+
if (!raw) return [];
|
|
254
|
+
var parsed = JSON.parse(raw);
|
|
255
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
256
|
+
} catch (e) {
|
|
257
|
+
return [];
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function saveHistory(history) {
|
|
262
|
+
localStorage.setItem(STORAGE_KEY_HISTORY, JSON.stringify(history));
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function addToHistory(url) {
|
|
266
|
+
var history = getHistory().filter(function(h) { return h !== url; });
|
|
267
|
+
history.unshift(url);
|
|
268
|
+
if (history.length > 10) history = history.slice(0, 10);
|
|
269
|
+
saveHistory(history);
|
|
270
|
+
renderHistory();
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function removeFromHistory(url) {
|
|
274
|
+
var history = getHistory().filter(function(h) { return h !== url; });
|
|
275
|
+
saveHistory(history);
|
|
276
|
+
renderHistory();
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function renderHistory() {
|
|
280
|
+
var container = document.getElementById('url-history');
|
|
281
|
+
if (!container) return;
|
|
282
|
+
var history = getHistory();
|
|
283
|
+
if (history.length === 0) {
|
|
284
|
+
container.innerHTML = '';
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
container.innerHTML = history.map(function(url) {
|
|
288
|
+
return '<div class="url-history-item">' +
|
|
289
|
+
'<button type="button" class="url-link" data-history-url="' + escapeAttr(url) + '">' + escapeHtml(url) + '</button>' +
|
|
290
|
+
'<button type="button" class="url-delete" data-history-delete="' + escapeAttr(url) + '">x</button>' +
|
|
291
|
+
'</div>';
|
|
292
|
+
}).join('');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Feature selection persistence
|
|
296
|
+
function getSelections() {
|
|
297
|
+
try {
|
|
298
|
+
var raw = localStorage.getItem(STORAGE_KEY_SELECTIONS);
|
|
299
|
+
if (!raw) return {};
|
|
300
|
+
var parsed = JSON.parse(raw);
|
|
301
|
+
return typeof parsed === 'object' && parsed !== null ? parsed : {};
|
|
302
|
+
} catch (e) {
|
|
303
|
+
return {};
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
function saveSelections() {
|
|
308
|
+
var selections = {};
|
|
309
|
+
FEATURES.forEach(function(f) {
|
|
310
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
311
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
312
|
+
if (checkbox && select) {
|
|
313
|
+
selections[f.key] = { checked: checkbox.checked, value: select.value };
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function restoreSelections() {
|
|
320
|
+
var selections = getSelections();
|
|
321
|
+
FEATURES.forEach(function(f) {
|
|
322
|
+
var saved = selections[f.key];
|
|
323
|
+
if (!saved) return;
|
|
324
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
325
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
326
|
+
if (checkbox) checkbox.checked = saved.checked;
|
|
327
|
+
if (select) select.value = saved.value;
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function escapeHtml(str) {
|
|
332
|
+
var div = document.createElement('div');
|
|
333
|
+
div.textContent = str;
|
|
334
|
+
return div.innerHTML;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function escapeAttr(str) {
|
|
338
|
+
return str.replace(/&/g, '&').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function buildTargetUrl(inputValue) {
|
|
342
|
+
var value = inputValue;
|
|
343
|
+
if (!value.startsWith('http://') && !value.startsWith('https://')) {
|
|
344
|
+
value = 'https://' + value;
|
|
345
|
+
}
|
|
346
|
+
var hostname = window.location.hostname;
|
|
347
|
+
var subdomain = hostname.split('.').length > 2 ? hostname.split('.')[0] : '';
|
|
348
|
+
var target = value;
|
|
349
|
+
var sep = target.includes('?') ? '&' : '?';
|
|
350
|
+
if (subdomain) {
|
|
351
|
+
target = target + sep + 'cvly_env=' + encodeURIComponent(subdomain);
|
|
352
|
+
sep = '&';
|
|
353
|
+
}
|
|
354
|
+
FEATURES.forEach(function(f) {
|
|
355
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
356
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
357
|
+
if (checkbox && checkbox.checked && select) {
|
|
358
|
+
target = target + sep + 'picked-feature=' + encodeURIComponent(f.key + ':' + select.value);
|
|
359
|
+
sep = '&';
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
return target;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function showCopyStatus(message, success) {
|
|
366
|
+
var el = document.getElementById('copy-status');
|
|
367
|
+
if (!el) return;
|
|
368
|
+
el.textContent = message;
|
|
369
|
+
el.style.visibility = 'visible';
|
|
370
|
+
el.style.color = success ? '#2e7d32' : '#b71c1c';
|
|
371
|
+
setTimeout(function() {
|
|
372
|
+
el.style.visibility = 'hidden';
|
|
373
|
+
}, 2000);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Init
|
|
377
|
+
window.addEventListener('load', function() {
|
|
378
|
+
var input = getUrlInput();
|
|
379
|
+
var savedUrl = localStorage.getItem(STORAGE_KEY_URL);
|
|
380
|
+
if (savedUrl && input) {
|
|
381
|
+
input.value = savedUrl;
|
|
382
|
+
}
|
|
383
|
+
renderHistory();
|
|
384
|
+
restoreSelections();
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
// Delegate click events
|
|
388
|
+
document.addEventListener('click', function(e) {
|
|
389
|
+
var target = e.target;
|
|
390
|
+
|
|
391
|
+
// History URL click
|
|
392
|
+
var historyUrl = target.getAttribute('data-history-url');
|
|
393
|
+
if (historyUrl) {
|
|
394
|
+
var input = getUrlInput();
|
|
395
|
+
if (input) input.value = historyUrl;
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// History delete click
|
|
400
|
+
var deleteUrl = target.getAttribute('data-history-delete');
|
|
401
|
+
if (deleteUrl) {
|
|
402
|
+
removeFromHistory(deleteUrl);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// Feature change persistence
|
|
408
|
+
document.addEventListener('change', function(e) {
|
|
409
|
+
var target = e.target;
|
|
410
|
+
if (target.getAttribute('data-feature-id') || target.getAttribute('data-value-for')) {
|
|
411
|
+
saveSelections();
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// Copy button
|
|
416
|
+
document.getElementById('copy-btn').addEventListener('click', function() {
|
|
417
|
+
var input = getUrlInput();
|
|
418
|
+
if (!input || !input.value) return;
|
|
419
|
+
localStorage.setItem(STORAGE_KEY_URL, input.value);
|
|
420
|
+
addToHistory(input.value);
|
|
421
|
+
saveSelections();
|
|
422
|
+
var target = buildTargetUrl(input.value);
|
|
423
|
+
navigator.clipboard.writeText(target).then(function() {
|
|
424
|
+
showCopyStatus('Preview URL copied to clipboard', true);
|
|
425
|
+
});
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// Preview button
|
|
429
|
+
document.getElementById('preview-btn').addEventListener('click', function() {
|
|
430
|
+
var input = getUrlInput();
|
|
431
|
+
if (!input || !input.value) return;
|
|
432
|
+
localStorage.setItem(STORAGE_KEY_URL, input.value);
|
|
433
|
+
addToHistory(input.value);
|
|
434
|
+
saveSelections();
|
|
435
|
+
var target = buildTargetUrl(input.value);
|
|
436
|
+
window.location.href = target;
|
|
437
|
+
});
|
|
438
|
+
<\/script>
|
|
439
|
+
</main>
|
|
440
|
+
</body>
|
|
441
|
+
</html>`], [`<!DOCTYPE html>
|
|
5
442
|
<html lang="en">
|
|
6
443
|
<head>
|
|
7
444
|
<meta charset="UTF-8">
|
|
@@ -210,20 +647,7 @@ function v(e) {
|
|
|
210
647
|
<div id="url-history" class="url-history"></div>
|
|
211
648
|
<div class="features-section">
|
|
212
649
|
<p class="features-label">Features</p>
|
|
213
|
-
|
|
214
|
-
(r) => `
|
|
215
|
-
<div class="feature-row">
|
|
216
|
-
<label>
|
|
217
|
-
<input type="checkbox" data-feature-id="${b(r.id)}" checked>
|
|
218
|
-
<span class="feature-name">${y(r.name)}</span>
|
|
219
|
-
<span class="feature-id">${y(r.id)}</span>
|
|
220
|
-
</label>
|
|
221
|
-
<select data-value-for="${b(r.id)}">
|
|
222
|
-
<option value="true" selected>true</option>
|
|
223
|
-
<option value="false">false</option>
|
|
224
|
-
</select>
|
|
225
|
-
</div>`
|
|
226
|
-
).join("") : '<p class="text no-features">No features configured for this project.</p>'}
|
|
650
|
+
`, `
|
|
227
651
|
</div>
|
|
228
652
|
<div class="buttons">
|
|
229
653
|
<button type="button" class="preview-button" id="copy-btn">Copy</button>
|
|
@@ -236,7 +660,7 @@ function v(e) {
|
|
|
236
660
|
</div>
|
|
237
661
|
|
|
238
662
|
<script>
|
|
239
|
-
var FEATURES =
|
|
663
|
+
var FEATURES = `, `;
|
|
240
664
|
var STORAGE_KEY_URL = 'picked-launcher-url';
|
|
241
665
|
var STORAGE_KEY_HISTORY = 'picked-launcher-history';
|
|
242
666
|
var STORAGE_KEY_SELECTIONS = 'picked-launcher-selections';
|
|
@@ -306,10 +730,10 @@ function v(e) {
|
|
|
306
730
|
function saveSelections() {
|
|
307
731
|
var selections = {};
|
|
308
732
|
FEATURES.forEach(function(f) {
|
|
309
|
-
var checkbox = document.querySelector('input[data-feature-id="' + f.
|
|
310
|
-
var select = document.querySelector('select[data-value-for="' + f.
|
|
733
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
734
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
311
735
|
if (checkbox && select) {
|
|
312
|
-
selections[f.
|
|
736
|
+
selections[f.key] = { checked: checkbox.checked, value: select.value };
|
|
313
737
|
}
|
|
314
738
|
});
|
|
315
739
|
localStorage.setItem(STORAGE_KEY_SELECTIONS, JSON.stringify(selections));
|
|
@@ -318,10 +742,10 @@ function v(e) {
|
|
|
318
742
|
function restoreSelections() {
|
|
319
743
|
var selections = getSelections();
|
|
320
744
|
FEATURES.forEach(function(f) {
|
|
321
|
-
var saved = selections[f.
|
|
745
|
+
var saved = selections[f.key];
|
|
322
746
|
if (!saved) return;
|
|
323
|
-
var checkbox = document.querySelector('input[data-feature-id="' + f.
|
|
324
|
-
var select = document.querySelector('select[data-value-for="' + f.
|
|
747
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
748
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
325
749
|
if (checkbox) checkbox.checked = saved.checked;
|
|
326
750
|
if (select) select.value = saved.value;
|
|
327
751
|
});
|
|
@@ -351,10 +775,10 @@ function v(e) {
|
|
|
351
775
|
sep = '&';
|
|
352
776
|
}
|
|
353
777
|
FEATURES.forEach(function(f) {
|
|
354
|
-
var checkbox = document.querySelector('input[data-feature-id="' + f.
|
|
355
|
-
var select = document.querySelector('select[data-value-for="' + f.
|
|
778
|
+
var checkbox = document.querySelector('input[data-feature-id="' + f.key + '"]');
|
|
779
|
+
var select = document.querySelector('select[data-value-for="' + f.key + '"]');
|
|
356
780
|
if (checkbox && checkbox.checked && select) {
|
|
357
|
-
target = target + sep + 'picked-feature=' + encodeURIComponent(f.
|
|
781
|
+
target = target + sep + 'picked-feature=' + encodeURIComponent(f.key + ':' + select.value);
|
|
358
782
|
sep = '&';
|
|
359
783
|
}
|
|
360
784
|
});
|
|
@@ -437,23 +861,23 @@ function v(e) {
|
|
|
437
861
|
<\/script>
|
|
438
862
|
</main>
|
|
439
863
|
</body>
|
|
440
|
-
</html
|
|
864
|
+
</html>`])), r, t);
|
|
441
865
|
}
|
|
442
|
-
function
|
|
443
|
-
return e.
|
|
866
|
+
function w(e) {
|
|
867
|
+
return e.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """);
|
|
444
868
|
}
|
|
445
|
-
function
|
|
446
|
-
return e.
|
|
869
|
+
function S(e) {
|
|
870
|
+
return e.replaceAll("&", "&").replaceAll('"', """).replaceAll("<", "<").replaceAll(">", ">");
|
|
447
871
|
}
|
|
448
|
-
const
|
|
449
|
-
function
|
|
872
|
+
const E = "picked", H = "\x1B[0m";
|
|
873
|
+
function O() {
|
|
450
874
|
const e = process.env.NO_COLOR;
|
|
451
875
|
return e === "1" || e === "true";
|
|
452
876
|
}
|
|
453
877
|
function c(e) {
|
|
454
|
-
return (t) =>
|
|
878
|
+
return (t) => O() ? t : `${e}${t}${H}`;
|
|
455
879
|
}
|
|
456
|
-
const
|
|
880
|
+
const x = ["debug", "info", "warn", "error", "silent"], m = {
|
|
457
881
|
debug: {
|
|
458
882
|
color: c("\x1B[2m"),
|
|
459
883
|
log: console.debug,
|
|
@@ -480,43 +904,43 @@ const w = ["debug", "info", "warn", "error", "silent"], m = {
|
|
|
480
904
|
enabled: !1
|
|
481
905
|
}
|
|
482
906
|
};
|
|
483
|
-
function
|
|
484
|
-
const
|
|
485
|
-
return `${
|
|
907
|
+
function $(e, t) {
|
|
908
|
+
const r = (/* @__PURE__ */ new Date()).toLocaleTimeString(), n = t ? `${E}:${t}` : E;
|
|
909
|
+
return `${r} [${n}] ${e}`;
|
|
486
910
|
}
|
|
487
|
-
function
|
|
911
|
+
function v(e, t, r, n) {
|
|
488
912
|
if (!e.enabled)
|
|
489
913
|
return;
|
|
490
|
-
const
|
|
491
|
-
e.log(e.color ? e.color(
|
|
914
|
+
const o = $(t, n);
|
|
915
|
+
e.log(e.color ? e.color(o) : o), r !== void 0 && e.log(r);
|
|
492
916
|
}
|
|
493
917
|
function p(e) {
|
|
494
|
-
const t = m[e],
|
|
918
|
+
const t = m[e], r = /* @__PURE__ */ new Set();
|
|
495
919
|
return Object.assign(
|
|
496
|
-
(
|
|
497
|
-
|
|
920
|
+
(n, o, i) => {
|
|
921
|
+
v(t, n, o, i);
|
|
498
922
|
},
|
|
499
923
|
{
|
|
500
|
-
once(
|
|
501
|
-
!t.enabled ||
|
|
924
|
+
once(n, o, i) {
|
|
925
|
+
!t.enabled || r.has(n) || (r.add(n), v(t, n, o, i));
|
|
502
926
|
}
|
|
503
927
|
}
|
|
504
928
|
);
|
|
505
929
|
}
|
|
506
|
-
function
|
|
507
|
-
const t =
|
|
930
|
+
function C(e) {
|
|
931
|
+
const t = x.indexOf(e);
|
|
508
932
|
if (t === -1) {
|
|
509
|
-
|
|
933
|
+
v(m.error, `invalid log level: ${e}`);
|
|
510
934
|
return;
|
|
511
935
|
}
|
|
512
|
-
for (const [
|
|
513
|
-
m[
|
|
936
|
+
for (const [r, n] of x.entries())
|
|
937
|
+
m[n].enabled = r >= t;
|
|
514
938
|
}
|
|
515
|
-
const s = c("\x1B[34m"),
|
|
516
|
-
function
|
|
939
|
+
const s = c("\x1B[34m"), _ = c("\x1B[36m");
|
|
940
|
+
function Y() {
|
|
517
941
|
const e = [
|
|
518
|
-
` ${s("_")} ${
|
|
519
|
-
`${s("(_)")} ${
|
|
942
|
+
` ${s("_")} ${_("_")} _ _ _`,
|
|
943
|
+
`${s("(_)")} ${_("(_)")} _ __(_)__| |_____ __| |`,
|
|
520
944
|
` ${s("_")} ${s("_")} | '_ \\ / _| / / -_) _\` |`,
|
|
521
945
|
`${s("(_)")} ${s("(_)")} | .__/_\\__|_\\_\\___\\__,_|`,
|
|
522
946
|
` |_|
|
|
@@ -526,39 +950,39 @@ function I() {
|
|
|
526
950
|
`));
|
|
527
951
|
}
|
|
528
952
|
const l = {
|
|
529
|
-
banner:
|
|
953
|
+
banner: Y,
|
|
530
954
|
debug: p("debug"),
|
|
531
955
|
info: p("info"),
|
|
532
956
|
warn: p("warn"),
|
|
533
957
|
error: p("error"),
|
|
534
|
-
setLevel:
|
|
958
|
+
setLevel: C
|
|
535
959
|
};
|
|
536
|
-
function
|
|
537
|
-
return (t,
|
|
960
|
+
function B(e) {
|
|
961
|
+
return (t, r, n) => {
|
|
538
962
|
if (t.method !== "GET") {
|
|
539
|
-
|
|
963
|
+
n();
|
|
540
964
|
return;
|
|
541
965
|
}
|
|
542
|
-
const
|
|
543
|
-
if (
|
|
544
|
-
|
|
966
|
+
const i = (t.url ?? "").split("?")[0];
|
|
967
|
+
if (i !== "/" && i !== "/index.html") {
|
|
968
|
+
n();
|
|
545
969
|
return;
|
|
546
970
|
}
|
|
547
971
|
const a = e();
|
|
548
|
-
|
|
972
|
+
r.setHeader("Content-Type", "text/html"), r.statusCode = 200, r.end(a);
|
|
549
973
|
};
|
|
550
974
|
}
|
|
551
|
-
function
|
|
975
|
+
function F(e) {
|
|
552
976
|
if (e.length === 0)
|
|
553
977
|
return;
|
|
554
|
-
const t = Math.max(4, ...e.map((a) => a.name.length)),
|
|
978
|
+
const t = Math.max(4, ...e.map((a) => a.name.length)), r = Math.max(3, ...e.map((a) => a.key.length)), n = ` ${"Name".padEnd(t)} ${"Key".padEnd(r)} Status Weight Ver`, o = ` ${"─".repeat(t)} ${"─".repeat(r)} ──────── ────── ───`, i = e.map((a) => {
|
|
555
979
|
const d = a.enabled ? "\x1B[32m enabled\x1B[0m" : "\x1B[2mdisabled\x1B[0m", u = `${a.weight.toString()}%`.padStart(6), f = `v${a.version.toString()}`;
|
|
556
|
-
return ` ${a.name.padEnd(t)} ${a.
|
|
980
|
+
return ` ${a.name.padEnd(t)} ${a.key.padEnd(r)} ${d} ${u} ${f}`;
|
|
557
981
|
});
|
|
558
|
-
console.log(["", " Features:", "",
|
|
982
|
+
console.log(["", " Features:", "", n, o, ...i, ""].join(`
|
|
559
983
|
`));
|
|
560
984
|
}
|
|
561
|
-
function
|
|
985
|
+
function z(e) {
|
|
562
986
|
try {
|
|
563
987
|
const t = new URL(e).hostname;
|
|
564
988
|
return t === "localhost" || t === "127.0.0.1" || t === "::1";
|
|
@@ -566,76 +990,76 @@ function B(e) {
|
|
|
566
990
|
return !1;
|
|
567
991
|
}
|
|
568
992
|
}
|
|
569
|
-
function
|
|
993
|
+
function P(e) {
|
|
570
994
|
return new Promise((t) => {
|
|
571
995
|
setTimeout(t, e);
|
|
572
996
|
});
|
|
573
997
|
}
|
|
574
|
-
async function
|
|
575
|
-
const
|
|
576
|
-
if (
|
|
577
|
-
return
|
|
578
|
-
for (let
|
|
998
|
+
async function N(e, t, r) {
|
|
999
|
+
const n = await g(e, t, { headers: r });
|
|
1000
|
+
if (n || !z(e))
|
|
1001
|
+
return n;
|
|
1002
|
+
for (let o = 1; o <= A; o++) {
|
|
579
1003
|
l.info(
|
|
580
|
-
`local API not ready, retrying in ${(
|
|
581
|
-
), await
|
|
582
|
-
const
|
|
583
|
-
if (
|
|
584
|
-
return
|
|
1004
|
+
`local API not ready, retrying in ${(T / 1e3).toString()}s (${o.toString()}/${A.toString()})`
|
|
1005
|
+
), await P(T);
|
|
1006
|
+
const i = await g(e, t, { headers: r });
|
|
1007
|
+
if (i)
|
|
1008
|
+
return i;
|
|
585
1009
|
}
|
|
586
1010
|
return null;
|
|
587
1011
|
}
|
|
588
|
-
function
|
|
589
|
-
return "0.0.1-dev.
|
|
1012
|
+
function K() {
|
|
1013
|
+
return "0.0.1-dev.1773363643396";
|
|
590
1014
|
}
|
|
591
|
-
const
|
|
592
|
-
function
|
|
593
|
-
const t = e.apiUrl ??
|
|
594
|
-
let
|
|
1015
|
+
const k = "https://api.picked.app", G = "__PICKED_PROJECT_CONFIG__", A = 5, T = 2e3;
|
|
1016
|
+
function q(e) {
|
|
1017
|
+
const t = e.apiUrl ?? k;
|
|
1018
|
+
let r = [];
|
|
595
1019
|
return {
|
|
596
1020
|
name: "picked",
|
|
597
1021
|
config: async () => {
|
|
598
|
-
l.banner(), l.info(`fetching project config for "${e.projectId}"`), t !==
|
|
599
|
-
const
|
|
600
|
-
if (!
|
|
1022
|
+
l.banner(), l.info(`fetching project config for "${e.projectId}"`), t !== k && l.warn(`using custom API URL: ${t}`);
|
|
1023
|
+
const n = R("vite-plugin", K()), o = performance.now(), i = await N(t, e.projectId, n), a = (performance.now() - o).toFixed(0);
|
|
1024
|
+
if (!i) {
|
|
601
1025
|
l.warn(`failed to fetch project config for "${e.projectId}" (${a}ms)`);
|
|
602
1026
|
return;
|
|
603
1027
|
}
|
|
604
|
-
|
|
605
|
-
const d =
|
|
1028
|
+
r = i.features;
|
|
1029
|
+
const d = i.features.length, u = i.features.filter((U) => U.enabled).length, f = JSON.stringify(i).length;
|
|
606
1030
|
return l.info(
|
|
607
1031
|
`fetched ${d.toString()} features (${u.toString()} enabled) for "${e.projectId}" in ${a}ms`
|
|
608
|
-
),
|
|
1032
|
+
), F(i.features), l.debug(`config size: ${f.toString()} bytes`), {
|
|
609
1033
|
define: {
|
|
610
|
-
[
|
|
1034
|
+
[G]: JSON.stringify(i)
|
|
611
1035
|
}
|
|
612
1036
|
};
|
|
613
1037
|
},
|
|
614
|
-
configureServer(
|
|
1038
|
+
configureServer(n) {
|
|
615
1039
|
if (e.disableLauncher) return;
|
|
616
|
-
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
const
|
|
620
|
-
if (
|
|
621
|
-
const a =
|
|
1040
|
+
n.middlewares.use(B(() => b(r)));
|
|
1041
|
+
const o = n.printUrls.bind(n);
|
|
1042
|
+
n.printUrls = () => {
|
|
1043
|
+
const i = n.resolvedUrls?.local[0];
|
|
1044
|
+
if (i) {
|
|
1045
|
+
const a = i.replace(
|
|
622
1046
|
/:(?<port>\d+)\//,
|
|
623
1047
|
(d, u) => `:\x1B[1m${u}\x1B[22m/`
|
|
624
1048
|
);
|
|
625
1049
|
console.log(` \x1B[32m➜\x1B[0m \x1B[1mPicked\x1B[22m: \x1B[36m${a}\x1B[0m`);
|
|
626
1050
|
}
|
|
627
|
-
|
|
1051
|
+
o();
|
|
628
1052
|
};
|
|
629
1053
|
},
|
|
630
1054
|
generateBundle() {
|
|
631
1055
|
e.disableLauncher || this.emitFile({
|
|
632
1056
|
type: "asset",
|
|
633
1057
|
fileName: "index.html",
|
|
634
|
-
source:
|
|
1058
|
+
source: b(r)
|
|
635
1059
|
});
|
|
636
1060
|
}
|
|
637
1061
|
};
|
|
638
1062
|
}
|
|
639
1063
|
export {
|
|
640
|
-
|
|
1064
|
+
q as picked
|
|
641
1065
|
};
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@picked/vite-plugin-picked",
|
|
3
3
|
"description": "Vite plugin for build-time config injection",
|
|
4
|
-
"version": "0.0.1-dev.
|
|
4
|
+
"version": "0.0.1-dev.1773363643396",
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@picked/client": "0.0.1-dev.
|
|
6
|
+
"@picked/client": "0.0.1-dev.1773363643396"
|
|
7
7
|
},
|
|
8
8
|
"devDependencies": {
|
|
9
9
|
"@repo/eslint-config": "workspace:*",
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
"dev": "vite build --watch",
|
|
57
57
|
"jscpd": "jscpd src",
|
|
58
58
|
"knip": "knip",
|
|
59
|
-
"lint": "eslint .",
|
|
59
|
+
"lint": "if [ \"$AGENT\" = \"true\" ]; then echo \"[AGENT HINT] Prefer running lint on specific files from the repo root: node scripts/lint-files.js <files>\"; fi && eslint .",
|
|
60
60
|
"lint-files": "eslint",
|
|
61
61
|
"lint:format": "eslint . --fix",
|
|
62
62
|
"lint:report": "eslint . -o './.reports/eslint.json' -f json || true",
|