funuicss 3.8.7 → 3.8.8

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/ui/theme/theme.js CHANGED
@@ -70,7 +70,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
70
70
  }
71
71
  };
72
72
  Object.defineProperty(exports, "__esModule", { value: true });
73
- exports.getPaginatedRecords = exports.useBucketCache = exports.useAllJsonRecords = exports.usePaginatedRecords = exports.useBucketJsonFiles = exports.useBucketsByCategory = exports.useBucket = exports.useBuckets = exports.useDocumentAssets = exports.useAudioAssets = exports.useVideoAssets = exports.useImageAssets = exports.useAssetsByType = exports.useAssetInfo = exports.useAssetType = exports.useAssetValue = exports.useAsset = exports.useAssets = exports.getAssetInfo = exports.getAssetType = exports.getAssetValue = exports.getAllAssets = exports.getAsset = exports.useVariable = exports.useVariables = exports.useComponentVariant = exports.useTypographyValue = exports.useColor = exports.useProjectData = exports.useThemeConfig = exports.useTypography = exports.useColors = exports.useComponentConfig = exports.useThemeValue = exports.getAllVariables = exports.getVariable = exports.useVariant = exports.useTheme = void 0;
73
+ exports.getPaginatedRecords = exports.useBucketCache = exports.useAllJsonRecords = exports.usePaginatedRecords = exports.useBucketJsonFiles = exports.useBucketsByCategory = exports.useBucket = exports.useBuckets = exports.useDocumentAssets = exports.useAudioAssets = exports.useVideoAssets = exports.useImageAssets = exports.useAssetsByType = exports.useAssetInfo = exports.useAssetType = exports.useAssetValue = exports.useAsset = exports.useAssets = exports.getAssetInfo = exports.getAssetType = exports.getAssetValue = exports.getAllAssets = exports.getAsset = exports.useVariable = exports.useVariables = exports.useComponentVariant = exports.useTypographyValue = exports.useColor = exports.useProjectData = exports.useThemeConfig = exports.useTypography = exports.useColors = exports.useComponentConfig = exports.useThemeValue = exports.getAllVariables = exports.getVariable = exports.clearGlobalProjectId = exports.getGlobalProjectId = exports.setGlobalProjectId = exports.useVariant = exports.useTheme = void 0;
74
74
  var react_1 = __importStar(require("react"));
75
75
  var themes_1 = require("./themes");
76
76
  var darkenUtils_1 = require("./darkenUtils");
@@ -98,6 +98,57 @@ var useVariant = function () {
98
98
  };
99
99
  exports.useVariant = useVariant;
100
100
  /* -------------------------------------------------------------------------- */
101
+ /* GLOBAL PROJECT ID */
102
+ /* -------------------------------------------------------------------------- */
103
+ // Global variable to store the project ID
104
+ var globalProjectId = null;
105
+ // Function to set the global project ID
106
+ var setGlobalProjectId = function (id) {
107
+ globalProjectId = id;
108
+ console.log("\uD83C\uDF0D Global project ID set to: ".concat(id));
109
+ };
110
+ exports.setGlobalProjectId = setGlobalProjectId;
111
+ // Function to get the global project ID
112
+ var getGlobalProjectId = function () {
113
+ return globalProjectId;
114
+ };
115
+ exports.getGlobalProjectId = getGlobalProjectId;
116
+ // Function to clear the global project ID
117
+ var clearGlobalProjectId = function () {
118
+ globalProjectId = null;
119
+ console.log('🌍 Global project ID cleared');
120
+ };
121
+ exports.clearGlobalProjectId = clearGlobalProjectId;
122
+ // Function to read project ID from a file
123
+ var readProjectIdFromFile = function (file) { return __awaiter(void 0, void 0, void 0, function () {
124
+ var text, data, error_1;
125
+ return __generator(this, function (_a) {
126
+ switch (_a.label) {
127
+ case 0:
128
+ _a.trys.push([0, 2, , 3]);
129
+ return [4 /*yield*/, file.text()];
130
+ case 1:
131
+ text = _a.sent();
132
+ data = JSON.parse(text);
133
+ // Check for project_id field
134
+ if (data.project_id) {
135
+ return [2 /*return*/, data.project_id];
136
+ }
137
+ // Also check for projectId (camelCase)
138
+ if (data.projectId) {
139
+ return [2 /*return*/, data.projectId];
140
+ }
141
+ console.warn('âš ī¸ Project file does not contain a project_id field');
142
+ return [2 /*return*/, null];
143
+ case 2:
144
+ error_1 = _a.sent();
145
+ console.error('❌ Error reading project file:', error_1);
146
+ return [2 /*return*/, null];
147
+ case 3: return [2 /*return*/];
148
+ }
149
+ });
150
+ }); };
151
+ /* -------------------------------------------------------------------------- */
101
152
  /* ORIGIN VALIDATION */
102
153
  /* -------------------------------------------------------------------------- */
