@kosmas10/portal 0.0.4 → 0.0.6

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.
@@ -3,105 +3,65 @@
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>Loading...</title>
6
+ <title>AI Chat Extensions Portal</title>
7
7
  </head>
8
8
  <body>
9
+ <div id="root"></div>
9
10
  <script>
10
- /**
11
- * Portal Bootstrap Loader
12
- * Copyright (c) 2025 Nova Science Ventures LLC
13
- * Created by Kosmas Karadimitriou
14
- *
15
- * Licensed under the MIT License
16
- * GitHub: https://github.com/kosmas10/ai-chat-extensions
17
- */
11
+ /**
12
+ * Portal Bootstrap Loader
13
+ * Copyright (c) 2025 Nova Science Ventures LLC
14
+ * Created by Kosmas Karadimitriou
15
+ *
16
+ * Licensed under the MIT License
17
+ * GitHub: https://github.com/kosmas10/ai-chat-extensions
18
+ *
19
+ * Loads app from CDN and injects into current document (preserves Claude's fetch proxy)
20
+ *
21
+ * NOTE: Do NOT use registry.npmjs.org - Claude Artifacts blocks it.
22
+ * Always use cdn.jsdelivr.net for both version lookup and file fetch.
23
+ */
24
+ (async function() {
25
+ var APP = '@kosmas10/portal';
26
+ var FILE = 'dist/portal.html';
18
27
 
19
- // ============================================================================
20
- // STAGE 1 BOOTSTRAP - IMMUTABLE
21
- // ============================================================================
22
- // This file should NEVER be modified after deployment.
23
- // Fetches loader version from package.json to avoid @latest cache issues.
24
- // Only change: the app package name (@kosmas10/portal)
25
- // ============================================================================
26
- (function() {
27
- // Configuration: Only change this for different apps
28
- var APP_PACKAGE = '@kosmas10/portal';
29
- var APP_NAME = 'Portal';
28
+ try {
29
+ // Get latest version from CDN (NOT registry.npmjs.org - blocked in Claude Artifacts)
30
+ var pkg = await fetch('https://cdn.jsdelivr.net/npm/' + APP + '@latest/package.json?t=' + Date.now()).then(r => r.json());
31
+ var html = await fetch('https://cdn.jsdelivr.net/npm/' + APP + '@' + pkg.version + '/' + FILE).then(r => r.text());
30
32
 
31
- // Shared error HTML generator
32
- function createErrorHtml(url) {
33
- return '<!DOCTYPE html>' +
34
- '<html><head><meta charset="UTF-8"><style>' +
35
- 'body{margin:0;padding:40px;font-family:system-ui,sans-serif;line-height:1.6}' +
36
- '.error{max-width:600px;margin:0 auto;padding:30px;background:#fee;border:2px solid #c33;border-radius:8px}' +
37
- 'h1{color:#c33;margin-top:0}' +
38
- 'code{background:#f5f5f5;padding:2px 6px;border-radius:3px;font-size:0.9em}' +
39
- 'ul{margin:15px 0}li{margin:8px 0}' +
40
- '</style></head><body>' +
41
- '<div class="error">' +
42
- '<h1>Failed to Load Application</h1>' +
43
- '<p>The application loader could not be loaded from:</p>' +
44
- '<p><code>' + url + '</code></p>' +
45
- '<p><strong>Possible causes:</strong></p>' +
46
- '<ul>' +
47
- '<li>No internet connection</li>' +
48
- '<li>CDN (cdn.jsdelivr.net) is blocked by firewall or proxy</li>' +
49
- '<li>NPM registry is inaccessible</li>' +
50
- '<li>Corporate network restrictions</li>' +
51
- '<li>Browser extensions blocking the request</li>' +
52
- '</ul>' +
53
- '<p><strong>What to try:</strong></p>' +
54
- '<ul>' +
55
- '<li>Check your internet connection</li>' +
56
- '<li>Try accessing <a href="https://cdn.jsdelivr.net" target="_blank">cdn.jsdelivr.net</a> directly</li>' +
57
- '<li>Disable VPN or proxy temporarily</li>' +
58
- '<li>Check firewall settings</li>' +
59
- '<li>Try a different network</li>' +
60
- '<li>Contact your IT department if on a corporate network</li>' +
61
- '</ul>' +
62
- '</div></body></html>';
33
+ // Inject all styles
34
+ var styles = html.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/gi);
35
+ for (var m of styles) {
36
+ var s = document.createElement('style');
37
+ s.textContent = m[1];
38
+ document.head.appendChild(s);
63
39
  }
64
40
 
65
- // Load script with error handling
66
- function loadScript(url) {
67
- var script = document.createElement('script');
68
- script.src = url + '&_=' + Date.now();
69
- script.onerror = function() {
70
- document.body.innerHTML = createErrorHtml(url);
71
- };
72
- document.head.appendChild(script);
41
+ // Inject all scripts
42
+ var scripts = html.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/gi);
43
+ for (var m of scripts) {
44
+ var s = document.createElement('script');
45
+ s.textContent = m[1];
46
+ document.body.appendChild(s);
73
47
  }
74
-
75
- // Fetch loader version from package.json
76
- async function getLoaderVersion() {
77
- var cacheBuster = Date.now();
78
- var packageJsonUrl = 'https://cdn.jsdelivr.net/npm/@kosmas10/html-app-loader@latest/package.json?t=' + cacheBuster;
79
- var response = await fetch(packageJsonUrl);
80
- if (!response.ok) {
81
- throw new Error('Failed to fetch loader package.json: HTTP ' + response.status);
82
- }
83
- var packageData = await response.json();
84
- if (!packageData.version) {
85
- throw new Error('package.json does not contain version field');
86
- }
87
- return packageData.version;
88
- }
89
-
90
- // Main loader function
91
- async function loadLoader() {
92
- try {
93
- var loaderVersion = await getLoaderVersion();
94
- var loaderUrl = 'https://cdn.jsdelivr.net/npm/@kosmas10/html-app-loader@' + loaderVersion + '/loader.js?app=' + APP_PACKAGE;
95
- loadScript(loaderUrl);
96
- } catch (error) {
97
- console.error(APP_NAME + ' Bootstrap: Error fetching loader version:', error);
98
- var fallbackUrl = 'https://cdn.jsdelivr.net/npm/@kosmas10/html-app-loader@latest/loader.js?app=' + APP_PACKAGE;
99
- loadScript(fallbackUrl);
100
- }
101
- }
102
-
103
- loadLoader();
104
- })();
48
+ } catch (e) {
49
+ document.body.innerHTML = '<div style="max-width:600px;margin:40px auto;padding:30px;font-family:system-ui,sans-serif;background:#fff;border:2px solid #dc3545;border-radius:12px;box-shadow:0 4px 20px rgba(0,0,0,0.1)">' +
50
+ '<h1 style="color:#dc3545;margin:0 0 15px 0;font-size:1.5em">⚠️ Unable to Load Portal</h1>' +
51
+ '<p style="background:#f8f9fa;padding:10px;border-radius:6px;font-family:monospace;font-size:0.9em;color:#666">' + e.message + '</p>' +
52
+ '<h2 style="font-size:1.1em;margin:20px 0 10px 0">What you can try:</h2>' +
53
+ '<ul style="margin:0;padding-left:20px;line-height:1.8">' +
54
+ '<li><strong>Refresh the page</strong> - Sometimes a simple refresh fixes temporary issues</li>' +
55
+ '<li><strong>Check your internet connection</strong> - The app needs to download from the internet</li>' +
56
+ '<li><strong>Wait a moment and try again</strong> - The server might be temporarily busy</li>' +
57
+ '<li><strong>Try a different browser</strong> - Some browser extensions can interfere</li>' +
58
+ '</ul>' +
59
+ '<p style="margin-top:20px;padding-top:15px;border-top:1px solid #eee;color:#666;font-size:0.9em">' +
60
+ 'If the problem persists, please report it at: ' +
61
+ '<a href="https://github.com/kosmas10/ai-chat-extensions/issues" target="_blank" style="color:#0066cc">github.com/kosmas10/ai-chat-extensions</a>' +
62
+ '</p></div>';
63
+ }
64
+ })();
105
65
  </script>
