@widgetic/editor 4.0.1 → 4.0.3
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/components/MockWidget.svelte +1 -1
- package/dist/components/WidgetPreview.svelte +36 -52
- package/dist/components/editors/EmbedEditor.svelte +1 -1
- package/dist/components/editors/PropsEditor.svelte +309 -227
- package/dist/components/ic/BrowserInputController.svelte +26 -19
- package/dist/components/ic/CheckboxInputController.svelte +1 -1
- package/dist/components/ic/ColorPickerInputController.svelte +37 -37
- package/dist/components/ic/DatePickerInputController.svelte +6 -6
- package/dist/components/ic/DropdownInputController.svelte +1 -1
- package/dist/components/ic/FontInputController.svelte +225 -116
- package/dist/components/ic/FontInputController.svelte.d.ts +4 -2
- package/dist/components/ic/NumberInputController.svelte +37 -37
- package/dist/components/ic/RadioGroupInputController.svelte +1 -1
- package/dist/components/ic/SliderRangeInputController.svelte +1 -1
- package/dist/components/ic/SwitchInputController.svelte +1 -1
- package/dist/components/ic/TextAreaInputController.svelte +213 -85
- package/dist/components/ic/TextAreaInputController.svelte.d.ts +1 -0
- package/dist/components/ic/TextAreaPreviewInputController.svelte +81 -79
- package/dist/components/ic/VectorInputController.svelte +34 -34
- package/dist/components/ic/shared/CategoryTabs.svelte +1 -0
- package/dist/components/ic/shared/RecentItemsSection.svelte +21 -6
- package/dist/components/ic/shared/RecentItemsSection.svelte.d.ts +1 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +19 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/stores/userSession.d.ts +1 -1
- package/dist/stores/userSession.js +17 -2
- package/dist/utils/FontManager.d.ts +3 -1
- package/dist/utils/FontManager.js +95 -103
- package/dist/utils/VectorManager.d.ts +3 -1
- package/dist/utils/VectorManager.js +30 -70
- package/dist/utils/colorTransparency.js +3 -3
- package/dist/utils/fontUtils.js +1 -1
- package/dist/utils/passiveEvents.d.ts +5 -0
- package/dist/utils/passiveEvents.js +9 -18
- package/dist/utils/recentColors.js +15 -15
- package/dist/utils/vectorUtils.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,22 @@
|
|
|
1
1
|
import { writable } from 'svelte/store';
|
|
2
|
+
const isBrowser = typeof window !== 'undefined';
|
|
3
|
+
let initialJwt = null;
|
|
4
|
+
let initialUser = null;
|
|
5
|
+
if (isBrowser) {
|
|
6
|
+
try {
|
|
7
|
+
initialJwt = localStorage.getItem('jwt');
|
|
8
|
+
const userStr = localStorage.getItem('user');
|
|
9
|
+
if (userStr) {
|
|
10
|
+
initialUser = JSON.parse(userStr);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
console.error('Failed to read initial session from localStorage:', error);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
2
17
|
export const userSession = writable({
|
|
3
|
-
user:
|
|
4
|
-
jwt:
|
|
18
|
+
user: initialUser,
|
|
19
|
+
jwt: initialJwt
|
|
5
20
|
});
|
|
6
21
|
export function setSession(user, jwt) {
|
|
7
22
|
userSession.set({ user, jwt });
|
|
@@ -25,7 +25,7 @@ export interface FontData {
|
|
|
25
25
|
/** Google Web Fonts API variant ids (e.g. "400", "700", "regular") */
|
|
26
26
|
variants?: string[];
|
|
27
27
|
}
|
|
28
|
-
/** Maps Google Fonts API variant ids to display weight labels. */
|
|
28
|
+
/** Maps Google Fonts API variant ids to display weight labels (includes italic faces). */
|
|
29
29
|
export declare function mapGoogleVariantIdsToWeightNames(variants: string[]): string[];
|
|
30
30
|
declare class FontManager {
|
|
31
31
|
private static readonly DEBUG_MODE;
|
|
@@ -70,6 +70,8 @@ declare class FontManager {
|
|
|
70
70
|
private static forbiddenApiKeyWarned;
|
|
71
71
|
private static badRequestApiKeyWarned;
|
|
72
72
|
private catalogFetchPromise;
|
|
73
|
+
/** Popular Google families shown when the Web Fonts API key is missing or blocked. */
|
|
74
|
+
private static getFallbackCatalog;
|
|
73
75
|
private hasGoogleFontsApiKey;
|
|
74
76
|
private warnMissingApiKey;
|
|
75
77
|
private warnForbiddenApiKey;
|
|
@@ -8,43 +8,68 @@ const fontWeightOrder = {
|
|
|
8
8
|
ExtraLight: 2,
|
|
9
9
|
Light: 3,
|
|
10
10
|
Regular: 4,
|
|
11
|
+
Italic: 4.5,
|
|
11
12
|
Medium: 5,
|
|
13
|
+
'Medium Italic': 5.5,
|
|
12
14
|
SemiBold: 6,
|
|
15
|
+
'SemiBold Italic': 6.5,
|
|
13
16
|
Bold: 7,
|
|
17
|
+
'Bold Italic': 7.5,
|
|
14
18
|
ExtraBold: 8,
|
|
19
|
+
'ExtraBold Italic': 8.5,
|
|
15
20
|
Black: 9,
|
|
21
|
+
'Black Italic': 9.5,
|
|
22
|
+
'Light Italic': 3.5,
|
|
23
|
+
'Thin Italic': 1.5,
|
|
24
|
+
'ExtraLight Italic': 2.5,
|
|
16
25
|
};
|
|
17
|
-
|
|
26
|
+
function googleVariantIdToWeightName(variant) {
|
|
27
|
+
const italic = /italic/i.test(variant);
|
|
28
|
+
const base = variant.replace(/italic/ig, '').toLowerCase() || 'regular';
|
|
29
|
+
let name;
|
|
30
|
+
switch (base) {
|
|
31
|
+
case '100':
|
|
32
|
+
name = 'Thin';
|
|
33
|
+
break;
|
|
34
|
+
case '200':
|
|
35
|
+
name = 'ExtraLight';
|
|
36
|
+
break;
|
|
37
|
+
case '300':
|
|
38
|
+
name = 'Light';
|
|
39
|
+
break;
|
|
40
|
+
case '400':
|
|
41
|
+
case 'regular':
|
|
42
|
+
case '':
|
|
43
|
+
name = 'Regular';
|
|
44
|
+
break;
|
|
45
|
+
case '500':
|
|
46
|
+
name = 'Medium';
|
|
47
|
+
break;
|
|
48
|
+
case '600':
|
|
49
|
+
name = 'SemiBold';
|
|
50
|
+
break;
|
|
51
|
+
case '700':
|
|
52
|
+
case 'bold':
|
|
53
|
+
name = 'Bold';
|
|
54
|
+
break;
|
|
55
|
+
case '800':
|
|
56
|
+
name = 'ExtraBold';
|
|
57
|
+
break;
|
|
58
|
+
case '900':
|
|
59
|
+
name = 'Black';
|
|
60
|
+
break;
|
|
61
|
+
default:
|
|
62
|
+
name = base;
|
|
63
|
+
}
|
|
64
|
+
if (!italic)
|
|
65
|
+
return name;
|
|
66
|
+
return name === 'Regular' ? 'Italic' : `${name} Italic`;
|
|
67
|
+
}
|
|
68
|
+
/** Maps Google Fonts API variant ids to display weight labels (includes italic faces). */
|
|
18
69
|
export function mapGoogleVariantIdsToWeightNames(variants) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
switch (v) {
|
|
23
|
-
case '100':
|
|
24
|
-
return 'Thin';
|
|
25
|
-
case '200':
|
|
26
|
-
return 'ExtraLight';
|
|
27
|
-
case '300':
|
|
28
|
-
return 'Light';
|
|
29
|
-
case '400':
|
|
30
|
-
case 'regular':
|
|
31
|
-
return 'Regular';
|
|
32
|
-
case '500':
|
|
33
|
-
return 'Medium';
|
|
34
|
-
case '600':
|
|
35
|
-
return 'SemiBold';
|
|
36
|
-
case '700':
|
|
37
|
-
case 'bold':
|
|
38
|
-
return 'Bold';
|
|
39
|
-
case '800':
|
|
40
|
-
return 'ExtraBold';
|
|
41
|
-
case '900':
|
|
42
|
-
return 'Black';
|
|
43
|
-
default:
|
|
44
|
-
return v;
|
|
45
|
-
}
|
|
46
|
-
})
|
|
47
|
-
.sort((a, b) => (fontWeightOrder[a] || 99) - (fontWeightOrder[b] || 99));
|
|
70
|
+
const names = variants.map(googleVariantIdToWeightName);
|
|
71
|
+
const unique = [...new Set(names)];
|
|
72
|
+
return unique.sort((a, b) => (fontWeightOrder[a] || 99) - (fontWeightOrder[b] || 99));
|
|
48
73
|
}
|
|
49
74
|
class FontManager {
|
|
50
75
|
// Debug configuration
|
|
@@ -112,6 +137,25 @@ class FontManager {
|
|
|
112
137
|
static forbiddenApiKeyWarned = false;
|
|
113
138
|
static badRequestApiKeyWarned = false;
|
|
114
139
|
catalogFetchPromise = null;
|
|
140
|
+
/** Popular Google families shown when the Web Fonts API key is missing or blocked. */
|
|
141
|
+
static getFallbackCatalog() {
|
|
142
|
+
const sans = ['Inter', 'Roboto', 'Open Sans', 'Poppins', 'Lato', 'Montserrat', 'Nunito', 'Source Sans 3', 'Work Sans', 'DM Sans'];
|
|
143
|
+
const serif = ['Playfair Display', 'Merriweather', 'Libre Baskerville', 'Lora', 'Cormorant Garamond'];
|
|
144
|
+
const script = ['Dancing Script', 'Pacifico', 'Great Vibes'];
|
|
145
|
+
const other = ['Oswald', 'Raleway', 'Space Grotesk'];
|
|
146
|
+
const pack = (families, category) => families.map((family) => ({
|
|
147
|
+
family,
|
|
148
|
+
category,
|
|
149
|
+
isCustom: false,
|
|
150
|
+
variants: ['regular', 'italic', '500', '500italic', '600', '600italic', '700', '700italic'],
|
|
151
|
+
}));
|
|
152
|
+
return [
|
|
153
|
+
...pack(sans, 'Sans Serif'),
|
|
154
|
+
...pack(serif, 'Serif'),
|
|
155
|
+
...pack(script, 'Script'),
|
|
156
|
+
...pack(other, 'Other'),
|
|
157
|
+
];
|
|
158
|
+
}
|
|
115
159
|
hasGoogleFontsApiKey() {
|
|
116
160
|
return Boolean(this.apiKey?.trim());
|
|
117
161
|
}
|
|
@@ -128,7 +172,7 @@ class FontManager {
|
|
|
128
172
|
FontManager.forbiddenApiKeyWarned = true;
|
|
129
173
|
console.warn('[FontManager] Google Fonts API returned 403 Forbidden. Fix in Google Cloud Console: ' +
|
|
130
174
|
'(1) Enable "Web Fonts Developer API" on the project, ' +
|
|
131
|
-
'(2) API key → Application restrictions → HTTP referrers: http://localhost:
|
|
175
|
+
'(2) API key → Application restrictions → HTTP referrers: http://localhost:5173/*, http://localhost:5174/*, http://localhost:5180/*, https://*.widgetic.com/*, ' +
|
|
132
176
|
'(3) use a key created for Web Fonts (not Gemini/other APIs). Font picker falls back to cached/custom fonts.');
|
|
133
177
|
}
|
|
134
178
|
warnBadRequestApiKey() {
|
|
@@ -136,7 +180,7 @@ class FontManager {
|
|
|
136
180
|
return;
|
|
137
181
|
FontManager.badRequestApiKeyWarned = true;
|
|
138
182
|
console.warn('[FontManager] Google Fonts API returned 400 Bad Request. Usually: invalid API key, Web Fonts Developer API not enabled, or wrong key type. ' +
|
|
139
|
-
'Use
|
|
183
|
+
'Use a Web Fonts Developer API key (not Gemini). Set PUBLIC_GOOGLE_FONTS_API_KEY and VITE_GOOGLE_FONTS_API_KEY in Frontend/site/.env and widget-creator/.env, restart Vite. ' +
|
|
140
184
|
'Font picker falls back to cached/custom fonts.');
|
|
141
185
|
}
|
|
142
186
|
/**
|
|
@@ -217,7 +261,7 @@ class FontManager {
|
|
|
217
261
|
*/
|
|
218
262
|
async initialize() {
|
|
219
263
|
if (FontManager.isInitialized) {
|
|
220
|
-
console.log('✅ [FontManager] Already initialized');
|
|
264
|
+
// console.log('✅ [FontManager] Already initialized');
|
|
221
265
|
return;
|
|
222
266
|
}
|
|
223
267
|
try {
|
|
@@ -252,74 +296,22 @@ class FontManager {
|
|
|
252
296
|
: await this.fetchGoogleFontsCatalog();
|
|
253
297
|
if (catalog?.length) {
|
|
254
298
|
this.catalog = { stage: 'complete', fonts: catalog };
|
|
255
|
-
//
|
|
299
|
+
// Index initial fonts for each category without blocking startup
|
|
256
300
|
const categories = ['Serif', 'Sans Serif', 'Script', 'Other'];
|
|
257
|
-
|
|
258
|
-
await Promise.all(categories.map(async (category) => {
|
|
301
|
+
categories.forEach(category => {
|
|
259
302
|
const categoryFonts = this.catalogFonts
|
|
260
303
|
.filter(font => fontCategories.normalize(font.category) === category)
|
|
261
304
|
.slice(0, FontManager.initialFontNumber);
|
|
262
305
|
this.categoryFonts.set(category, categoryFonts);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
try {
|
|
266
|
-
await this.insertFontStylesheet(font.family);
|
|
267
|
-
await this.loadFont(font.family, ['400', '500', '600', '700']);
|
|
268
|
-
}
|
|
269
|
-
catch (error) {
|
|
270
|
-
console.warn(`⚠️ [FontManager] Failed to preload font: ${font.family}`, error);
|
|
271
|
-
}
|
|
272
|
-
}));
|
|
273
|
-
// console.log(`📚 [FontManager] Preloaded fonts for ${category}:`, {
|
|
274
|
-
// total: categoryFonts.length,
|
|
275
|
-
// sample: categoryFonts.slice(0, 3).map(f => f.family)
|
|
276
|
-
// });
|
|
277
|
-
}));
|
|
278
|
-
// Save filtered list to localStorage cache
|
|
306
|
+
});
|
|
307
|
+
// Save filtered list to cache
|
|
279
308
|
this.saveFontListToCache(this.catalogFonts);
|
|
280
|
-
// console.log('📚 [FontManager] Complete font list cached:', {
|
|
281
|
-
// total: this.cachedFontList.length,
|
|
282
|
-
// categoriesPreloaded: Array.from(this.categoryFonts.keys())
|
|
283
|
-
// });
|
|
284
309
|
}
|
|
285
310
|
}
|
|
286
311
|
catch (error) {
|
|
287
312
|
// console.error('❌ [FontManager] Error caching complete font list:', error);
|
|
288
313
|
}
|
|
289
|
-
//
|
|
290
|
-
const initialFonts = [
|
|
291
|
-
'Roboto', 'Open Sans', 'Montserrat', 'Poppins',
|
|
292
|
-
'Lato', 'Inter'
|
|
293
|
-
].filter(font => !shouldSkipFont(font));
|
|
294
|
-
// Add popular fonts from the initial list
|
|
295
|
-
const popularFonts = initialFontList
|
|
296
|
-
.slice(0, FontManager.initialFontNumber)
|
|
297
|
-
.map(font => font.family)
|
|
298
|
-
.filter(family => !initialFonts.includes(family));
|
|
299
|
-
// Combine all fonts to preload: initial fonts + recent fonts + popular fonts
|
|
300
|
-
const fontsToLoad = [...new Set([
|
|
301
|
-
...initialFonts,
|
|
302
|
-
...recentFonts.map(font => font.family),
|
|
303
|
-
...popularFonts
|
|
304
|
-
])].filter(font => !this.loadedFonts.has(font));
|
|
305
|
-
if (fontsToLoad.length > 0) {
|
|
306
|
-
// console.log('🔄 [FontManager] Preloading fonts:', fontsToLoad);
|
|
307
|
-
// Load all fonts in parallel with all weights
|
|
308
|
-
const loadPromises = fontsToLoad.map(async (family) => {
|
|
309
|
-
try {
|
|
310
|
-
await this.insertFontStylesheet(family);
|
|
311
|
-
await this.loadFont(family, ['400', '500', '600', '700']);
|
|
312
|
-
}
|
|
313
|
-
catch (error) {
|
|
314
|
-
console.warn(`⚠️ [FontManager] Failed to load font: ${family}`, error);
|
|
315
|
-
}
|
|
316
|
-
});
|
|
317
|
-
await Promise.all(loadPromises);
|
|
318
|
-
}
|
|
319
|
-
else {
|
|
320
|
-
console.log('✨ [FontManager] All initial fonts already cached');
|
|
321
|
-
}
|
|
322
|
-
// Only set initialized after everything is complete
|
|
314
|
+
// Only set initialized after catalog/custom setup is complete
|
|
323
315
|
FontManager.isInitialized = true;
|
|
324
316
|
// console.log('✅ [FontManager] Initialization complete. Font status:', {
|
|
325
317
|
// totalLoaded: this.loadedFonts.size,
|
|
@@ -621,7 +613,7 @@ class FontManager {
|
|
|
621
613
|
// Add custom fonts from fonts.json
|
|
622
614
|
const customFonts = await this.loadCustomFonts();
|
|
623
615
|
const catalog = await this.fetchGoogleFontsCatalog();
|
|
624
|
-
const googleFonts = catalog
|
|
616
|
+
const googleFonts = (catalog && catalog.length > 0) ? catalog : FontManager.getFallbackCatalog();
|
|
625
617
|
// Combine all fonts. A full Google catalog means the list is already
|
|
626
618
|
// complete; otherwise keep the 'initial' stage so a later fetch can
|
|
627
619
|
// still upgrade it.
|
|
@@ -638,7 +630,7 @@ class FontManager {
|
|
|
638
630
|
}
|
|
639
631
|
catch (error) {
|
|
640
632
|
console.error('Error getting initial fonts:', error);
|
|
641
|
-
return
|
|
633
|
+
return FontManager.getFallbackCatalog();
|
|
642
634
|
}
|
|
643
635
|
}
|
|
644
636
|
/**
|
|
@@ -684,7 +676,7 @@ class FontManager {
|
|
|
684
676
|
return null;
|
|
685
677
|
// Check if cache is expired
|
|
686
678
|
if (Date.now() - cache.timestamp > FontManager.CACHE_DURATION) {
|
|
687
|
-
console.log('⚠️ [FontManager] Cache expired, removing');
|
|
679
|
+
// console.log('⚠️ [FontManager] Cache expired, removing');
|
|
688
680
|
void deleteKvValue(FontManager.CACHE_KEY);
|
|
689
681
|
return null;
|
|
690
682
|
}
|
|
@@ -747,13 +739,13 @@ class FontManager {
|
|
|
747
739
|
}
|
|
748
740
|
// Return immediately if preload is already complete
|
|
749
741
|
if (FontManager.initialPreloadComplete) {
|
|
750
|
-
console.log('✅ [FontManager] Initial fonts already preloaded');
|
|
742
|
+
// console.log('✅ [FontManager] Initial fonts already preloaded');
|
|
751
743
|
return;
|
|
752
744
|
}
|
|
753
745
|
// Create new preload promise
|
|
754
746
|
FontManager.preloadPromise = (async () => {
|
|
755
747
|
try {
|
|
756
|
-
console.log('🚀 [FontManager] Preloading initial fonts...');
|
|
748
|
+
// console.log('🚀 [FontManager] Preloading initial fonts...');
|
|
757
749
|
const initialFonts = await this.getInitialFontList();
|
|
758
750
|
const loadPromises = initialFonts.map(font => {
|
|
759
751
|
this.insertFontStylesheet(font.family);
|
|
@@ -761,7 +753,7 @@ class FontManager {
|
|
|
761
753
|
});
|
|
762
754
|
await Promise.all(loadPromises);
|
|
763
755
|
FontManager.initialPreloadComplete = true;
|
|
764
|
-
console.log('✅ [FontManager] Initial fonts preloaded');
|
|
756
|
+
// console.log('✅ [FontManager] Initial fonts preloaded');
|
|
765
757
|
}
|
|
766
758
|
catch (error) {
|
|
767
759
|
console.error('❌ [FontManager] Error preloading initial fonts:', error);
|
|
@@ -1150,12 +1142,12 @@ class FontManager {
|
|
|
1150
1142
|
? Array.from(this.customFonts.values())
|
|
1151
1143
|
: this.catalogFonts.filter(font => fontCategories.normalize(font.category) === category);
|
|
1152
1144
|
const remainingItems = categoryFonts.length - currentIndex;
|
|
1153
|
-
console.log('🔍 [FontManager] Checking remaining fonts:', {
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
});
|
|
1145
|
+
// console.log('🔍 [FontManager] Checking remaining fonts:', {
|
|
1146
|
+
// category,
|
|
1147
|
+
// currentIndex,
|
|
1148
|
+
// totalInCategory: categoryFonts.length,
|
|
1149
|
+
// remainingItems
|
|
1150
|
+
// });
|
|
1159
1151
|
// Only return true if we have more items in this category
|
|
1160
1152
|
return remainingItems > 0;
|
|
1161
1153
|
}
|
|
@@ -1204,7 +1196,7 @@ class FontManager {
|
|
|
1204
1196
|
fonts: this.catalog.fonts.filter(font => font.family !== family || font.category !== 'Mine'),
|
|
1205
1197
|
};
|
|
1206
1198
|
}
|
|
1207
|
-
console.log('✅ [FontManager] Custom font removed:', family);
|
|
1199
|
+
// console.log('✅ [FontManager] Custom font removed:', family);
|
|
1208
1200
|
}
|
|
1209
1201
|
}
|
|
1210
1202
|
catch (error) {
|
|
@@ -46,6 +46,8 @@ declare class VectorManager {
|
|
|
46
46
|
static isInitialized: boolean;
|
|
47
47
|
static initialVectorNumber: number;
|
|
48
48
|
private static initializationPromise;
|
|
49
|
+
private static svgsFetchPromise;
|
|
50
|
+
private static fetchSvgsJson;
|
|
49
51
|
private remainingTime;
|
|
50
52
|
private preInitializedObservers;
|
|
51
53
|
static readonly BATCH_SIZE = 100;
|
|
@@ -86,7 +88,7 @@ declare class VectorManager {
|
|
|
86
88
|
*/
|
|
87
89
|
getInitialVectorList(): Promise<VectorData[]>;
|
|
88
90
|
/**
|
|
89
|
-
* Saves vector list to localStorage
|
|
91
|
+
* Saves vector list to cache (avoids writing 1.2MB JSON to localStorage)
|
|
90
92
|
*/
|
|
91
93
|
private saveVectorListToCache;
|
|
92
94
|
/**
|
|
@@ -33,6 +33,22 @@ class VectorManager {
|
|
|
33
33
|
static initialVectorNumber = 8; // 8 - how many vectors to load initially
|
|
34
34
|
// Add a static property to track initialization state
|
|
35
35
|
static initializationPromise = null;
|
|
36
|
+
static svgsFetchPromise = null;
|
|
37
|
+
static async fetchSvgsJson() {
|
|
38
|
+
if (!VectorManager.svgsFetchPromise) {
|
|
39
|
+
VectorManager.svgsFetchPromise = fetch('/svgs.json')
|
|
40
|
+
.then(response => {
|
|
41
|
+
if (!response.ok)
|
|
42
|
+
throw new Error('Failed to fetch vectors');
|
|
43
|
+
return response.json();
|
|
44
|
+
})
|
|
45
|
+
.catch(err => {
|
|
46
|
+
VectorManager.svgsFetchPromise = null;
|
|
47
|
+
throw err;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return VectorManager.svgsFetchPromise;
|
|
51
|
+
}
|
|
36
52
|
// Add this property
|
|
37
53
|
remainingTime = 0;
|
|
38
54
|
// Add a Map to store pre-initialized observers
|
|
@@ -97,54 +113,24 @@ class VectorManager {
|
|
|
97
113
|
category: vectorCategories.normalize(vector.category),
|
|
98
114
|
url: vector.url
|
|
99
115
|
}));
|
|
100
|
-
// Get initial vector list and cache it
|
|
116
|
+
// Get initial vector list and cache it (deduplicated fetch)
|
|
101
117
|
const initialVectorList = await this.getInitialVectorList();
|
|
102
118
|
// console.log('📋 [VectorManager] Initial vector list loaded:', initialVectorList.length);
|
|
103
|
-
//
|
|
119
|
+
// Setup category indexing without eager vector preloading
|
|
104
120
|
try {
|
|
105
|
-
// Load vectors from svgs.json instead of API
|
|
106
|
-
const response = await fetch('/svgs.json');
|
|
107
|
-
if (!response.ok)
|
|
108
|
-
throw new Error('Failed to fetch vectors');
|
|
109
|
-
const data = await response.json();
|
|
110
|
-
// Convert to VectorData format and cache
|
|
111
|
-
this.cachedVectorList = data.svgGroups.flatMap((group) => group.items.map((item) => ({
|
|
112
|
-
name: item.name,
|
|
113
|
-
category: vectorCategories.normalize(group.category),
|
|
114
|
-
url: item.url
|
|
115
|
-
})));
|
|
116
|
-
// Preload initial vectors for each category
|
|
117
121
|
const categories = ['Icons', 'Emojis', 'Clipart', 'Mine'];
|
|
118
|
-
|
|
119
|
-
await Promise.all(categories.map(async (category) => {
|
|
122
|
+
categories.forEach(category => {
|
|
120
123
|
const categoryVectors = this.cachedVectorList
|
|
121
124
|
.filter(vector => vectorCategories.normalize(vector.category) === category)
|
|
122
125
|
.slice(0, VectorManager.initialVectorNumber);
|
|
123
126
|
this.categoryVectors.set(category, categoryVectors);
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
try {
|
|
127
|
-
await this.loadVector(vector.name);
|
|
128
|
-
}
|
|
129
|
-
catch (error) {
|
|
130
|
-
console.warn(`⚠️ [VectorManager] Failed to preload vector: ${vector.name}`, error);
|
|
131
|
-
}
|
|
132
|
-
}));
|
|
133
|
-
// console.log(`📚 [VectorManager] Preloaded vectors for ${category}:`, {
|
|
134
|
-
// total: categoryVectors.length,
|
|
135
|
-
// sample: categoryVectors.slice(0, 3).map(v => v.name)
|
|
136
|
-
// });
|
|
137
|
-
}));
|
|
138
|
-
// Save filtered list to localStorage cache
|
|
127
|
+
});
|
|
128
|
+
// Clean up legacy cache and mark loaded
|
|
139
129
|
this.saveVectorListToCache(this.cachedVectorList);
|
|
140
130
|
this.allVectorsLoaded = true;
|
|
141
|
-
// console.log('📚 [VectorManager] Complete vector list cached:', {
|
|
142
|
-
// total: this.cachedVectorList.length,
|
|
143
|
-
// categoriesPreloaded: Array.from(this.categoryVectors.keys())
|
|
144
|
-
// });
|
|
145
131
|
}
|
|
146
132
|
catch (error) {
|
|
147
|
-
console.error('❌ [VectorManager] Error
|
|
133
|
+
console.error('❌ [VectorManager] Error indexing vector list:', error);
|
|
148
134
|
}
|
|
149
135
|
// Only set initialized after everything is complete
|
|
150
136
|
VectorManager.isInitialized = true;
|
|
@@ -292,11 +278,8 @@ class VectorManager {
|
|
|
292
278
|
}));
|
|
293
279
|
// Add custom vectors from custom-svgs.json
|
|
294
280
|
const customVectors = await this.loadCustomVectors();
|
|
295
|
-
// Load vectors from svgs.json
|
|
296
|
-
const
|
|
297
|
-
if (!response.ok)
|
|
298
|
-
throw new Error('Failed to fetch vectors');
|
|
299
|
-
const data = await response.json();
|
|
281
|
+
// Load vectors from svgs.json using deduplicated fetch promise
|
|
282
|
+
const data = await VectorManager.fetchSvgsJson();
|
|
300
283
|
// Process and combine vectors
|
|
301
284
|
const standardVectors = data.svgGroups.flatMap((group) => group.items.map((item) => ({
|
|
302
285
|
name: item.name,
|
|
@@ -320,22 +303,15 @@ class VectorManager {
|
|
|
320
303
|
}
|
|
321
304
|
}
|
|
322
305
|
/**
|
|
323
|
-
* Saves vector list to localStorage
|
|
306
|
+
* Saves vector list to cache (avoids writing 1.2MB JSON to localStorage)
|
|
324
307
|
*/
|
|
325
308
|
saveVectorListToCache(vectors) {
|
|
326
309
|
try {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
vectors: vectors
|
|
330
|
-
};
|
|
331
|
-
localStorage.setItem(VectorManager.CACHE_KEY, JSON.stringify(cacheData));
|
|
332
|
-
// console.log('💾 [VectorManager] Vector list cached:', {
|
|
333
|
-
// vectors: vectors.length,
|
|
334
|
-
// expires: new Date(cacheData.timestamp + VectorManager.CACHE_DURATION)
|
|
335
|
-
// });
|
|
310
|
+
// Remove legacy large JSON from localStorage if present to free storage quota
|
|
311
|
+
localStorage.removeItem(VectorManager.CACHE_KEY);
|
|
336
312
|
}
|
|
337
313
|
catch (error) {
|
|
338
|
-
|
|
314
|
+
// Ignore storage errors
|
|
339
315
|
}
|
|
340
316
|
}
|
|
341
317
|
/**
|
|
@@ -672,7 +648,7 @@ class VectorManager {
|
|
|
672
648
|
return this.observers.get(key) || null;
|
|
673
649
|
}
|
|
674
650
|
// Create new observer
|
|
675
|
-
console.log('🔧 [VectorManager] Creating new observer for container:', key);
|
|
651
|
+
// console.log('🔧 [VectorManager] Creating new observer for container:', key);
|
|
676
652
|
const observer = new IntersectionObserver((entries) => {
|
|
677
653
|
entries.forEach(entry => {
|
|
678
654
|
const vectorName = entry.target.getAttribute('data-vector');
|
|
@@ -732,23 +708,7 @@ class VectorManager {
|
|
|
732
708
|
* Returns null if cache is invalid or expired
|
|
733
709
|
*/
|
|
734
710
|
getVectorListFromCache() {
|
|
735
|
-
|
|
736
|
-
const cached = localStorage.getItem(VectorManager.CACHE_KEY);
|
|
737
|
-
if (!cached)
|
|
738
|
-
return null;
|
|
739
|
-
const cache = JSON.parse(cached);
|
|
740
|
-
const now = Date.now();
|
|
741
|
-
// Check if cache has expired
|
|
742
|
-
if (now - cache.timestamp > VectorManager.CACHE_DURATION) {
|
|
743
|
-
console.log('📅 [VectorManager] Cache expired, will refresh');
|
|
744
|
-
return null;
|
|
745
|
-
}
|
|
746
|
-
return cache.vectors;
|
|
747
|
-
}
|
|
748
|
-
catch (error) {
|
|
749
|
-
console.error('❌ [VectorManager] Error reading vector cache:', error);
|
|
750
|
-
return null;
|
|
751
|
-
}
|
|
711
|
+
return null;
|
|
752
712
|
}
|
|
753
713
|
}
|
|
754
714
|
export default VectorManager;
|
|
@@ -12,7 +12,7 @@ export class ColorTransparencyHandler {
|
|
|
12
12
|
* Converts hex color to RGBA while preserving opacity
|
|
13
13
|
*/
|
|
14
14
|
hexToRgba(hex) {
|
|
15
|
-
console.log('Converting hex to rgba:', hex, 'Current opacity:', this.persistentOpacity);
|
|
15
|
+
// console.log('Converting hex to rgba:', hex, 'Current opacity:', this.persistentOpacity);
|
|
16
16
|
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i.exec(hex);
|
|
17
17
|
if (result) {
|
|
18
18
|
return {
|
|
@@ -57,7 +57,7 @@ export class ColorTransparencyHandler {
|
|
|
57
57
|
finally {
|
|
58
58
|
this.isInternalUpdate = false;
|
|
59
59
|
}
|
|
60
|
-
console.log('Updated opacity:', newOpacity);
|
|
60
|
+
// console.log('Updated opacity:', newOpacity);
|
|
61
61
|
}
|
|
62
62
|
/**
|
|
63
63
|
* Updates opacity from input value
|
|
@@ -75,7 +75,7 @@ export class ColorTransparencyHandler {
|
|
|
75
75
|
finally {
|
|
76
76
|
this.isInternalUpdate = false;
|
|
77
77
|
}
|
|
78
|
-
console.log('Updated opacity from input:', value);
|
|
78
|
+
// console.log('Updated opacity from input:', value);
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
81
81
|
* Gets the current opacity percentage
|
package/dist/utils/fontUtils.js
CHANGED
|
@@ -15,7 +15,7 @@ export const fontCategories = {
|
|
|
15
15
|
normalize(category) {
|
|
16
16
|
// Handle null or undefined category
|
|
17
17
|
if (!category) {
|
|
18
|
-
console.log('⚠️ [FontUtils] Null category, returning Other');
|
|
18
|
+
// console.log('⚠️ [FontUtils] Null category, returning Other');
|
|
19
19
|
return 'Other';
|
|
20
20
|
}
|
|
21
21
|
// Convert to lowercase and trim for consistent matching
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Passive event listener helper.
|
|
3
|
+
* Apply specifically to scroll-listening elements that do not call preventDefault().
|
|
4
|
+
*/
|
|
5
|
+
export declare function addPassiveEventListener<K extends keyof WindowEventMap>(target: EventTarget, type: K, listener: (this: EventTarget, ev: WindowEventMap[K]) => any, options?: boolean | AddEventListenerOptions): () => void;
|
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
if (typeof options === 'object') {
|
|
11
|
-
newOptions = { ...options, passive: true };
|
|
12
|
-
}
|
|
13
|
-
else {
|
|
14
|
-
newOptions = { passive: true };
|
|
15
|
-
}
|
|
16
|
-
return originalAddEventListener.call(this, type, listener, newOptions);
|
|
17
|
-
}
|
|
18
|
-
return originalAddEventListener.call(this, type, listener, options);
|
|
1
|
+
/**
|
|
2
|
+
* Passive event listener helper.
|
|
3
|
+
* Apply specifically to scroll-listening elements that do not call preventDefault().
|
|
4
|
+
*/
|
|
5
|
+
export function addPassiveEventListener(target, type, listener, options) {
|
|
6
|
+
const opts = typeof options === 'object' ? { ...options, passive: true } : { passive: true };
|
|
7
|
+
target.addEventListener(type, listener, opts);
|
|
8
|
+
return () => {
|
|
9
|
+
target.removeEventListener(type, listener, opts);
|
|
19
10
|
};
|
|
20
11
|
}
|
|
@@ -14,31 +14,31 @@ export const recentColorsUtil = {
|
|
|
14
14
|
addRecentColor(color, alpha) {
|
|
15
15
|
try {
|
|
16
16
|
const normalizedColor = color.toLowerCase();
|
|
17
|
-
console.log('Adding/updating recent color:', {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
});
|
|
17
|
+
// console.log('Adding/updating recent color:', {
|
|
18
|
+
// normalizedColor,
|
|
19
|
+
// alpha,
|
|
20
|
+
// originalColor: color
|
|
21
|
+
// });
|
|
22
22
|
let colors = this.getRecentColors();
|
|
23
23
|
// Normalize all colors for comparison
|
|
24
24
|
const existingIndex = colors.findIndex(c => {
|
|
25
25
|
const normalizedExisting = c.color.toLowerCase();
|
|
26
26
|
const alphaMatch = Math.abs(c.alpha - alpha) < 0.001;
|
|
27
|
-
console.log('Comparing:', {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
});
|
|
27
|
+
// console.log('Comparing:', {
|
|
28
|
+
// existing: normalizedExisting,
|
|
29
|
+
// new: normalizedColor,
|
|
30
|
+
// existingAlpha: c.alpha,
|
|
31
|
+
// newAlpha: alpha,
|
|
32
|
+
// alphaMatch,
|
|
33
|
+
// colorsMatch: normalizedExisting === normalizedColor
|
|
34
|
+
// });
|
|
35
35
|
return normalizedExisting === normalizedColor && alphaMatch;
|
|
36
36
|
});
|
|
37
|
-
console.log('Found existing color at index:', existingIndex);
|
|
37
|
+
// console.log('Found existing color at index:', existingIndex);
|
|
38
38
|
if (existingIndex !== -1) {
|
|
39
39
|
// Remove the existing color
|
|
40
40
|
const removed = colors.splice(existingIndex, 1)[0];
|
|
41
|
-
console.log('Removed existing color:', removed);
|
|
41
|
+
// console.log('Removed existing color:', removed);
|
|
42
42
|
}
|
|
43
43
|
// Add the new/updated color to the front
|
|
44
44
|
const newColor = {
|
|
@@ -10,7 +10,7 @@ export const vectorCategories = {
|
|
|
10
10
|
normalize(category) {
|
|
11
11
|
// Handle null or undefined category
|
|
12
12
|
if (!category) {
|
|
13
|
-
console.log('⚠️ [VectorUtils] Null category, returning Icons');
|
|
13
|
+
// console.log('⚠️ [VectorUtils] Null category, returning Icons');
|
|
14
14
|
return 'Icons';
|
|
15
15
|
}
|
|
16
16
|
// Convert to lowercase and trim for consistent matching
|