103
154
  var getCurrentOrigin = function () {
@@ -113,7 +164,7 @@ var getCurrentOrigin = function () {
113
164
  return domain;
114
165
  };
115
166
  var validateOriginAccess = function (projectId) { return __awaiter(void 0, void 0, void 0, function () {
116
- var currentOrigin, projectData, trustedDomains, hasAccess, error_1;
167
+ var currentOrigin, projectData, trustedDomains, hasAccess, error_2;
117
168
  return __generator(this, function (_a) {
118
169
  switch (_a.label) {
119
170
  case 0:
@@ -149,8 +200,8 @@ var validateOriginAccess = function (projectId) { return __awaiter(void 0, void
149
200
  }
150
201
  return [2 /*return*/, true];
151
202
  case 3:
152
- error_1 = _a.sent();
153
- console.error('❌ Error during origin validation:', error_1);
203
+ error_2 = _a.sent();
204
+ console.error('❌ Error during origin validation:', error_2);
154
205
  return [2 /*return*/, false];
155
206
  case 4: return [2 /*return*/];
156
207
  }
@@ -160,7 +211,7 @@ var validateOriginAccess = function (projectId) { return __awaiter(void 0, void
160
211
  /* LOCAL FILE MANAGEMENT */
161
212
  /* -------------------------------------------------------------------------- */
162
213
  var loadLocalTheme = function () { return __awaiter(void 0, void 0, void 0, function () {
163
- var response, data, error_2;
214
+ var response, data, error_3;
164
215
  return __generator(this, function (_a) {
165
216
  switch (_a.label) {
166
217
  case 0:
@@ -177,7 +228,7 @@ var loadLocalTheme = function () { return __awaiter(void 0, void 0, void 0, func
177
228
  return [2 /*return*/, data];
178
229
  case 3: return [3 /*break*/, 5];
179
230
  case 4:
180
- error_2 = _a.sent();
231
+ error_3 = _a.sent();
181
232
  console.log('â„šī¸ No local theme file found');
182
233
  return [3 /*break*/, 5];
183
234
  case 5: return [2 /*return*/, null];
@@ -188,7 +239,7 @@ var loadLocalTheme = function () { return __awaiter(void 0, void 0, void 0, func
188
239
  /* CDN THEME LOADER */
189
240
  /* -------------------------------------------------------------------------- */
190
241
  var loadThemeFromCDN = function (projectId) { return __awaiter(void 0, void 0, void 0, function () {
191
- var publicUrl, response, data, error_3;
242
+ var publicUrl, response, data, error_4;
192
243
  return __generator(this, function (_a) {
193
244
  switch (_a.label) {
194
245
  case 0:
@@ -215,8 +266,8 @@ var loadThemeFromCDN = function (projectId) { return __awaiter(void 0, void 0, v
215
266
  _a.label = 5;
216
267
  case 5: return [3 /*break*/, 7];
217
268
  case 6:
218
- error_3 = _a.sent();
219
- console.error('❌ Error loading from Firebase Storage:', error_3);
269
+ error_4 = _a.sent();
270
+ console.error('❌ Error loading from Firebase Storage:', error_4);
220
271
  return [3 /*break*/, 7];
221
272
  case 7: return [2 /*return*/, null];
222
273
  }
@@ -245,7 +296,7 @@ var cleanExpiredCache = function () {
245
296
  };
246
297
  // Load JSON file with caching and performance optimizations
247
298
  var loadBucketJsonFromCDN = function (bucketSanitizedName, projectId, page) { return __awaiter(void 0, void 0, void 0, function () {
248
- var cacheKey, cached, pageNumber, publicUrl, controller_1, timeoutId, response, data, error_4;
299
+ var cacheKey, cached, pageNumber, publicUrl, controller_1, timeoutId, response, data, error_5;
249
300
  return __generator(this, function (_a) {
250
301
  switch (_a.label) {
251
302
  case 0:
@@ -295,12 +346,12 @@ var loadBucketJsonFromCDN = function (bucketSanitizedName, projectId, page) { re
295
346
  return [2 /*return*/, null];
296
347
  case 5: return [3 /*break*/, 7];
297
348
  case 6:
298
- error_4 = _a.sent();
299
- if (error_4 instanceof DOMException && error_4.name === 'AbortError') {
349
+ error_5 = _a.sent();
350
+ if (error_5 instanceof DOMException && error_5.name === 'AbortError') {
300
351
  console.error("\u23F0 Timeout loading JSON file for page ".concat(page));
301
352
  }
302
353
  else {
303
- console.error("\u274C Error loading JSON file for page ".concat(page, ":"), error_4);
354
+ console.error("\u274C Error loading JSON file for page ".concat(page, ":"), error_5);
304
355
  }
305
356
  return [2 /*return*/, null];
306
357
  case 7: return [2 /*return*/];
@@ -309,7 +360,7 @@ var loadBucketJsonFromCDN = function (bucketSanitizedName, projectId, page) { re
309
360
  }); };
310
361
  // Parallel loading for multiple pages
311
362
  var loadMultipleJsonPages = function (bucketSanitizedName, projectId, pages) { return __awaiter(void 0, void 0, void 0, function () {
312
- var promises, results, error_5;
363
+ var promises, results, error_6;
313
364
  return __generator(this, function (_a) {
314
365
  switch (_a.label) {
315
366
  case 0:
@@ -322,15 +373,15 @@ var loadMultipleJsonPages = function (bucketSanitizedName, projectId, pages) { r
322
373
  results = _a.sent();
323
374
  return [2 /*return*/, results.filter(Boolean)];
324
375
  case 2:
325
- error_5 = _a.sent();
326
- console.error('❌ Error loading multiple JSON pages:', error_5);
376
+ error_6 = _a.sent();
377
+ console.error('❌ Error loading multiple JSON pages:', error_6);
327
378
  return [2 /*return*/, []];
328
379
  case 3: return [2 /*return*/];
329
380
  }
330
381
  });
331
382
  }); };
332
383
  var listBucketJsonFiles = function (bucketSanitizedName, projectId) { return __awaiter(void 0, void 0, void 0, function () {
333
- var files, page, hasMoreFiles, batchSize, pageChecks, batchPromises, i, paddedPage, publicUrl, responses, i, currentPage, paddedPage, publicUrl, error_6;
384
+ var files, page, hasMoreFiles, batchSize, pageChecks, batchPromises, i, paddedPage, publicUrl, responses, i, currentPage, paddedPage, publicUrl, error_7;
334
385
  return __generator(this, function (_a) {
335
386
  switch (_a.label) {
336
387
  case 0:
@@ -383,8 +434,8 @@ var listBucketJsonFiles = function (bucketSanitizedName, projectId) { return __a
383
434
  return [3 /*break*/, 2];
384
435
  case 4: return [2 /*return*/, files];
385
436
  case 5:
386
- error_6 = _a.sent();
387
- console.error('❌ Error listing JSON files:', error_6);
437
+ error_7 = _a.sent();
438
+ console.error('❌ Error listing JSON files:', error_7);
388
439
  return [2 /*return*/, []];
389
440
  case 6: return [2 /*return*/];
390
441
  }
@@ -483,7 +534,7 @@ var transformProjectBucket = function (bucket, projectId) {
483
534
  /* COMPONENT */
484
535
  /* -------------------------------------------------------------------------- */
485
536
  var ThemeProvider = function (_a) {
486
- var theme = _a.theme, children = _a.children, _b = _a.funcss, funcss = _b === void 0 ? '' : _b, _c = _a.minHeight, minHeight = _c === void 0 ? '100vh' : _c, projectId = _a.projectId, providedProject = _a.project;
537
+ var theme = _a.theme, children = _a.children, _b = _a.funcss, funcss = _b === void 0 ? '' : _b, _c = _a.minHeight, minHeight = _c === void 0 ? '100vh' : _c, propProjectId = _a.projectId, providedProject = _a.project, projectFile = _a.projectFile;
487
538
  var _d = (0, react_1.useState)('standard'), variant = _d[0], setVariant = _d[1];
488
539
  var _e = (0, react_1.useState)({}), themeConfig = _e[0], setThemeConfig = _e[1];
489
540
  var _f = (0, react_1.useState)(null), projectData = _f[0], setProjectData = _f[1];
@@ -491,6 +542,8 @@ var ThemeProvider = function (_a) {
491
542
  var _h = (0, react_1.useState)(true), isInitialLoad = _h[0], setIsInitialLoad = _h[1];
492
543
  var _j = (0, react_1.useState)(null), error = _j[0], setError = _j[1];
493
544
  var _k = (0, react_1.useState)(null), currentVersion = _k[0], setCurrentVersion = _k[1];
545
+ // Determine the actual project ID to use
546
+ var _l = (0, react_1.useState)(propProjectId), actualProjectId = _l[0], setActualProjectId = _l[1];
494
547
  /* -------------------------- Apply base theme --------------------------- */
495
548
  (0, react_1.useEffect)(function () {
496
549
  var root = document.documentElement;
@@ -522,20 +575,56 @@ var ThemeProvider = function (_a) {
522
575
  var root = document.documentElement;
523
576
  var pollTimer;
524
577
  var loadTheme = function () { return __awaiter(void 0, void 0, void 0, function () {
525
- var finalTheme, finalVersion, localTheme, localVersion, hasAccess, cdnTheme, cdnVersion, err_1;
578
+ var finalTheme, finalVersion, finalProjectId, fileProjectId, text, fileData, localTheme, localVersion, projectIdToUse, hasAccess, cdnTheme, cdnVersion, err_1;
526
579
  return __generator(this, function (_a) {
527
580
  switch (_a.label) {
528
581
  case 0:
529
- _a.trys.push([0, 8, 9, 10]);
582
+ _a.trys.push([0, 12, 13, 14]);
530
583
  finalTheme = null;
531
584
  finalVersion = null;
532
- // If project data is provided directly, use it and skip all loading
585
+ finalProjectId = actualProjectId;
586
+ if (!projectFile) return [3 /*break*/, 4];
587
+ console.log('📁 Processing project file...');
588
+ return [4 /*yield*/, readProjectIdFromFile(projectFile)];
589
+ case 1:
590
+ fileProjectId = _a.sent();
591
+ if (!fileProjectId) return [3 /*break*/, 3];
592
+ // Set global project ID
593
+ (0, exports.setGlobalProjectId)(fileProjectId);
594
+ setActualProjectId(fileProjectId);
595
+ finalProjectId = fileProjectId;
596
+ console.log("\u2705 Project ID from file: ".concat(fileProjectId));
597
+ return [4 /*yield*/, projectFile.text()];
598
+ case 2:
599
+ text = _a.sent();
600
+ fileData = JSON.parse(text);
601
+ // Use the file data as the project data
602
+ finalTheme = fileData;
603
+ finalVersion = fileData.version || 0;
604
+ // Apply theme immediately - fileData is guaranteed to be ProjectData here
605
+ applyThemeData(fileData, root);
606
+ setCurrentVersion(finalVersion);
607
+ setError(null);
608
+ setIsLoading(false);
609
+ setIsInitialLoad(false);
610
+ return [2 /*return*/]; // Skip all other loading logic
611
+ case 3:
612
+ console.warn('âš ī¸ Project file does not contain a project_id');
613
+ _a.label = 4;
614
+ case 4:
615
+ // If project data is provided directly, use it
533
616
  if (providedProject) {
534
617
  console.log('✅ Using provided project data directly');
535
618
  finalTheme = providedProject;
536
619
  finalVersion = providedProject.version || 0;
537
- // Apply theme immediately
538
- applyThemeData(finalTheme, root);
620
+ finalProjectId = providedProject.project_id || propProjectId;
621
+ // Set global project ID if available
622
+ if (finalProjectId) {
623
+ (0, exports.setGlobalProjectId)(finalProjectId);
624
+ setActualProjectId(finalProjectId);
625
+ }
626
+ // Apply theme immediately - providedProject is guaranteed to be ProjectData here
627
+ applyThemeData(providedProject, root);
539
628
  setCurrentVersion(finalVersion);
540
629
  setError(null);
541
630
  setIsLoading(false);
@@ -543,16 +632,17 @@ var ThemeProvider = function (_a) {
543
632
  return [2 /*return*/]; // Skip all other loading logic
544
633
  }
545
634
  return [4 /*yield*/, loadLocalTheme()];
546
- case 1:
635
+ case 5:
547
636
  localTheme = _a.sent();
548
637
  localVersion = (localTheme === null || localTheme === void 0 ? void 0 : localTheme.version) || 0;
549
- if (!projectId) return [3 /*break*/, 6];
550
- return [4 /*yield*/, validateOriginAccess(projectId)];
551
- case 2:
638
+ projectIdToUse = finalProjectId || (0, exports.getGlobalProjectId)() || propProjectId;
639
+ if (!projectIdToUse) return [3 /*break*/, 10];
640
+ return [4 /*yield*/, validateOriginAccess(projectIdToUse)];
641
+ case 6:
552
642
  hasAccess = _a.sent();
553
- if (!hasAccess) return [3 /*break*/, 4];
554
- return [4 /*yield*/, loadThemeFromCDN(projectId)];
555
- case 3:
643
+ if (!hasAccess) return [3 /*break*/, 8];
644
+ return [4 /*yield*/, loadThemeFromCDN(projectIdToUse)];
645
+ case 7:
556
646
  cdnTheme = _a.sent();
557
647
  cdnVersion = (cdnTheme === null || cdnTheme === void 0 ? void 0 : cdnTheme.version) || 0;
558
648
  if (cdnTheme) {
@@ -575,8 +665,8 @@ var ThemeProvider = function (_a) {
575
665
  console.warn('âš ī¸ No theme found (CDN unavailable and no local theme)');
576
666
  setError('Theme not found');
577
667
  }
578
- return [3 /*break*/, 5];
579
- case 4:
668
+ return [3 /*break*/, 9];
669
+ case 8:
580
670
  // Origin validation failed
581
671
  if (localTheme) {
582
672
  console.log('âš ī¸ Origin validation failed, using local theme');
@@ -587,9 +677,9 @@ var ThemeProvider = function (_a) {
587
677
  console.error('❌ Origin validation failed and no local theme available');
588
678
  setError('Access denied and no local theme available');
589
679
  }
590
- _a.label = 5;
591
- case 5: return [3 /*break*/, 7];
592
- case 6:
680
+ _a.label = 9;
681
+ case 9: return [3 /*break*/, 11];
682
+ case 10:
593
683
  // No project ID provided - only use local theme
594
684
  console.log('â„šī¸ No project ID provided, using local theme only');
595
685
  if (localTheme) {
@@ -601,10 +691,12 @@ var ThemeProvider = function (_a) {
601
691
  console.log('â„šī¸ No local theme file found - using base theme only');
602
692
  // No error here - it's valid to use only base theme
603
693
  }
604
- _a.label = 7;
605
- case 7:
694
+ _a.label = 11;
695
+ case 11:
606
696
  // Apply the theme if we have one
697
+ // Check if finalTheme is not null before calling applyThemeData
607
698
  if (finalTheme && (!currentVersion || finalVersion !== currentVersion)) {
699
+ // finalTheme is guaranteed to be ProjectData here because we checked it's not null
608
700
  applyThemeData(finalTheme, root);
609
701
  setCurrentVersion(finalVersion);
610
702
  setError(null);
@@ -612,26 +704,26 @@ var ThemeProvider = function (_a) {
612
704
  else if (finalTheme) {
613
705
  console.log('✓ Theme up to date');
614
706
  }
615
- return [3 /*break*/, 10];
616
- case 8:
707
+ return [3 /*break*/, 14];
708
+ case 12:
617
709
  err_1 = _a.sent();
618
710
  console.error('❌ Error loading theme:', err_1);
619
711
  setError('Failed to load theme');
620
- return [3 /*break*/, 10];
621
- case 9:
712
+ return [3 /*break*/, 14];
713
+ case 13:
622
714
  setIsLoading(false);
623
715
  setIsInitialLoad(false);
624
716
  return [7 /*endfinally*/];
625
- case 10: return [2 /*return*/];
717
+ case 14: return [2 /*return*/];
626
718
  }
627
719
  });
628
720
  }); };
629
721
  // Only load theme if no project is provided
630
- if (!providedProject) {
722
+ if (!providedProject && !projectFile) {
631
723
  // Initial load
632
724
  loadTheme();
633
725
  // Only poll for updates if we have a project ID
634
- if (projectId) {
726
+ if (actualProjectId) {
635
727
  pollTimer = setInterval(function () {
636
728
  loadTheme();
637
729
  }, 5 * 60 * 1000);
@@ -643,18 +735,21 @@ var ThemeProvider = function (_a) {
643
735
  };
644
736
  }
645
737
  else {
646
- // If project is provided, skip loading and set state directly
647
- console.log('✅ Using provided project data, skipping theme loading');
648
- applyThemeData(providedProject, document.documentElement);
649
- setCurrentVersion(providedProject.version || 0);
738
+ // If project or file is provided, skip loading and set state directly
739
+ console.log('✅ Using provided project data/file, skipping theme loading');
740
+ if (providedProject) {
741
+ applyThemeData(providedProject, document.documentElement);
742
+ setCurrentVersion(providedProject.version || 0);
743
+ }
650
744
  setIsLoading(false);
651
745
  setIsInitialLoad(false);
652
746
  }
653
- }, [projectId, currentVersion, theme, providedProject]); // Added providedProject to dependencies
747
+ }, [propProjectId, actualProjectId, currentVersion, theme, providedProject, projectFile]);
654
748
  var applyThemeData = function (data, root) {
655
749
  var _a;
656
750
  var themeConfig = (_a = data.theme_config) !== null && _a !== void 0 ? _a : {};
657
751
  var newVariant = data.default_variation || 'standard';
752
+ var projectId = data.project_id || actualProjectId;
658
753
  setVariant(newVariant);
659
754
  setThemeConfig(themeConfig);
660
755
  setProjectData(data);
@@ -665,10 +760,15 @@ var ThemeProvider = function (_a) {
665
760
  // Cache for bucket access
666
761
  var projectBuckets = data.buckets || [];
667
762
  cachedBuckets = projectBuckets.map(function (bucket) {
668
- return transformProjectBucket(bucket, data.project_id || '');
763
+ return transformProjectBucket(bucket, projectId || '');
669
764
  });
670
765
  // Apply all theme config to CSS variables
671
766
  applyThemeConfig(themeConfig, root);
767
+ // Update global project ID if available
768
+ if (projectId) {
769
+ (0, exports.setGlobalProjectId)(projectId);
770
+ setActualProjectId(projectId);
771
+ }
672
772
  };
673
773
  var contextValue = (0, react_1.useMemo)(function () { return ({
674
774
  variant: variant,
@@ -678,8 +778,8 @@ var ThemeProvider = function (_a) {
678
778
  isLoading: isLoading,
679
779
  isInitialLoad: isInitialLoad,
680
780
  error: error,
681
- projectId: projectId,
682
- }); }, [variant, themeConfig, projectData, isLoading, isInitialLoad, error, projectId]);
781
+ projectId: actualProjectId, // Use actual project ID in context
782
+ }); }, [variant, themeConfig, projectData, isLoading, isInitialLoad, error, actualProjectId]);
683
783
  return (react_1.default.createElement(ThemeContext.Provider, { value: contextValue },
684
784
  react_1.default.createElement("div", { className: "theme-".concat(theme, " ").concat(funcss), style: {
685
785
  backgroundColor: 'var(--page-bg)',
@@ -874,8 +974,9 @@ var useBuckets = function () {
874
974
  var _a = (0, react_1.useState)([]), buckets = _a[0], setBuckets = _a[1];
875
975
  (0, react_1.useEffect)(function () {
876
976
  if (projectData === null || projectData === void 0 ? void 0 : projectData.buckets) {
977
+ var projectId_1 = projectData.project_id || (0, exports.getGlobalProjectId)() || '';
877
978
  var transformedBuckets = projectData.buckets.map(function (bucket) {
878
- return transformProjectBucket(bucket, projectData.project_id || '');
979
+ return transformProjectBucket(bucket, projectId_1);
879
980
  });
880
981
  setBuckets(transformedBuckets);
881
982
  cachedBuckets = transformedBuckets;
@@ -1409,6 +1510,24 @@ exports.getPaginatedRecords = getPaginatedRecords;
1409
1510
  // /* -------------------------------------------------------------------------- */
1410
1511
  // /* BUCKET JSON LOADER */
1411
1512
  // /* -------------------------------------------------------------------------- */
1513
+ // // Cache for JSON responses
1514
+ // const jsonFileCache = new Map<string, { data: JsonFileData; timestamp: number }>()
1515
+ // const CACHE_DURATION = 5 * 60 * 1000 // 5 minutes
1516
+ // // Helper function to get cache key
1517
+ // const getCacheKey = (bucketSanitizedName: string, projectId: string, page: number): string => {
1518
+ // return `${projectId}:${bucketSanitizedName}:${page}`
1519
+ // }
1520
+ // // Helper function to clean expired cache entries
1521
+ // const cleanExpiredCache = () => {
1522
+ // const now = Date.now()
1523
+ // for (const key of Array.from(jsonFileCache.keys())) {
1524
+ // const entry = jsonFileCache.get(key)
1525
+ // if (entry && now - entry.timestamp > CACHE_DURATION) {
1526
+ // jsonFileCache.delete(key)
1527
+ // }
1528
+ // }
1529
+ // }
1530
+ // // Load JSON file with caching and performance optimizations
1412
1531
  // const loadBucketJsonFromCDN = async (
1413
1532
  // bucketSanitizedName: string,
1414
1533
  // projectId: string,
@@ -1418,26 +1537,67 @@ exports.getPaginatedRecords = getPaginatedRecords;
1418
1537
  // console.error('❌ Missing parameters for JSON loading')
1419
1538
  // return null
1420
1539
  // }
1540
+ // // Clean expired cache entries periodically
1541
+ // if (jsonFileCache.size > 100) { // Only clean when cache gets large
1542
+ // cleanExpiredCache()
1543
+ // }
1544
+ // // Check cache first
1545
+ // const cacheKey = getCacheKey(bucketSanitizedName, projectId, page)
1546
+ // const cached = jsonFileCache.get(cacheKey)
1547
+ // if (cached && (Date.now() - cached.timestamp < CACHE_DURATION)) {
1548
+ // console.log(`đŸ“Ļ Returning cached data for page ${page}`)
1549
+ // return cached.data
1550
+ // }
1421
1551
  // try {
1422
1552
  // // Construct the URL for JSON files
1423
1553
  // const pageNumber = page.toString()
1424
1554
  // const publicUrl = `https://firebasestorage.googleapis.com/v0/b/funui-4bcd1.firebasestorage.app/o/projects%2F${projectId}%2Fbuckets%2F${bucketSanitizedName}%2F${pageNumber}.json?alt=media`
1555
+ // // Use AbortController for request timeout
1556
+ // const controller = new AbortController()
1557
+ // const timeoutId = setTimeout(() => controller.abort(), 10000) // 10 second timeout
1425
1558
  // const response = await fetch(publicUrl, {
1426
1559
  // cache: 'no-cache',
1560
+ // signal: controller.signal
1427
1561
  // })
1562
+ // clearTimeout(timeoutId)
1428
1563
  // if (response.ok) {
1429
1564
  // const data = await response.json()
1430
- // console.log(data)
1565
+ // // Cache the response
1566
+ // jsonFileCache.set(cacheKey, {
1567
+ // data,
1568
+ // timestamp: Date.now()
1569
+ // })
1431
1570
  // return data
1432
1571
  // } else {
1433
1572
  // // File might not exist (e.g., page out of range)
1434
1573
  // return null
1435
1574
  // }
1436
1575
  // } catch (error) {
1437
- // console.error(`❌ Error loading JSON file for page ${page}:`, error)
1576
+ // if (error instanceof DOMException && error.name === 'AbortError') {
1577
+ // console.error(`⏰ Timeout loading JSON file for page ${page}`)
1578
+ // } else {
1579
+ // console.error(`❌ Error loading JSON file for page ${page}:`, error)
1580
+ // }
1438
1581
  // return null
1439
1582
  // }
1440
1583
  // }
1584
+ // // Parallel loading for multiple pages
1585
+ // const loadMultipleJsonPages = async (
1586
+ // bucketSanitizedName: string,
1587
+ // projectId: string,
1588
+ // pages: number[]
1589
+ // ): Promise<(JsonFileData | null)[]> => {
1590
+ // try {
1591
+ // const promises = pages.map(page =>
1592
+ // loadBucketJsonFromCDN(bucketSanitizedName, projectId, page)
1593
+ // )
1594
+ // const results = await Promise.all(promises)
1595
+ // return results.filter(Boolean) as JsonFileData[]
1596
+ // } catch (error) {
1597
+ // console.error('❌ Error loading multiple JSON pages:', error)
1598
+ // return []
1599
+ // }
1600
+ // }
1441
1601
  // const listBucketJsonFiles = async (
1442
1602
  // bucketSanitizedName: string,
1443
1603
  // projectId: string
@@ -1450,24 +1610,39 @@ exports.getPaginatedRecords = getPaginatedRecords;
1450
1610
  // const files: JsonFileInfo[] = []
1451
1611
  // let page = 1
1452
1612
  // let hasMoreFiles = true
1613
+ // // Check multiple pages in parallel for faster discovery
1614
+ // const batchSize = 5
1615
+ // const pageChecks = []
1453
1616
  // while (hasMoreFiles && page <= 100) {
1454
- // const paddedPage = page.toString().padStart(3, '0')
1455
- // const publicUrl = `https://firebasestorage.googleapis.com/v0/b/funui-4bcd1.firebasestorage.app/o/projects%2F${projectId}%2Fbuckets%2F${bucketSanitizedName}%2Fpage_${paddedPage}.json?alt=media`
1456
- // const response = await fetch(publicUrl, {
1457
- // method: 'HEAD',
1458
- // cache: 'no-cache',
1459
- // })
1460
- // if (response.ok) {
1461
- // files.push({
1462
- // name: `page_${paddedPage}.json`,
1463
- // fullPath: `projects/${projectId}/buckets/${bucketSanitizedName}/page_${paddedPage}.json`,
1464
- // url: publicUrl,
1465
- // size: parseInt(response.headers.get('content-length') || '0', 10),
1466
- // page: page
1467
- // })
1617
+ // const batchPromises = []
1618
+ // for (let i = 0; i < batchSize && page <= 100; i++) {
1619
+ // const paddedPage = page.toString().padStart(3, '0')
1620
+ // const publicUrl = `https://firebasestorage.googleapis.com/v0/b/funui-4bcd1.firebasestorage.app/o/projects%2F${projectId}%2Fbuckets%2F${bucketSanitizedName}%2Fpage_${paddedPage}.json?alt=media`
1621
+ // batchPromises.push(
1622
+ // fetch(publicUrl, {
1623
+ // method: 'HEAD',
1624
+ // cache: 'no-cache',
1625
+ // })
1626
+ // )
1468
1627
  // page++
1469
- // } else {
1470
- // hasMoreFiles = false
1628
+ // }
1629
+ // const responses = await Promise.all(batchPromises)
1630
+ // for (let i = 0; i < responses.length; i++) {
1631
+ // if (responses[i].ok) {
1632
+ // const currentPage = page - batchSize + i
1633
+ // const paddedPage = currentPage.toString().padStart(3, '0')
1634
+ // const publicUrl = `https://firebasestorage.googleapis.com/v0/b/funui-4bcd1.firebasestorage.app/o/projects%2F${projectId}%2Fbuckets%2F${bucketSanitizedName}%2Fpage_${paddedPage}.json?alt=media`
1635
+ // files.push({
1636
+ // name: `page_${paddedPage}.json`,
1637
+ // fullPath: `projects/${projectId}/buckets/${bucketSanitizedName}/page_${paddedPage}.json`,
1638
+ // url: publicUrl,
1639
+ // size: parseInt(responses[i].headers.get('content-length') || '0', 10),
1640
+ // page: currentPage
1641
+ // })
1642
+ // } else {
1643
+ // hasMoreFiles = false
1644
+ // break
1645
+ // }
1471
1646
  // }
1472
1647
  // }
1473
1648
  // return files
@@ -1540,7 +1715,6 @@ exports.getPaginatedRecords = getPaginatedRecords;
1540
1715
  // const transformProjectBucket = (bucket: any, projectId: string): Bucket => {
1541
1716
  // return {
1542
1717
  // id: bucket.id || bucket._id || '',
1543
- // // projectId: bucket.projectId || projectId || '',
1544
1718
  // name: bucket.name || '',
1545
1719
  // displayName: bucket.displayName || bucket.name || '',
1546
1720
  // category: bucket.category || 'uncategorized',
@@ -1616,59 +1790,65 @@ exports.getPaginatedRecords = getPaginatedRecords;
1616
1790
  // console.log('✅ Using provided project data directly')
1617
1791
  // finalTheme = providedProject
1618
1792
  // finalVersion = providedProject.version || 0
1619
- // } else {
1620
- // // Otherwise, follow the normal loading flow
1621
- // // First, try to load local theme
1622
- // const localTheme = await loadLocalTheme()
1623
- // const localVersion = localTheme?.version || 0
1624
- // if (projectId) {
1625
- // // Validate origin access for CDN
1626
- // const hasAccess = await validateOriginAccess(projectId)
1627
- // if (hasAccess) {
1628
- // // Try to load from CDN
1629
- // const cdnTheme = await loadThemeFromCDN(projectId)
1630
- // const cdnVersion = cdnTheme?.version || 0
1631
- // if (cdnTheme) {
1632
- // // CDN theme available - use it
1633
- // finalTheme = cdnTheme
1634
- // finalVersion = cdnVersion
1635
- // if (cdnVersion !== localVersion) {
1636
- // console.log(`🔄 Version mismatch: Local(${localVersion}) vs CDN(${cdnVersion})`)
1637
- // console.log('â„šī¸ Using CDN version. Please update your local funui.json file manually.')
1638
- // }
1639
- // } else if (localTheme) {
1640
- // // CDN not available but we have local theme
1641
- // console.log('âš ī¸ CDN unavailable, using local theme')
1642
- // finalTheme = localTheme
1643
- // finalVersion = localVersion
1644
- // } else {
1645
- // // No theme available anywhere
1646
- // console.warn('âš ī¸ No theme found (CDN unavailable and no local theme)')
1647
- // setError('Theme not found')
1793
+ // // Apply theme immediately
1794
+ // applyThemeData(finalTheme, root)
1795
+ // setCurrentVersion(finalVersion)
1796
+ // setError(null)
1797
+ // setIsLoading(false)
1798
+ // setIsInitialLoad(false)
1799
+ // return // Skip all other loading logic
1800
+ // }
1801
+ // // Otherwise, follow the normal loading flow
1802
+ // // First, try to load local theme
1803
+ // const localTheme = await loadLocalTheme()
1804
+ // const localVersion = localTheme?.version || 0
1805
+ // if (projectId) {
1806
+ // // Validate origin access for CDN
1807
+ // const hasAccess = await validateOriginAccess(projectId)
1808
+ // if (hasAccess) {
1809
+ // // Try to load from CDN
1810
+ // const cdnTheme = await loadThemeFromCDN(projectId)
1811
+ // const cdnVersion = cdnTheme?.version || 0
1812
+ // if (cdnTheme) {
1813
+ // // CDN theme available - use it
1814
+ // finalTheme = cdnTheme
1815
+ // finalVersion = cdnVersion
1816
+ // if (cdnVersion !== localVersion) {
1817
+ // console.log(`🔄 Version mismatch: Local(${localVersion}) vs CDN(${cdnVersion})`)
1818
+ // console.log('â„šī¸ Using CDN version. Please update your local funui.json file manually.')
1648
1819
  // }
1820
+ // } else if (localTheme) {
1821
+ // // CDN not available but we have local theme
1822
+ // console.log('âš ī¸ CDN unavailable, using local theme')
1823
+ // finalTheme = localTheme
1824
+ // finalVersion = localVersion
1649
1825
  // } else {
1650
- // // Origin validation failed
1651
- // if (localTheme) {
1652
- // console.log('âš ī¸ Origin validation failed, using local theme')
1653
- // finalTheme = localTheme
1654
- // finalVersion = localVersion
1655
- // } else {
1656
- // console.error('❌ Origin validation failed and no local theme available')
1657
- // setError('Access denied and no local theme available')
1658
- // }
1826
+ // // No theme available anywhere
1827
+ // console.warn('âš ī¸ No theme found (CDN unavailable and no local theme)')
1828
+ // setError('Theme not found')
1659
1829
  // }
1660
1830
  // } else {
1661
- // // No project ID provided - only use local theme
1662
- // console.log('â„šī¸ No project ID provided, using local theme only')
1831
+ // // Origin validation failed
1663
1832
  // if (localTheme) {
1833
+ // console.log('âš ī¸ Origin validation failed, using local theme')
1664
1834
  // finalTheme = localTheme
1665
1835
  // finalVersion = localVersion
1666
- // console.log('✅ Theme loaded from local file')
1667
1836
  // } else {
1668
- // console.log('â„šī¸ No local theme file found - using base theme only')
1669
- // // No error here - it's valid to use only base theme
1837
+ // console.error('❌ Origin validation failed and no local theme available')
1838
+ // setError('Access denied and no local theme available')
1670
1839
  // }
1671
1840
  // }
1841
+ // } else {
1842
+ // // No project ID provided - only use local theme
1843
+ // console.log('â„šī¸ No project ID provided, using local theme only')
1844
+ // if (localTheme) {
1845
+ // finalTheme = localTheme
1846
+ // finalVersion = localVersion
1847
+ // console.log('✅ Theme loaded from local file')
1848
+ // } else {
1849
+ // console.log('â„šī¸ No local theme file found - using base theme only')
1850
+ // // No error here - it's valid to use only base theme
1851
+ // }
1672
1852
  // }
1673
1853
  // // Apply the theme if we have one
1674
1854
  // if (finalTheme && (!currentVersion || finalVersion !== currentVersion)) {
@@ -1686,18 +1866,28 @@ exports.getPaginatedRecords = getPaginatedRecords;
1686
1866
  // setIsInitialLoad(false)
1687
1867
  // }
1688
1868
  // }
1689
- // // Initial load
1690
- // loadTheme()
1691
- // // Only poll for updates if we have a project ID AND no provided project
1692
- // if (projectId && !providedProject) {
1693
- // pollTimer = setInterval(() => {
1694
- // loadTheme()
1695
- // }, 5 * 60 * 1000)
1696
- // }
1697
- // return () => {
1698
- // if (pollTimer) {
1699
- // clearInterval(pollTimer)
1869
+ // // Only load theme if no project is provided
1870
+ // if (!providedProject) {
1871
+ // // Initial load
1872
+ // loadTheme()
1873
+ // // Only poll for updates if we have a project ID
1874
+ // if (projectId) {
1875
+ // pollTimer = setInterval(() => {
1876
+ // loadTheme()
1877
+ // }, 5 * 60 * 1000)
1878
+ // }
1879
+ // return () => {
1880
+ // if (pollTimer) {
1881
+ // clearInterval(pollTimer)
1882
+ // }
1700
1883
  // }
1884
+ // } else {
1885
+ // // If project is provided, skip loading and set state directly
1886
+ // console.log('✅ Using provided project data, skipping theme loading')
1887
+ // applyThemeData(providedProject, document.documentElement)
1888
+ // setCurrentVersion(providedProject.version || 0)
1889
+ // setIsLoading(false)
1890
+ // setIsInitialLoad(false)
1701
1891
  // }
1702
1892
  // }, [projectId, currentVersion, theme, providedProject]) // Added providedProject to dependencies
1703
1893
  // const applyThemeData = (data: ProjectData, root: HTMLElement) => {
@@ -1809,7 +1999,7 @@ exports.getPaginatedRecords = getPaginatedRecords;
1809
1999
  // let cachedAssets: Asset[] = []
1810
2000
  // export const getAsset = (name: string): Asset | undefined => {
1811
2001
  // if (!cachedAssets.length) {
1812
- // console.warn('No assets available. Make sure ThemeProvider is mounted and assets are loaded.')
2002
+ // console.warn('No assets available. Make sure ThemeProvider is mounted.')
1813
2003
  // return undefined
1814
2004
  // }
1815
2005
  // const asset = cachedAssets.find(a => a.name === name)
@@ -2068,14 +2258,19 @@ exports.getPaginatedRecords = getPaginatedRecords;
2068
2258
  // try {
2069
2259
  // setLoading(true)
2070
2260
  // setError(null)
2261
+ // // Load pages in parallel for better performance
2262
+ // const pageNumbers = files.map(file => file.page)
2263
+ // const jsonDataArray = await loadMultipleJsonPages(
2264
+ // sanitizeBucketName(bucket.displayName || bucket.name),
2265
+ // projectId,
2266
+ // pageNumbers
2267
+ // )
2071
2268
  // const allRecords: BucketRecord[] = []
2072
- // for (const file of files) {
2073
- // const bucketSanitizedName = sanitizeBucketName(bucket.displayName || bucket.name)
2074
- // const jsonData = await loadBucketJsonFromCDN(bucketSanitizedName, projectId, file.page)
2269
+ // jsonDataArray.forEach(jsonData => {
2075
2270
  // if (jsonData && jsonData.records) {
2076
2271
  // allRecords.push(...jsonData.records)
2077
2272
  // }
2078
- // }
2273
+ // })
2079
2274
  // setRecords(allRecords)
2080
2275
  // } catch (err) {
2081
2276
  // console.error('Error loading all records:', err)
@@ -2107,11 +2302,19 @@ exports.getPaginatedRecords = getPaginatedRecords;
2107
2302
  // const cacheKey = `${bucket.id}_${projectId}`
2108
2303
  // delete cachedJsonFiles[cacheKey]
2109
2304
  // delete cachedJsonData[cacheKey]
2305
+ // // Also clear JSON file cache
2306
+ // const bucketSanitizedName = sanitizeBucketName(bucket.displayName || bucket.name)
2307
+ // for (const key of Array.from(jsonFileCache.keys())) {
2308
+ // if (key.startsWith(`${projectId}:${bucketSanitizedName}`)) {
2309
+ // jsonFileCache.delete(key)
2310
+ // }
2311
+ // }
2110
2312
  // }
2111
2313
  // }
2112
2314
  // } else {
2113
2315
  // cachedJsonFiles = {}
2114
2316
  // cachedJsonData = {}
2317
+ // jsonFileCache.clear()
2115
2318
  // }
2116
2319
  // }, [])
2117
2320
  // const refresh = useCallback(() => {