106
66
  </body>
107
67
  </html>
package/portal.html DELETED
@@ -1,460 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>AI Chat Extensions</title>
7
- <link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect x='0' y='0' width='50' height='50' fill='%236ee7b7'/><rect x='50' y='0' width='50' height='50' fill='%23fbbf24'/><rect x='0' y='50' width='50' height='50' fill='%23764ba2'/><rect x='50' y='50' width='50' height='50' fill='%23ffffff'/></svg>">
8
- <style>
9
- * {
10
- margin: 0;
11
- padding: 0;
12
- box-sizing: border-box;
13
- }
14
-
15
- body {
16
- font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
17
- background: linear-gradient(135deg, #d4c4a8 0%, #c4b5a0 100%);
18
- min-height: 100vh;
19
- display: flex;
20
- align-items: flex-start;
21
- justify-content: center;
22
- padding: 60px 20px 20px 20px;
23
- overflow-x: hidden;
24
- }
25
-
26
- .container {
27
- background: rgba(255, 255, 255, 0.95);
28
- backdrop-filter: blur(10px);
29
- border-radius: 20px;
30
- padding: 40px 70px 70px 70px;
31
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
32
- max-width: 871px;
33
- width: 100%;
34
- text-align: center;
35
- box-sizing: border-box;
36
- }
37
-
38
- .version {
39
- position: absolute;
40
- top: 5px;
41
- right: 10px;
42
- font-size: 0.7rem;
43
- opacity: 0.5;
44
- color: #6b7280;
45
- font-family: Arial, Helvetica, sans-serif;
46
- z-index: 1000;
47
- }
48
-
49
- .header {
50
- margin-bottom: 40px;
51
- }
52
-
53
- .header h1 {
54
- color: #333;
55
- font-size: 2.5rem;
56
- margin-bottom: 10px;
57
- font-family: ui-serif, Georgia, Cambria, "Times New Roman", Times, serif;
58
- background: linear-gradient(135deg, #000000, #333333);
59
- -webkit-background-clip: text;
60
- -webkit-text-fill-color: transparent;
61
- background-clip: text;
62
- }
63
-
64
- .header p {
65
- color: #666;
66
- font-size: 1.1rem;
67
- line-height: 1.6;
68
- }
69
-
70
- .apps-grid {
71
- display: grid;
72
- grid-template-columns: repeat(auto-fit, minmax(305px, 1fr));
73
- gap: 30px;
74
- margin-top: 40px;
75
- width: 100%;
76
- }
77
-
78
- .app-card {
79
- background: white;
80
- border-radius: 15px;
81
- padding: 30px;
82
- box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
83
- transition: all 0.3s ease;
84
- border: 2px solid transparent;
85
- position: relative;
86
- overflow: hidden;
87
- box-sizing: border-box;
88
- width: 100%;
89
- }
90
-
91
- .app-card::before {
92
- content: '';
93
- position: absolute;
94
- top: 0;
95
- left: 0;
96
- right: 0;
97
- height: 4px;
98
- background: linear-gradient(135deg, #667eea, #764ba2);
99
- }
100
-
101
- /* Chat & Verify Card - Green Theme */
102
- .chat-verify-card::before {
103
- background: linear-gradient(135deg, #a7f3d0, #6ee7b7);
104
- }
105
-
106
- .chat-verify-card:hover {
107
- border-color: #a7f3d0;
108
- }
109
-
110
- .chat-verify-button {
111
- background: linear-gradient(135deg, #a7f3d0, #6ee7b7);
112
- color: #1f2937;
113
- }
114
-
115
- .chat-verify-button:hover {
116
- transform: translateY(-2px);
117
- box-shadow: 0 10px 20px rgba(167, 243, 208, 0.3);
118
- }
119
-
120
- /* Folder Analyzer Card - Yellow Theme */
121
- .folder-analyzer-card::before {
122
- background: linear-gradient(135deg, #fde68a, #fbbf24);
123
- }
124
-
125
- .folder-analyzer-card:hover {
126
- border-color: #fde68a;
127
- }
128
-
129
- .folder-analyzer-button {
130
- background: linear-gradient(135deg, #fde68a, #fbbf24);
131
- color: #1f2937;
132
- }
133
-
134
- .folder-analyzer-button:hover {
135
- transform: translateY(-2px);
136
- box-shadow: 0 10px 20px rgba(253, 230, 138, 0.3);
137
- }
138
-
139
- .app-card:hover {
140
- transform: translateY(-5px);
141
- box-shadow: 0 20px 40px rgba(0, 0, 0, 0.15);
142
- }
143
-
144
- /* Chat & Verify hover effects */
145
- .chat-verify-card:hover {
146
- border-color: #d1d5db;
147
- box-shadow: 0 20px 40px rgba(209, 213, 219, 0.2);
148
- }
149
-
150
- /* Folder Analyzer hover effects */
151
- .folder-analyzer-card:hover {
152
- border-color: #d1d5db;
153
- box-shadow: 0 20px 40px rgba(209, 213, 219, 0.2);
154
- }
155
-
156
- .app-icon {
157
- width: 60px;
158
- height: 60px;
159
- margin: 0 auto 20px;
160
- background: linear-gradient(135deg, #667eea, #764ba2);
161
- border-radius: 50%;
162
- display: flex;
163
- align-items: center;
164
- justify-content: center;
165
- font-size: 24px;
166
- color: white;
167
- }
168
-
169
- /* Chat & Verify Icon - Green Theme */
170
- .chat-verify-card .app-icon {
171
- background: linear-gradient(135deg, #a7f3d0, #6ee7b7);
172
- color: #1f2937;
173
- position: relative;
174
- }
175
-
176
- /* Custom thick checkmark for Chat & Verify */
177
- .chat-verify-card .app-icon::before {
178
- content: '';
179
- position: absolute;
180
- width: 8px;
181
- height: 16px;
182
- border: solid #1f2937;
183
- border-width: 0 4px 4px 0;
184
- transform: rotate(45deg);
185
- margin-top: -2px;
186
- }
187
-
188
- /* Folder Analyzer Icon - Yellow Theme */
189
- .folder-analyzer-card .app-icon {
190
- background: linear-gradient(135deg, #fde68a, #fbbf24);
191
- color: #1f2937;
192
- }
193
-
194
- .app-title {
195
- font-size: 1.5rem;
196
- color: #333;
197
- margin-bottom: 15px;
198
- font-weight: 600;
199
- }
200
-
201
- .app-description {
202
- color: #666;
203
- line-height: 1.6;
204
- margin-bottom: 25px;
205
- font-size: 0.95rem;
206
- }
207
-
208
- .app-features {
209
- list-style: none;
210
- margin-bottom: 25px;
211
- text-align: left;
212
- }
213
-
214
- .app-features li {
215
- color: #555;
216
- margin-bottom: 8px;
217
- padding-left: 20px;
218
- position: relative;
219
- font-size: 0.9rem;
220
- }
221
-
222
- .app-features li::before {
223
- content: '✓';
224
- position: absolute;
225
- left: 0;
226
- color: #667eea;
227
- font-weight: bold;
228
- }
229
-
230
- .app-button {
231
- background: linear-gradient(135deg, #667eea, #764ba2);
232
- color: white;
233
- border: none;
234
- padding: 12px 30px;
235
- border-radius: 25px;
236
- font-size: 1rem;
237
- font-weight: 600;
238
- cursor: pointer;
239
- transition: all 0.3s ease;
240
- text-decoration: none;
241
- display: inline-block;
242
- width: 100%;
243
- }
244
-
245
- .app-button:hover {
246
- transform: translateY(-2px);
247
- box-shadow: 0 10px 20px rgba(102, 126, 234, 0.3);
248
- }
249
-
250
- /* Themed button styles */
251
- .chat-verify-button {
252
- background: linear-gradient(135deg, #a7f3d0, #6ee7b7);
253
- color: #1f2937;
254
- }
255
-
256
- .chat-verify-button:hover {
257
- transform: translateY(-2px);
258
- box-shadow: 0 10px 20px rgba(167, 243, 208, 0.3);
259
- }
260
-
261
- .folder-analyzer-button {
262
- background: linear-gradient(135deg, #fde68a, #fbbf24);
263
- color: #1f2937;
264
- }
265
-
266
- .folder-analyzer-button:hover {
267
- transform: translateY(-2px);
268
- box-shadow: 0 10px 20px rgba(253, 230, 138, 0.3);
269
- }
270
-
271
- .footer {
272
- margin-top: 40px;
273
- padding-top: 20px;
274
- border-top: 1px solid #eee;
275
- color: #666;
276
- font-size: 0.9rem;
277
- font-family: Arial, Helvetica, sans-serif;
278
- }
279
-
280
- @media (max-width: 768px) {
281
- body {
282
- padding: 40px 10px 10px 10px;
283
- }
284
-
285
- .container {
286
- padding: 20px;
287
- margin: 0;
288
- }
289
-
290
- .header h1 {
291
- font-size: 2rem;
292
- }
293
-
294
- .apps-grid {
295
- grid-template-columns: 1fr;
296
- gap: 20px;
297
- }
298
-
299
- .app-card {
300
- padding: 20px;
301
- }
302
- }
303
-
304
- @media (max-width: 480px) {
305
- body {
306
- padding: 20px 5px 5px 5px;
307
- }
308
-
309
- .container {
310
- padding: 15px;
311
- }
312
-
313
- .header h1 {
314
- font-size: 1.8rem;
315
- }
316
-
317
- .app-card {
318
- padding: 15px;
319
- }
320
- }
321
- </style>
322
- </head>
323
- <body>
324
- <div class="version">v<span id="app-version"></span></div>
325
-
326
- <div class="container">
327
- <div class="header">
328
- <h1>AI Chat Extensions</h1>
329
- <p>Tools and extensions to enhance AI chat productivity.</p>
330
- </div>
331
-
332
- <div class="apps-grid">
333
- <div class="app-card chat-verify-card">
334
- <div class="app-icon"></div>
335
- <h2 class="app-title">Chat & Verify</h2>
336
- <p class="app-description">
337
- Chat with citations and highlights in the source document for easy verifications.
338
- </p>
339
- <button class="app-button chat-verify-button" onclick="openApp('chat-and-verify')">
340
- Launch Chat & Verify
341
- </button>
342
- </div>
343
-
344
- <div class="app-card folder-analyzer-card">
345
- <div class="app-icon">📁</div>
346
- <h2 class="app-title">Folder LLM Analyzer</h2>
347
- <p class="app-description">
348
- Runs the same LLM query on each file in a folder and displays results in a grid.
349
- </p>
350
- <button class="app-button folder-analyzer-button" onclick="openApp('folder-llm-analyzer')">
351
- Launch Folder Analyzer
352
- </button>
353
- </div>
354
- </div>
355
-
356
- </div>
357
-
358
- <script>
359
- // App version - keep in sync with package.json
360
- const APP_VERSION = '0.0.4';
361
-
362
- // CDN base URL for loading apps
363
- const CDN_BASE = 'https://cdn.jsdelivr.net/npm/@kosmas10/';
364
-
365
- // Cache for resolved versions to avoid multiple fetches
366
- const versionCache = {};
367
-
368
- /**
369
- * Fetch the latest version from package.json
370
- * This avoids @latest cache issues by fetching package.json (which updates faster)
371
- * and then using the specific version number
372
- */
373
- async function getLatestVersion(packageName) {
374
- // Check cache first
375
- if (versionCache[packageName]) {
376
- return versionCache[packageName];
377
- }
378
-
379
- try {
380
- const cacheBuster = Date.now();
381
- const packageJsonUrl = CDN_BASE + packageName + '@latest/package.json?t=' + cacheBuster;
382
-
383
- const response = await fetch(packageJsonUrl);
384
- if (!response.ok) {
385
- throw new Error('Failed to fetch package.json: HTTP ' + response.status);
386
- }
387
-
388
- const packageData = await response.json();
389
- if (!packageData.version) {
390
- throw new Error('package.json does not contain version field');
391
- }
392
-
393
- // Cache the version
394
- versionCache[packageName] = packageData.version;
395
- return packageData.version;
396
- } catch (error) {
397
- console.error('Portal: Error fetching latest version for', packageName, ':', error);
398
- // Fallback to 'latest' if we can't fetch the version
399
- return 'latest';
400
- }
401
- }
402
-
403
- async function openApp(packageName) {
404
- try {
405
- // Resolve 'latest' to actual version number
406
- const resolvedVersion = await getLatestVersion(packageName);
407
-
408
- // Build URL with specific version (not @latest)
409
- const url = CDN_BASE + packageName + '@' + resolvedVersion + '/' + packageName + '-bootstrap.html';
410
-
411
- // Open the application bootstrap from CDN in a new tab/window
412
- window.open(url, '_blank');
413
- } catch (error) {
414
- console.error('Portal: Error opening app', packageName, ':', error);
415
- // Fallback: try with @latest if version resolution fails
416
- const fallbackUrl = CDN_BASE + packageName + '@latest/' + packageName + '-bootstrap.html';
417
- window.open(fallbackUrl, '_blank');
418
- }
419
- }
420
-
421
- // Add some interactive effects
422
- document.addEventListener('DOMContentLoaded', function() {
423
- // Set the version display from the constant
424
- const versionElement = document.getElementById('app-version');
425
- if (versionElement) {
426
- versionElement.textContent = APP_VERSION;
427
- }
428
-
429
- const cards = document.querySelectorAll('.app-card');
430
-
431
- cards.forEach(card => {
432
- card.addEventListener('mouseenter', function() {
433
- this.style.transform = 'translateY(-5px) scale(1.02)';
434
- });
435
-
436
- card.addEventListener('mouseleave', function() {
437
- this.style.transform = 'translateY(0) scale(1)';
438
- });
439
-
440
- // Make entire card clickable
441
- card.addEventListener('click', function(e) {
442
- // Don't trigger if clicking on the button (to avoid double-triggering)
443
- if (e.target.classList.contains('app-button')) {
444
- return;
445
- }
446
-
447
- // Find the button in this card and trigger its click
448
- const button = this.querySelector('.app-button');
449
- if (button) {
450
- button.click();
451
- }
452
- });
453
-
454
- // Add cursor pointer to indicate clickability
455
- card.style.cursor = 'pointer';
456
- });
457
- });
458
- </script>
459
- </body>
460
- </html>