@liiift-studio/sanity-font-manager 2.3.18 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +437 -437
- package/dist/index.js +103 -48
- package/dist/index.mjs +103 -48
- package/package.json +85 -85
- package/src/components/BatchUploadFonts.jsx +640 -639
- package/src/components/FontScriptUploaderComponent.jsx +463 -463
- package/src/components/GenerateCollectionsPairsComponent.jsx +259 -259
- package/src/components/KeyValueInput.jsx +95 -95
- package/src/components/KeyValueReferenceInput.jsx +254 -254
- package/src/components/NestedObjectArraySelector.jsx +146 -146
- package/src/components/PriceInput.jsx +26 -26
- package/src/components/PrimaryCollectionGeneratorTypeface.jsx +116 -116
- package/src/components/RegenerateSubfamiliesComponent.jsx +185 -185
- package/src/components/SetOTF.jsx +87 -87
- package/src/components/SingleUploaderTool.jsx +673 -673
- package/src/components/StatusDisplay.jsx +26 -26
- package/src/components/StyleCountInput.jsx +16 -16
- package/src/components/UpdateScriptsComponent.jsx +76 -76
- package/src/components/UploadButton.jsx +43 -43
- package/src/components/UploadScriptsComponent.jsx +537 -537
- package/src/components/VariableInstanceReferencesInput.jsx +190 -190
- package/src/hooks/useNestedObjects.js +92 -92
- package/src/hooks/useSanityClient.js +9 -9
- package/src/index.js +70 -70
- package/src/schema/openTypeField.js +1945 -1945
- package/src/schema/styleCountField.js +12 -12
- package/src/schema/stylesField.js +268 -268
- package/src/schema/stylisticSetField.js +301 -301
- package/src/utils/generateCssFile.js +205 -205
- package/src/utils/generateFontData.js +145 -145
- package/src/utils/generateFontFile.js +38 -38
- package/src/utils/generateKeywords.js +185 -185
- package/src/utils/generateSubset.js +45 -45
- package/src/utils/getEmptyFontKit.js +99 -99
- package/src/utils/parseVariableFontInstances.js +211 -211
- package/src/utils/processFontFiles.js +487 -477
- package/src/utils/regenerateFontData.js +146 -146
- package/src/utils/sanitizeForSanityId.js +65 -65
- package/src/utils/updateFontPrices.js +94 -94
- package/src/utils/updateTypefaceDocument.js +149 -160
- package/src/utils/uploadFontFiles.js +115 -26
- package/src/utils/utils.js +24 -24
|
@@ -1,211 +1,211 @@
|
|
|
1
|
-
// Resolves named variable font instances into Sanity font document references, creating documents for missing instances
|
|
2
|
-
|
|
3
|
-
import { nanoid } from 'nanoid';
|
|
4
|
-
import { expandAbbreviations } from './generateKeywords';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Parses a variable font's named instances and maps each to its corresponding static font document.
|
|
8
|
-
* Uses 6 matching strategies in priority order:
|
|
9
|
-
* 1. Exact title match
|
|
10
|
-
* 2. Title normalisation (strips VF/var/variable prefixes, handles Regular/Italic suffixes)
|
|
11
|
-
* 3. Abbreviation expansion
|
|
12
|
-
* 4. Weight + style matching
|
|
13
|
-
* 5. weightName comparison
|
|
14
|
-
* 6. metaData.fullName fallback
|
|
15
|
-
*
|
|
16
|
-
* @param {Object} font - The variable font object (must have typefaceName and variableInstances)
|
|
17
|
-
* @param {Object} client - Sanity client (parameterized queries only)
|
|
18
|
-
* @returns {Promise<Array>} Array of { key, value, _key } instance mappings
|
|
19
|
-
*/
|
|
20
|
-
export const parseVariableFontInstances = async (font, client) => {
|
|
21
|
-
if (!font.variableFont || !font.variableInstances) return [];
|
|
22
|
-
|
|
23
|
-
let variableInstances;
|
|
24
|
-
try {
|
|
25
|
-
variableInstances = JSON.parse(font.variableInstances);
|
|
26
|
-
} catch (err) {
|
|
27
|
-
console.error('Error parsing variable instances:', err);
|
|
28
|
-
variableInstances = {};
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (Object.keys(variableInstances).length === 0) return [];
|
|
32
|
-
|
|
33
|
-
// Fetch the typeface's curated font list (parameterized — no injection risk)
|
|
34
|
-
let staticFonts;
|
|
35
|
-
const typeface = await client.fetch(
|
|
36
|
-
`*[_type == 'typeface' && title == $typefaceName][0]{
|
|
37
|
-
'fonts': styles.fonts[]-> {
|
|
38
|
-
_id,
|
|
39
|
-
title,
|
|
40
|
-
subfamily,
|
|
41
|
-
style,
|
|
42
|
-
weight,
|
|
43
|
-
weightName,
|
|
44
|
-
metaData,
|
|
45
|
-
variableFont
|
|
46
|
-
}
|
|
47
|
-
}`,
|
|
48
|
-
{ typefaceName: font.typefaceName }
|
|
49
|
-
);
|
|
50
|
-
|
|
51
|
-
if (typeface?.fonts && typeface.fonts.length > 0) {
|
|
52
|
-
staticFonts = typeface.fonts.filter(f => !f.variableFont);
|
|
53
|
-
console.log('Using curated typeface fonts list:', staticFonts.length, 'fonts');
|
|
54
|
-
} else {
|
|
55
|
-
console.warn('Typeface not found or no fonts in curated list, falling back to all fonts query');
|
|
56
|
-
staticFonts = await client.fetch(
|
|
57
|
-
`*[_type == 'font' && typefaceName == $typefaceName && variableFont != true]{
|
|
58
|
-
_id,
|
|
59
|
-
title,
|
|
60
|
-
subfamily,
|
|
61
|
-
style,
|
|
62
|
-
weight,
|
|
63
|
-
weightName,
|
|
64
|
-
metaData
|
|
65
|
-
}`,
|
|
66
|
-
{ typefaceName: font.typefaceName }
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
console.log('Variable font instances:', Object.keys(variableInstances));
|
|
71
|
-
console.log('Available static fonts:', staticFonts.map(sf => sf.title));
|
|
72
|
-
|
|
73
|
-
const instanceMappings = [];
|
|
74
|
-
|
|
75
|
-
Object.keys(variableInstances).forEach(instanceName => {
|
|
76
|
-
let matchingFont = null;
|
|
77
|
-
|
|
78
|
-
// Strategy 1: Exact title match
|
|
79
|
-
matchingFont = staticFonts.find(sf => sf.title === instanceName);
|
|
80
|
-
|
|
81
|
-
// Strategy 2: Title normalisation — strip VF/var/variable prefix words, handle Regular/Italic
|
|
82
|
-
if (!matchingFont && staticFonts.some(sf => sf.metaData?.fullName)) {
|
|
83
|
-
matchingFont = staticFonts.find(sf => {
|
|
84
|
-
if (!sf.metaData?.fullName) return false;
|
|
85
|
-
|
|
86
|
-
let fullName = sf.metaData.fullName;
|
|
87
|
-
|
|
88
|
-
const WORDS_TO_REMOVE = ['VF', 'var', 'variable', 'VAR', 'vf'];
|
|
89
|
-
const variableName = font.metaData?.familyName
|
|
90
|
-
?.replace(new RegExp(`\\b(${WORDS_TO_REMOVE.join('|')})\\b`, 'gi'), '')
|
|
91
|
-
.replace(/\s{2,}/g, ' ')
|
|
92
|
-
.trim();
|
|
93
|
-
|
|
94
|
-
if (variableName && fullName.startsWith(variableName)) {
|
|
95
|
-
fullName = fullName.substring(variableName.length).trim();
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (variableName) {
|
|
99
|
-
const words = variableName.split(/\s+/).map(w => w.trim()).filter(Boolean);
|
|
100
|
-
if (words.length > 0) {
|
|
101
|
-
const regex = new RegExp(`\\b(${words.join('|')})\\b`, 'gi');
|
|
102
|
-
const stripped = fullName.replace(regex, '').replace(/\s{2,}/g, ' ').trim();
|
|
103
|
-
if (stripped !== '') fullName = stripped;
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (fullName.startsWith(font.typefaceName)) {
|
|
108
|
-
fullName = fullName.substring(font.typefaceName.length).trim();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (sf.style?.toLowerCase() === 'italic' &&
|
|
112
|
-
!fullName.toLowerCase().endsWith('italic') &&
|
|
113
|
-
!fullName.toLowerCase().endsWith('slanted')) {
|
|
114
|
-
fullName = fullName + ' Italic';
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (fullName.trim().toLowerCase().endsWith('regular')) {
|
|
118
|
-
if (instanceName.trim().toLowerCase() + ' regular' === fullName.trim().toLowerCase()) return true;
|
|
119
|
-
}
|
|
120
|
-
if (fullName.trim().toLowerCase().startsWith('regular')) {
|
|
121
|
-
if ('regular ' + instanceName.trim().toLowerCase() === fullName.trim().toLowerCase()) return true;
|
|
122
|
-
}
|
|
123
|
-
if (fullName.trim().toLowerCase().endsWith('italic')) {
|
|
124
|
-
if (instanceName.trim().toLowerCase().endsWith('italic')) {
|
|
125
|
-
const k = instanceName.trim().toLowerCase().slice(0, -6).trim() + ' regular italic';
|
|
126
|
-
if (k === fullName.trim().toLowerCase()) return true;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
return fullName.trim().toLowerCase() === instanceName.trim().toLowerCase();
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// Strategy 3: Abbreviation expansion
|
|
135
|
-
if (!matchingFont) {
|
|
136
|
-
const expandedName = instanceName.split(' ').map(word => expandAbbreviations(word)).join(' ');
|
|
137
|
-
matchingFont = staticFonts.find(sf => {
|
|
138
|
-
const nameWithoutTypeface = sf.title.replace(font.typefaceName, '').trim();
|
|
139
|
-
return nameWithoutTypeface === expandedName;
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Strategy 4: Weight + style matching
|
|
144
|
-
if (!matchingFont) {
|
|
145
|
-
const isItalic = instanceName.toLowerCase().includes('italic');
|
|
146
|
-
const weightTerms = [
|
|
147
|
-
{ term: 'thin', weight: '100' },
|
|
148
|
-
{ term: 'extralight', weight: '200' },
|
|
149
|
-
{ term: 'extra light', weight: '200' },
|
|
150
|
-
{ term: 'light', weight: '300' },
|
|
151
|
-
{ term: 'regular', weight: '400' },
|
|
152
|
-
{ term: 'normal', weight: '400' },
|
|
153
|
-
{ term: 'medium', weight: '500' },
|
|
154
|
-
{ term: 'semibold', weight: '600' },
|
|
155
|
-
{ term: 'semi bold', weight: '600' },
|
|
156
|
-
{ term: 'bold', weight: '700' },
|
|
157
|
-
{ term: 'extrabold', weight: '800' },
|
|
158
|
-
{ term: 'extra bold', weight: '800' },
|
|
159
|
-
{ term: 'black', weight: '900' },
|
|
160
|
-
{ term: 'heavy', weight: '900' },
|
|
161
|
-
];
|
|
162
|
-
|
|
163
|
-
let instanceWeight = '400';
|
|
164
|
-
for (const { term, weight } of weightTerms) {
|
|
165
|
-
if (instanceName.toLowerCase().includes(term)) {
|
|
166
|
-
instanceWeight = weight;
|
|
167
|
-
break;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
matchingFont = staticFonts.find(sf =>
|
|
172
|
-
sf.weight === instanceWeight &&
|
|
173
|
-
((isItalic && sf.style === 'Italic') || (!isItalic && sf.style === 'Regular'))
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// Strategy 5: weightName comparison
|
|
178
|
-
if (!matchingFont) {
|
|
179
|
-
matchingFont = staticFonts.find(sf => {
|
|
180
|
-
if (!sf.weightName) return false;
|
|
181
|
-
const cleanInstance = instanceName.toLowerCase().replace(/italic/i, '').trim();
|
|
182
|
-
const cleanWeight = sf.weightName.toLowerCase().replace(/italic/i, '').trim();
|
|
183
|
-
return cleanInstance === cleanWeight;
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
// Strategy 6: Legacy metaData.fullName fallback
|
|
188
|
-
if (!matchingFont && staticFonts.some(sf => sf.metaData?.fullName)) {
|
|
189
|
-
matchingFont = staticFonts.find(sf => {
|
|
190
|
-
if (!sf.metaData?.fullName) return false;
|
|
191
|
-
const typefacePattern = new RegExp(`^${font.typefaceName}\\s+`, 'i');
|
|
192
|
-
const stylePart = sf.metaData.fullName.replace(typefacePattern, '').trim();
|
|
193
|
-
return instanceName.toLowerCase() === stylePart.toLowerCase();
|
|
194
|
-
});
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
console.log(`Instance "${instanceName}" matched with:`, matchingFont ? matchingFont.title : 'No match found');
|
|
198
|
-
|
|
199
|
-
instanceMappings.push({
|
|
200
|
-
key: instanceName,
|
|
201
|
-
value: matchingFont
|
|
202
|
-
? { _type: 'reference', _ref: matchingFont._id, _weak: true }
|
|
203
|
-
: null,
|
|
204
|
-
_key: nanoid(),
|
|
205
|
-
});
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
return instanceMappings;
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
export default parseVariableFontInstances;
|
|
1
|
+
// Resolves named variable font instances into Sanity font document references, creating documents for missing instances
|
|
2
|
+
|
|
3
|
+
import { nanoid } from 'nanoid';
|
|
4
|
+
import { expandAbbreviations } from './generateKeywords';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Parses a variable font's named instances and maps each to its corresponding static font document.
|
|
8
|
+
* Uses 6 matching strategies in priority order:
|
|
9
|
+
* 1. Exact title match
|
|
10
|
+
* 2. Title normalisation (strips VF/var/variable prefixes, handles Regular/Italic suffixes)
|
|
11
|
+
* 3. Abbreviation expansion
|
|
12
|
+
* 4. Weight + style matching
|
|
13
|
+
* 5. weightName comparison
|
|
14
|
+
* 6. metaData.fullName fallback
|
|
15
|
+
*
|
|
16
|
+
* @param {Object} font - The variable font object (must have typefaceName and variableInstances)
|
|
17
|
+
* @param {Object} client - Sanity client (parameterized queries only)
|
|
18
|
+
* @returns {Promise<Array>} Array of { key, value, _key } instance mappings
|
|
19
|
+
*/
|
|
20
|
+
export const parseVariableFontInstances = async (font, client) => {
|
|
21
|
+
if (!font.variableFont || !font.variableInstances) return [];
|
|
22
|
+
|
|
23
|
+
let variableInstances;
|
|
24
|
+
try {
|
|
25
|
+
variableInstances = JSON.parse(font.variableInstances);
|
|
26
|
+
} catch (err) {
|
|
27
|
+
console.error('Error parsing variable instances:', err);
|
|
28
|
+
variableInstances = {};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (Object.keys(variableInstances).length === 0) return [];
|
|
32
|
+
|
|
33
|
+
// Fetch the typeface's curated font list (parameterized — no injection risk)
|
|
34
|
+
let staticFonts;
|
|
35
|
+
const typeface = await client.fetch(
|
|
36
|
+
`*[_type == 'typeface' && title == $typefaceName][0]{
|
|
37
|
+
'fonts': styles.fonts[]-> {
|
|
38
|
+
_id,
|
|
39
|
+
title,
|
|
40
|
+
subfamily,
|
|
41
|
+
style,
|
|
42
|
+
weight,
|
|
43
|
+
weightName,
|
|
44
|
+
metaData,
|
|
45
|
+
variableFont
|
|
46
|
+
}
|
|
47
|
+
}`,
|
|
48
|
+
{ typefaceName: font.typefaceName }
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
if (typeface?.fonts && typeface.fonts.length > 0) {
|
|
52
|
+
staticFonts = typeface.fonts.filter(f => !f.variableFont);
|
|
53
|
+
console.log('Using curated typeface fonts list:', staticFonts.length, 'fonts');
|
|
54
|
+
} else {
|
|
55
|
+
console.warn('Typeface not found or no fonts in curated list, falling back to all fonts query');
|
|
56
|
+
staticFonts = await client.fetch(
|
|
57
|
+
`*[_type == 'font' && typefaceName == $typefaceName && variableFont != true]{
|
|
58
|
+
_id,
|
|
59
|
+
title,
|
|
60
|
+
subfamily,
|
|
61
|
+
style,
|
|
62
|
+
weight,
|
|
63
|
+
weightName,
|
|
64
|
+
metaData
|
|
65
|
+
}`,
|
|
66
|
+
{ typefaceName: font.typefaceName }
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log('Variable font instances:', Object.keys(variableInstances));
|
|
71
|
+
console.log('Available static fonts:', staticFonts.map(sf => sf.title));
|
|
72
|
+
|
|
73
|
+
const instanceMappings = [];
|
|
74
|
+
|
|
75
|
+
Object.keys(variableInstances).forEach(instanceName => {
|
|
76
|
+
let matchingFont = null;
|
|
77
|
+
|
|
78
|
+
// Strategy 1: Exact title match
|
|
79
|
+
matchingFont = staticFonts.find(sf => sf.title === instanceName);
|
|
80
|
+
|
|
81
|
+
// Strategy 2: Title normalisation — strip VF/var/variable prefix words, handle Regular/Italic
|
|
82
|
+
if (!matchingFont && staticFonts.some(sf => sf.metaData?.fullName)) {
|
|
83
|
+
matchingFont = staticFonts.find(sf => {
|
|
84
|
+
if (!sf.metaData?.fullName) return false;
|
|
85
|
+
|
|
86
|
+
let fullName = sf.metaData.fullName;
|
|
87
|
+
|
|
88
|
+
const WORDS_TO_REMOVE = ['VF', 'var', 'variable', 'VAR', 'vf'];
|
|
89
|
+
const variableName = font.metaData?.familyName
|
|
90
|
+
?.replace(new RegExp(`\\b(${WORDS_TO_REMOVE.join('|')})\\b`, 'gi'), '')
|
|
91
|
+
.replace(/\s{2,}/g, ' ')
|
|
92
|
+
.trim();
|
|
93
|
+
|
|
94
|
+
if (variableName && fullName.startsWith(variableName)) {
|
|
95
|
+
fullName = fullName.substring(variableName.length).trim();
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (variableName) {
|
|
99
|
+
const words = variableName.split(/\s+/).map(w => w.trim()).filter(Boolean);
|
|
100
|
+
if (words.length > 0) {
|
|
101
|
+
const regex = new RegExp(`\\b(${words.join('|')})\\b`, 'gi');
|
|
102
|
+
const stripped = fullName.replace(regex, '').replace(/\s{2,}/g, ' ').trim();
|
|
103
|
+
if (stripped !== '') fullName = stripped;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (fullName.startsWith(font.typefaceName)) {
|
|
108
|
+
fullName = fullName.substring(font.typefaceName.length).trim();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (sf.style?.toLowerCase() === 'italic' &&
|
|
112
|
+
!fullName.toLowerCase().endsWith('italic') &&
|
|
113
|
+
!fullName.toLowerCase().endsWith('slanted')) {
|
|
114
|
+
fullName = fullName + ' Italic';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (fullName.trim().toLowerCase().endsWith('regular')) {
|
|
118
|
+
if (instanceName.trim().toLowerCase() + ' regular' === fullName.trim().toLowerCase()) return true;
|
|
119
|
+
}
|
|
120
|
+
if (fullName.trim().toLowerCase().startsWith('regular')) {
|
|
121
|
+
if ('regular ' + instanceName.trim().toLowerCase() === fullName.trim().toLowerCase()) return true;
|
|
122
|
+
}
|
|
123
|
+
if (fullName.trim().toLowerCase().endsWith('italic')) {
|
|
124
|
+
if (instanceName.trim().toLowerCase().endsWith('italic')) {
|
|
125
|
+
const k = instanceName.trim().toLowerCase().slice(0, -6).trim() + ' regular italic';
|
|
126
|
+
if (k === fullName.trim().toLowerCase()) return true;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return fullName.trim().toLowerCase() === instanceName.trim().toLowerCase();
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Strategy 3: Abbreviation expansion
|
|
135
|
+
if (!matchingFont) {
|
|
136
|
+
const expandedName = instanceName.split(' ').map(word => expandAbbreviations(word)).join(' ');
|
|
137
|
+
matchingFont = staticFonts.find(sf => {
|
|
138
|
+
const nameWithoutTypeface = sf.title.replace(font.typefaceName, '').trim();
|
|
139
|
+
return nameWithoutTypeface === expandedName;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Strategy 4: Weight + style matching
|
|
144
|
+
if (!matchingFont) {
|
|
145
|
+
const isItalic = instanceName.toLowerCase().includes('italic');
|
|
146
|
+
const weightTerms = [
|
|
147
|
+
{ term: 'thin', weight: '100' },
|
|
148
|
+
{ term: 'extralight', weight: '200' },
|
|
149
|
+
{ term: 'extra light', weight: '200' },
|
|
150
|
+
{ term: 'light', weight: '300' },
|
|
151
|
+
{ term: 'regular', weight: '400' },
|
|
152
|
+
{ term: 'normal', weight: '400' },
|
|
153
|
+
{ term: 'medium', weight: '500' },
|
|
154
|
+
{ term: 'semibold', weight: '600' },
|
|
155
|
+
{ term: 'semi bold', weight: '600' },
|
|
156
|
+
{ term: 'bold', weight: '700' },
|
|
157
|
+
{ term: 'extrabold', weight: '800' },
|
|
158
|
+
{ term: 'extra bold', weight: '800' },
|
|
159
|
+
{ term: 'black', weight: '900' },
|
|
160
|
+
{ term: 'heavy', weight: '900' },
|
|
161
|
+
];
|
|
162
|
+
|
|
163
|
+
let instanceWeight = '400';
|
|
164
|
+
for (const { term, weight } of weightTerms) {
|
|
165
|
+
if (instanceName.toLowerCase().includes(term)) {
|
|
166
|
+
instanceWeight = weight;
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
matchingFont = staticFonts.find(sf =>
|
|
172
|
+
sf.weight === instanceWeight &&
|
|
173
|
+
((isItalic && sf.style === 'Italic') || (!isItalic && sf.style === 'Regular'))
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Strategy 5: weightName comparison
|
|
178
|
+
if (!matchingFont) {
|
|
179
|
+
matchingFont = staticFonts.find(sf => {
|
|
180
|
+
if (!sf.weightName) return false;
|
|
181
|
+
const cleanInstance = instanceName.toLowerCase().replace(/italic/i, '').trim();
|
|
182
|
+
const cleanWeight = sf.weightName.toLowerCase().replace(/italic/i, '').trim();
|
|
183
|
+
return cleanInstance === cleanWeight;
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Strategy 6: Legacy metaData.fullName fallback
|
|
188
|
+
if (!matchingFont && staticFonts.some(sf => sf.metaData?.fullName)) {
|
|
189
|
+
matchingFont = staticFonts.find(sf => {
|
|
190
|
+
if (!sf.metaData?.fullName) return false;
|
|
191
|
+
const typefacePattern = new RegExp(`^${font.typefaceName}\\s+`, 'i');
|
|
192
|
+
const stylePart = sf.metaData.fullName.replace(typefacePattern, '').trim();
|
|
193
|
+
return instanceName.toLowerCase() === stylePart.toLowerCase();
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
console.log(`Instance "${instanceName}" matched with:`, matchingFont ? matchingFont.title : 'No match found');
|
|
198
|
+
|
|
199
|
+
instanceMappings.push({
|
|
200
|
+
key: instanceName,
|
|
201
|
+
value: matchingFont
|
|
202
|
+
? { _type: 'reference', _ref: matchingFont._id, _weak: true }
|
|
203
|
+
: null,
|
|
204
|
+
_key: nanoid(),
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return instanceMappings;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
export default parseVariableFontInstances;
|