@liiift-studio/sanity-font-manager 2.3.19 → 2.5.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/UploadModal-6LIX7XOK.js +6 -0
- package/dist/UploadModal-NME2W53V.mjs +6 -0
- package/dist/chunk-646WCBRR.mjs +7276 -0
- package/dist/chunk-FH4QKHOH.js +7276 -0
- package/dist/index.js +747 -1675
- package/dist/index.mjs +400 -1237
- package/package.json +85 -85
- package/src/components/BatchUploadFonts.jsx +653 -639
- package/src/components/BulkActions.jsx +99 -0
- package/src/components/ExistingDocumentResolver.jsx +152 -0
- package/src/components/FontReviewCard.jsx +415 -0
- 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 +672 -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/UploadModal.jsx +268 -0
- package/src/components/UploadScriptsComponent.jsx +539 -537
- package/src/components/UploadStep1Settings.jsx +272 -0
- package/src/components/UploadStep2Review.jsx +472 -0
- package/src/components/UploadStep3Execute.jsx +234 -0
- package/src/components/UploadSummary.jsx +196 -0
- 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 +115 -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/buildUploadPlan.js +325 -0
- package/src/utils/executeUploadPlan.js +437 -0
- package/src/utils/executionReducer.js +56 -0
- package/src/utils/fontHelpers.js +267 -0
- package/src/utils/generateCssFile.js +207 -205
- package/src/utils/generateFontData.js +98 -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 +101 -99
- package/src/utils/parseFont.js +55 -0
- package/src/utils/parseVariableFontInstances.js +211 -211
- package/src/utils/planReducer.js +517 -0
- package/src/utils/planTypes.js +183 -0
- package/src/utils/processFontFiles.js +529 -477
- package/src/utils/regenerateFontData.js +146 -146
- package/src/utils/resolveExistingFont.js +87 -0
- 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 +405 -316
- package/src/utils/utils.js +24 -24
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
// Sanity schema field definition for displaying the total style count — uses StyleCountInput component
|
|
2
|
-
import { StyleCountInput } from '../components/StyleCountInput.jsx';
|
|
3
|
-
|
|
4
|
-
export const styleCountField = {
|
|
5
|
-
name: 'styleCount',
|
|
6
|
-
type: 'number',
|
|
7
|
-
group: 'styles',
|
|
8
|
-
components: {
|
|
9
|
-
input: StyleCountInput,
|
|
10
|
-
},
|
|
11
|
-
readOnly: true,
|
|
12
|
-
};
|
|
1
|
+
// Sanity schema field definition for displaying the total style count — uses StyleCountInput component
|
|
2
|
+
import { StyleCountInput } from '../components/StyleCountInput.jsx';
|
|
3
|
+
|
|
4
|
+
export const styleCountField = {
|
|
5
|
+
name: 'styleCount',
|
|
6
|
+
type: 'number',
|
|
7
|
+
group: 'styles',
|
|
8
|
+
components: {
|
|
9
|
+
input: StyleCountInput,
|
|
10
|
+
},
|
|
11
|
+
readOnly: true,
|
|
12
|
+
};
|
|
@@ -1,268 +1,268 @@
|
|
|
1
|
-
// Sanity schema factory function for the Styles object field — call createStylesField(options) to generate the field definition for a typeface document
|
|
2
|
-
import React from 'react';
|
|
3
|
-
import { AdvancedRefArray } from '@liiift-studio/sanity-advanced-reference-array';
|
|
4
|
-
import { RegenerateSubfamiliesComponent } from '../components/RegenerateSubfamiliesComponent.jsx';
|
|
5
|
-
|
|
6
|
-
// Returns extra GROQ params scoped to the current typeface document
|
|
7
|
-
const typefaceParams = (doc) => ({ typefaceName: doc?.title || '' });
|
|
8
|
-
|
|
9
|
-
// AdvancedRefArray wrapper — limits search results to fonts belonging to this typeface
|
|
10
|
-
const FontsRefArray = (props) => React.createElement(AdvancedRefArray, {
|
|
11
|
-
...props,
|
|
12
|
-
filterGroq: 'lower(typefaceName) == lower($typefaceName)',
|
|
13
|
-
filterParams: typefaceParams,
|
|
14
|
-
});
|
|
15
|
-
|
|
16
|
-
// AdvancedRefArray wrapper — limits search results to variable fonts belonging to this typeface
|
|
17
|
-
const VariableFontsRefArray = (props) => React.createElement(AdvancedRefArray, {
|
|
18
|
-
...props,
|
|
19
|
-
filterGroq: 'lower(typefaceName) == lower($typefaceName) && variableFont == true',
|
|
20
|
-
filterParams: typefaceParams,
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
// Conditionally includes a field definition in an array
|
|
24
|
-
const field = (condition, def) => condition ? [def] : [];
|
|
25
|
-
|
|
26
|
-
// GROQ filter — fonts from the same typeface, excluding items already in the array
|
|
27
|
-
const fontsFilter = async ({ getClient, document, parent }) => {
|
|
28
|
-
const client = getClient({ apiVersion: '2022-11-09' });
|
|
29
|
-
const typefaceName = document.title;
|
|
30
|
-
const fonts = await client.fetch('*[_type == "font" && lower(typefaceName) == lower($typefaceName)]', { typefaceName });
|
|
31
|
-
const relatedItemsFiltered = fonts.map(f => f._id).filter(Boolean);
|
|
32
|
-
const existingItems = (parent || []).map(f => f._ref).filter(Boolean);
|
|
33
|
-
return {
|
|
34
|
-
filter: '!(_id in $existingItems) && (_id in $relatedItemsFiltered)',
|
|
35
|
-
params: { existingItems, relatedItemsFiltered },
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
// GROQ filter — variable fonts from the same typeface, excluding items already in the array
|
|
40
|
-
const variableFontsFilter = async ({ getClient, document, parent }) => {
|
|
41
|
-
const client = getClient({ apiVersion: '2022-11-09' });
|
|
42
|
-
const typefaceName = document.title;
|
|
43
|
-
const existingItems = (parent || []).map(f => f._ref).filter(Boolean);
|
|
44
|
-
const fonts = await client.fetch('*[_type == "font" && typefaceName == $typefaceName && variableFont == true]', { typefaceName });
|
|
45
|
-
const relatedItemsFiltered = fonts.map(f => f._id).filter(Boolean);
|
|
46
|
-
return {
|
|
47
|
-
filter: '!(_id in $existingItems) && (_id in $relatedItemsFiltered)',
|
|
48
|
-
params: { existingItems, relatedItemsFiltered },
|
|
49
|
-
};
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// GROQ filter — non-variable fonts already in the subfamily's fonts array, for preferred style picker
|
|
53
|
-
const subfamilyPreferredStyleFilter = async ({ getClient, document, parent }) => {
|
|
54
|
-
const client = getClient({ apiVersion: '2022-11-09' });
|
|
55
|
-
const typefaceName = document.title;
|
|
56
|
-
const fonts = await client.fetch('*[_type == "font" && typefaceName == $typefaceName && variableFont == false]', { typefaceName });
|
|
57
|
-
const relatedItemsFiltered = fonts.map(f => f._id).filter(Boolean);
|
|
58
|
-
const existingItems = (parent.fonts || []).map(f => f._ref).filter(Boolean);
|
|
59
|
-
return {
|
|
60
|
-
filter: '(_id in $existingItems) && (_id in $relatedItemsFiltered)',
|
|
61
|
-
params: { existingItems, relatedItemsFiltered },
|
|
62
|
-
};
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
/**
|
|
66
|
-
* Generates the Styles object field for a typeface document with configurable per-site options.
|
|
67
|
-
* @param {Object} [options]
|
|
68
|
-
* @param {boolean} [options.free=false] - Include "Free Typeface" boolean
|
|
69
|
-
* @param {boolean} [options.displayStyles=true] - Show "Display All Styles" toggle to editors
|
|
70
|
-
* @param {boolean} [options.sortHeaviestFirst=false] - Include sort order toggle
|
|
71
|
-
* @param {boolean} [options.buySectionColumns=false] - Include multi-column buy section toggle
|
|
72
|
-
* @param {boolean} [options.fontSizeMultiplier=false] - Include style grid font size multiplier
|
|
73
|
-
* @param {boolean} [options.serif=false] - Include serif/sans classification field
|
|
74
|
-
* @param {boolean} [options.regenerateSubfamilies=false] - Include RegenerateSubfamilies action
|
|
75
|
-
* @param {boolean} [options.subfamilyFontSizeMultiplier=false] - Include per-subfamily font size multiplier
|
|
76
|
-
* @param {boolean} [options.subfamilyListOrder=false] - Include per-subfamily manual order toggle
|
|
77
|
-
* @param {boolean} [options.subfamilyPreferredStyle=false] - Include per-subfamily preferred style picker
|
|
78
|
-
* @param {boolean} [options.subfamilyFontFilter=false] - Filter subfamily font picker to typeface fonts only
|
|
79
|
-
* @param {boolean} [options.subfamilyPreview=false] - Include preview on subfamily array items
|
|
80
|
-
* @param {boolean} [options.pairs=true] - Show pairs array to editors
|
|
81
|
-
*/
|
|
82
|
-
export function createStylesField({
|
|
83
|
-
free = false,
|
|
84
|
-
displayStyles = true,
|
|
85
|
-
sortHeaviestFirst = false,
|
|
86
|
-
buySectionColumns = false,
|
|
87
|
-
fontSizeMultiplier = false,
|
|
88
|
-
serif = false,
|
|
89
|
-
regenerateSubfamilies = false,
|
|
90
|
-
subfamilyFontSizeMultiplier = false,
|
|
91
|
-
subfamilyListOrder = false,
|
|
92
|
-
subfamilyPreferredStyle = false,
|
|
93
|
-
subfamilyFontFilter = false,
|
|
94
|
-
subfamilyPreview = false,
|
|
95
|
-
pairs = true,
|
|
96
|
-
} = {}) {
|
|
97
|
-
|
|
98
|
-
const subfamilyFields = [
|
|
99
|
-
{
|
|
100
|
-
title: 'Title',
|
|
101
|
-
name: 'title',
|
|
102
|
-
type: 'string',
|
|
103
|
-
},
|
|
104
|
-
...field(subfamilyFontSizeMultiplier, {
|
|
105
|
-
title: 'Subfamily Font Size Multiplier',
|
|
106
|
-
name: 'fontSizeMultiplier',
|
|
107
|
-
type: 'number',
|
|
108
|
-
initialValue: 1,
|
|
109
|
-
description: 'Adjust font size for this subfamily in the Family Overview (Design Space). Default is 1.0 (100%). Range: 0.5 to 2.0',
|
|
110
|
-
validation: Rule => Rule.min(0.5).max(2.0).precision(2),
|
|
111
|
-
}),
|
|
112
|
-
...field(subfamilyListOrder, {
|
|
113
|
-
title: 'Use List Order',
|
|
114
|
-
name: 'useListOrder',
|
|
115
|
-
type: 'boolean',
|
|
116
|
-
initialValue: false,
|
|
117
|
-
description: 'Display fonts in the manual order listed below, bypassing programmatic weight-based sorting in the Family Overview.',
|
|
118
|
-
}),
|
|
119
|
-
{
|
|
120
|
-
title: 'Fonts',
|
|
121
|
-
name: 'fonts',
|
|
122
|
-
type: 'array',
|
|
123
|
-
components: { input: FontsRefArray },
|
|
124
|
-
of: [{ type: 'reference', weak: true, to: [{ type: 'font' }] }],
|
|
125
|
-
options: {
|
|
126
|
-
sortable: true,
|
|
127
|
-
...(subfamilyFontFilter ? { filter: fontsFilter } : {}),
|
|
128
|
-
},
|
|
129
|
-
},
|
|
130
|
-
...field(subfamilyPreferredStyle, {
|
|
131
|
-
title: 'Subfamily Preferred Style',
|
|
132
|
-
name: 'preferredStyle',
|
|
133
|
-
type: 'reference',
|
|
134
|
-
weak: true,
|
|
135
|
-
to: [{ type: 'font' }],
|
|
136
|
-
options: { filter: subfamilyPreferredStyleFilter },
|
|
137
|
-
}),
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
const subfamilyItem = {
|
|
141
|
-
type: 'object',
|
|
142
|
-
fields: subfamilyFields,
|
|
143
|
-
...(subfamilyPreview ? {
|
|
144
|
-
preview: {
|
|
145
|
-
select: { title: 'title', fonts: 'fonts' },
|
|
146
|
-
prepare({ title, fonts }) {
|
|
147
|
-
return { title, subtitle: `${(fonts || []).length} fonts` };
|
|
148
|
-
},
|
|
149
|
-
},
|
|
150
|
-
} : {}),
|
|
151
|
-
};
|
|
152
|
-
|
|
153
|
-
const fields = [
|
|
154
|
-
...field(free, {
|
|
155
|
-
title: 'Free Typeface',
|
|
156
|
-
name: 'free',
|
|
157
|
-
type: 'boolean',
|
|
158
|
-
initialValue: false,
|
|
159
|
-
description: 'This typeface is free to download and use. This will alter the "Buy" button and checkout experience.',
|
|
160
|
-
}),
|
|
161
|
-
{
|
|
162
|
-
title: 'Display All Styles',
|
|
163
|
-
name: 'displayStyles',
|
|
164
|
-
type: 'boolean',
|
|
165
|
-
initialValue: true,
|
|
166
|
-
hidden: !displayStyles,
|
|
167
|
-
description: 'Show all Font Styles below collections in Buy Section',
|
|
168
|
-
},
|
|
169
|
-
...field(sortHeaviestFirst, {
|
|
170
|
-
title: 'Sort Fonts Heaviest to Lightest',
|
|
171
|
-
name: 'sortHeaviestFirst',
|
|
172
|
-
type: 'boolean',
|
|
173
|
-
initialValue: false,
|
|
174
|
-
description: 'Sort fonts by weight from heaviest (900) to lightest (100). Default is lightest to heaviest (industry standard).',
|
|
175
|
-
}),
|
|
176
|
-
...field(buySectionColumns, {
|
|
177
|
-
title: 'Multi Column Buy Section',
|
|
178
|
-
name: 'buySectionColumns',
|
|
179
|
-
type: 'boolean',
|
|
180
|
-
initialValue: true,
|
|
181
|
-
description: 'Choose Single Column or Multi Column for the Buy Section, Default is Multi Column',
|
|
182
|
-
}),
|
|
183
|
-
...field(fontSizeMultiplier, {
|
|
184
|
-
title: 'Style Grid Font Size Multiplier',
|
|
185
|
-
name: 'fontSizeMultiplier',
|
|
186
|
-
type: 'number',
|
|
187
|
-
initialValue: 1,
|
|
188
|
-
description: 'Adjust font size in the buy section style grid. Default is 1.0 (100%). Range: 0.5 to 2.0',
|
|
189
|
-
validation: Rule => Rule.min(0.5).max(2.0).precision(2),
|
|
190
|
-
}),
|
|
191
|
-
...field(serif, {
|
|
192
|
-
title: 'Includes Serifs',
|
|
193
|
-
name: 'serif',
|
|
194
|
-
type: 'boolean',
|
|
195
|
-
initialValue: false,
|
|
196
|
-
description: 'Check if this typeface includes serif letterforms. Used for typeface overview serif/sans filters. Frontend automatically treats non-serif typefaces as sans serif.',
|
|
197
|
-
}),
|
|
198
|
-
{
|
|
199
|
-
title: 'Fonts',
|
|
200
|
-
name: 'fonts',
|
|
201
|
-
type: 'array',
|
|
202
|
-
components: { input: FontsRefArray },
|
|
203
|
-
of: [{
|
|
204
|
-
type: 'reference',
|
|
205
|
-
weak: true,
|
|
206
|
-
to: [{ type: 'font' }],
|
|
207
|
-
options: { filter: fontsFilter },
|
|
208
|
-
}],
|
|
209
|
-
options: { sortable: true },
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
title: 'Variable Fonts',
|
|
213
|
-
name: 'variableFont',
|
|
214
|
-
type: 'array',
|
|
215
|
-
components: { input: VariableFontsRefArray },
|
|
216
|
-
of: [{
|
|
217
|
-
type: 'reference',
|
|
218
|
-
weak: true,
|
|
219
|
-
to: [{ type: 'font' }],
|
|
220
|
-
options: { filter: variableFontsFilter },
|
|
221
|
-
}],
|
|
222
|
-
description: 'Variable fonts are automatically included as a bonus when customers purchase all non-variable styles of this typeface.',
|
|
223
|
-
options: { sortable: true },
|
|
224
|
-
},
|
|
225
|
-
...field(regenerateSubfamilies, {
|
|
226
|
-
title: 'Regenerate Subfamilies',
|
|
227
|
-
name: 'regenerateSubfamilies',
|
|
228
|
-
type: 'string',
|
|
229
|
-
hidden: ({ parent }) => !parent?.subfamilies?.length || !parent?.fonts?.length,
|
|
230
|
-
description: 'Regenerates subfamily groups based on the fonts in this typeface.',
|
|
231
|
-
components: { input: RegenerateSubfamiliesComponent },
|
|
232
|
-
}),
|
|
233
|
-
{
|
|
234
|
-
title: 'Subfamilies',
|
|
235
|
-
name: 'subfamilies',
|
|
236
|
-
type: 'array',
|
|
237
|
-
of: [subfamilyItem],
|
|
238
|
-
},
|
|
239
|
-
{
|
|
240
|
-
title: 'Collections',
|
|
241
|
-
name: 'collections',
|
|
242
|
-
type: 'array',
|
|
243
|
-
components: { input: AdvancedRefArray },
|
|
244
|
-
of: [{ type: 'reference', weak: true, to: [{ type: 'collection' }] }],
|
|
245
|
-
options: { sortable: true },
|
|
246
|
-
validation: Rule => Rule.unique(),
|
|
247
|
-
},
|
|
248
|
-
{
|
|
249
|
-
title: 'Pairs',
|
|
250
|
-
name: 'pairs',
|
|
251
|
-
type: 'array',
|
|
252
|
-
components: { input: AdvancedRefArray },
|
|
253
|
-
of: [{ type: 'reference', weak: true, to: [{ type: 'pair' }] }],
|
|
254
|
-
options: { sortable: true },
|
|
255
|
-
validation: Rule => Rule.unique(),
|
|
256
|
-
hidden: !pairs,
|
|
257
|
-
},
|
|
258
|
-
];
|
|
259
|
-
|
|
260
|
-
return {
|
|
261
|
-
title: 'Styles',
|
|
262
|
-
name: 'styles',
|
|
263
|
-
type: 'object',
|
|
264
|
-
group: 'styles',
|
|
265
|
-
fields,
|
|
266
|
-
options: { collapsible: true },
|
|
267
|
-
};
|
|
268
|
-
}
|
|
1
|
+
// Sanity schema factory function for the Styles object field — call createStylesField(options) to generate the field definition for a typeface document
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { AdvancedRefArray } from '@liiift-studio/sanity-advanced-reference-array';
|
|
4
|
+
import { RegenerateSubfamiliesComponent } from '../components/RegenerateSubfamiliesComponent.jsx';
|
|
5
|
+
|
|
6
|
+
// Returns extra GROQ params scoped to the current typeface document
|
|
7
|
+
const typefaceParams = (doc) => ({ typefaceName: doc?.title || '' });
|
|
8
|
+
|
|
9
|
+
// AdvancedRefArray wrapper — limits search results to fonts belonging to this typeface
|
|
10
|
+
const FontsRefArray = (props) => React.createElement(AdvancedRefArray, {
|
|
11
|
+
...props,
|
|
12
|
+
filterGroq: 'lower(typefaceName) == lower($typefaceName)',
|
|
13
|
+
filterParams: typefaceParams,
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// AdvancedRefArray wrapper — limits search results to variable fonts belonging to this typeface
|
|
17
|
+
const VariableFontsRefArray = (props) => React.createElement(AdvancedRefArray, {
|
|
18
|
+
...props,
|
|
19
|
+
filterGroq: 'lower(typefaceName) == lower($typefaceName) && variableFont == true',
|
|
20
|
+
filterParams: typefaceParams,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
// Conditionally includes a field definition in an array
|
|
24
|
+
const field = (condition, def) => condition ? [def] : [];
|
|
25
|
+
|
|
26
|
+
// GROQ filter — fonts from the same typeface, excluding items already in the array
|
|
27
|
+
const fontsFilter = async ({ getClient, document, parent }) => {
|
|
28
|
+
const client = getClient({ apiVersion: '2022-11-09' });
|
|
29
|
+
const typefaceName = document.title;
|
|
30
|
+
const fonts = await client.fetch('*[_type == "font" && lower(typefaceName) == lower($typefaceName)]', { typefaceName });
|
|
31
|
+
const relatedItemsFiltered = fonts.map(f => f._id).filter(Boolean);
|
|
32
|
+
const existingItems = (parent || []).map(f => f._ref).filter(Boolean);
|
|
33
|
+
return {
|
|
34
|
+
filter: '!(_id in $existingItems) && (_id in $relatedItemsFiltered)',
|
|
35
|
+
params: { existingItems, relatedItemsFiltered },
|
|
36
|
+
};
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// GROQ filter — variable fonts from the same typeface, excluding items already in the array
|
|
40
|
+
const variableFontsFilter = async ({ getClient, document, parent }) => {
|
|
41
|
+
const client = getClient({ apiVersion: '2022-11-09' });
|
|
42
|
+
const typefaceName = document.title;
|
|
43
|
+
const existingItems = (parent || []).map(f => f._ref).filter(Boolean);
|
|
44
|
+
const fonts = await client.fetch('*[_type == "font" && typefaceName == $typefaceName && variableFont == true]', { typefaceName });
|
|
45
|
+
const relatedItemsFiltered = fonts.map(f => f._id).filter(Boolean);
|
|
46
|
+
return {
|
|
47
|
+
filter: '!(_id in $existingItems) && (_id in $relatedItemsFiltered)',
|
|
48
|
+
params: { existingItems, relatedItemsFiltered },
|
|
49
|
+
};
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// GROQ filter — non-variable fonts already in the subfamily's fonts array, for preferred style picker
|
|
53
|
+
const subfamilyPreferredStyleFilter = async ({ getClient, document, parent }) => {
|
|
54
|
+
const client = getClient({ apiVersion: '2022-11-09' });
|
|
55
|
+
const typefaceName = document.title;
|
|
56
|
+
const fonts = await client.fetch('*[_type == "font" && typefaceName == $typefaceName && variableFont == false]', { typefaceName });
|
|
57
|
+
const relatedItemsFiltered = fonts.map(f => f._id).filter(Boolean);
|
|
58
|
+
const existingItems = (parent.fonts || []).map(f => f._ref).filter(Boolean);
|
|
59
|
+
return {
|
|
60
|
+
filter: '(_id in $existingItems) && (_id in $relatedItemsFiltered)',
|
|
61
|
+
params: { existingItems, relatedItemsFiltered },
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Generates the Styles object field for a typeface document with configurable per-site options.
|
|
67
|
+
* @param {Object} [options]
|
|
68
|
+
* @param {boolean} [options.free=false] - Include "Free Typeface" boolean
|
|
69
|
+
* @param {boolean} [options.displayStyles=true] - Show "Display All Styles" toggle to editors
|
|
70
|
+
* @param {boolean} [options.sortHeaviestFirst=false] - Include sort order toggle
|
|
71
|
+
* @param {boolean} [options.buySectionColumns=false] - Include multi-column buy section toggle
|
|
72
|
+
* @param {boolean} [options.fontSizeMultiplier=false] - Include style grid font size multiplier
|
|
73
|
+
* @param {boolean} [options.serif=false] - Include serif/sans classification field
|
|
74
|
+
* @param {boolean} [options.regenerateSubfamilies=false] - Include RegenerateSubfamilies action
|
|
75
|
+
* @param {boolean} [options.subfamilyFontSizeMultiplier=false] - Include per-subfamily font size multiplier
|
|
76
|
+
* @param {boolean} [options.subfamilyListOrder=false] - Include per-subfamily manual order toggle
|
|
77
|
+
* @param {boolean} [options.subfamilyPreferredStyle=false] - Include per-subfamily preferred style picker
|
|
78
|
+
* @param {boolean} [options.subfamilyFontFilter=false] - Filter subfamily font picker to typeface fonts only
|
|
79
|
+
* @param {boolean} [options.subfamilyPreview=false] - Include preview on subfamily array items
|
|
80
|
+
* @param {boolean} [options.pairs=true] - Show pairs array to editors
|
|
81
|
+
*/
|
|
82
|
+
export function createStylesField({
|
|
83
|
+
free = false,
|
|
84
|
+
displayStyles = true,
|
|
85
|
+
sortHeaviestFirst = false,
|
|
86
|
+
buySectionColumns = false,
|
|
87
|
+
fontSizeMultiplier = false,
|
|
88
|
+
serif = false,
|
|
89
|
+
regenerateSubfamilies = false,
|
|
90
|
+
subfamilyFontSizeMultiplier = false,
|
|
91
|
+
subfamilyListOrder = false,
|
|
92
|
+
subfamilyPreferredStyle = false,
|
|
93
|
+
subfamilyFontFilter = false,
|
|
94
|
+
subfamilyPreview = false,
|
|
95
|
+
pairs = true,
|
|
96
|
+
} = {}) {
|
|
97
|
+
|
|
98
|
+
const subfamilyFields = [
|
|
99
|
+
{
|
|
100
|
+
title: 'Title',
|
|
101
|
+
name: 'title',
|
|
102
|
+
type: 'string',
|
|
103
|
+
},
|
|
104
|
+
...field(subfamilyFontSizeMultiplier, {
|
|
105
|
+
title: 'Subfamily Font Size Multiplier',
|
|
106
|
+
name: 'fontSizeMultiplier',
|
|
107
|
+
type: 'number',
|
|
108
|
+
initialValue: 1,
|
|
109
|
+
description: 'Adjust font size for this subfamily in the Family Overview (Design Space). Default is 1.0 (100%). Range: 0.5 to 2.0',
|
|
110
|
+
validation: Rule => Rule.min(0.5).max(2.0).precision(2),
|
|
111
|
+
}),
|
|
112
|
+
...field(subfamilyListOrder, {
|
|
113
|
+
title: 'Use List Order',
|
|
114
|
+
name: 'useListOrder',
|
|
115
|
+
type: 'boolean',
|
|
116
|
+
initialValue: false,
|
|
117
|
+
description: 'Display fonts in the manual order listed below, bypassing programmatic weight-based sorting in the Family Overview.',
|
|
118
|
+
}),
|
|
119
|
+
{
|
|
120
|
+
title: 'Fonts',
|
|
121
|
+
name: 'fonts',
|
|
122
|
+
type: 'array',
|
|
123
|
+
components: { input: FontsRefArray },
|
|
124
|
+
of: [{ type: 'reference', weak: true, to: [{ type: 'font' }] }],
|
|
125
|
+
options: {
|
|
126
|
+
sortable: true,
|
|
127
|
+
...(subfamilyFontFilter ? { filter: fontsFilter } : {}),
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
...field(subfamilyPreferredStyle, {
|
|
131
|
+
title: 'Subfamily Preferred Style',
|
|
132
|
+
name: 'preferredStyle',
|
|
133
|
+
type: 'reference',
|
|
134
|
+
weak: true,
|
|
135
|
+
to: [{ type: 'font' }],
|
|
136
|
+
options: { filter: subfamilyPreferredStyleFilter },
|
|
137
|
+
}),
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
const subfamilyItem = {
|
|
141
|
+
type: 'object',
|
|
142
|
+
fields: subfamilyFields,
|
|
143
|
+
...(subfamilyPreview ? {
|
|
144
|
+
preview: {
|
|
145
|
+
select: { title: 'title', fonts: 'fonts' },
|
|
146
|
+
prepare({ title, fonts }) {
|
|
147
|
+
return { title, subtitle: `${(fonts || []).length} fonts` };
|
|
148
|
+
},
|
|
149
|
+
},
|
|
150
|
+
} : {}),
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const fields = [
|
|
154
|
+
...field(free, {
|
|
155
|
+
title: 'Free Typeface',
|
|
156
|
+
name: 'free',
|
|
157
|
+
type: 'boolean',
|
|
158
|
+
initialValue: false,
|
|
159
|
+
description: 'This typeface is free to download and use. This will alter the "Buy" button and checkout experience.',
|
|
160
|
+
}),
|
|
161
|
+
{
|
|
162
|
+
title: 'Display All Styles',
|
|
163
|
+
name: 'displayStyles',
|
|
164
|
+
type: 'boolean',
|
|
165
|
+
initialValue: true,
|
|
166
|
+
hidden: !displayStyles,
|
|
167
|
+
description: 'Show all Font Styles below collections in Buy Section',
|
|
168
|
+
},
|
|
169
|
+
...field(sortHeaviestFirst, {
|
|
170
|
+
title: 'Sort Fonts Heaviest to Lightest',
|
|
171
|
+
name: 'sortHeaviestFirst',
|
|
172
|
+
type: 'boolean',
|
|
173
|
+
initialValue: false,
|
|
174
|
+
description: 'Sort fonts by weight from heaviest (900) to lightest (100). Default is lightest to heaviest (industry standard).',
|
|
175
|
+
}),
|
|
176
|
+
...field(buySectionColumns, {
|
|
177
|
+
title: 'Multi Column Buy Section',
|
|
178
|
+
name: 'buySectionColumns',
|
|
179
|
+
type: 'boolean',
|
|
180
|
+
initialValue: true,
|
|
181
|
+
description: 'Choose Single Column or Multi Column for the Buy Section, Default is Multi Column',
|
|
182
|
+
}),
|
|
183
|
+
...field(fontSizeMultiplier, {
|
|
184
|
+
title: 'Style Grid Font Size Multiplier',
|
|
185
|
+
name: 'fontSizeMultiplier',
|
|
186
|
+
type: 'number',
|
|
187
|
+
initialValue: 1,
|
|
188
|
+
description: 'Adjust font size in the buy section style grid. Default is 1.0 (100%). Range: 0.5 to 2.0',
|
|
189
|
+
validation: Rule => Rule.min(0.5).max(2.0).precision(2),
|
|
190
|
+
}),
|
|
191
|
+
...field(serif, {
|
|
192
|
+
title: 'Includes Serifs',
|
|
193
|
+
name: 'serif',
|
|
194
|
+
type: 'boolean',
|
|
195
|
+
initialValue: false,
|
|
196
|
+
description: 'Check if this typeface includes serif letterforms. Used for typeface overview serif/sans filters. Frontend automatically treats non-serif typefaces as sans serif.',
|
|
197
|
+
}),
|
|
198
|
+
{
|
|
199
|
+
title: 'Fonts',
|
|
200
|
+
name: 'fonts',
|
|
201
|
+
type: 'array',
|
|
202
|
+
components: { input: FontsRefArray },
|
|
203
|
+
of: [{
|
|
204
|
+
type: 'reference',
|
|
205
|
+
weak: true,
|
|
206
|
+
to: [{ type: 'font' }],
|
|
207
|
+
options: { filter: fontsFilter },
|
|
208
|
+
}],
|
|
209
|
+
options: { sortable: true },
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
title: 'Variable Fonts',
|
|
213
|
+
name: 'variableFont',
|
|
214
|
+
type: 'array',
|
|
215
|
+
components: { input: VariableFontsRefArray },
|
|
216
|
+
of: [{
|
|
217
|
+
type: 'reference',
|
|
218
|
+
weak: true,
|
|
219
|
+
to: [{ type: 'font' }],
|
|
220
|
+
options: { filter: variableFontsFilter },
|
|
221
|
+
}],
|
|
222
|
+
description: 'Variable fonts are automatically included as a bonus when customers purchase all non-variable styles of this typeface.',
|
|
223
|
+
options: { sortable: true },
|
|
224
|
+
},
|
|
225
|
+
...field(regenerateSubfamilies, {
|
|
226
|
+
title: 'Regenerate Subfamilies',
|
|
227
|
+
name: 'regenerateSubfamilies',
|
|
228
|
+
type: 'string',
|
|
229
|
+
hidden: ({ parent }) => !parent?.subfamilies?.length || !parent?.fonts?.length,
|
|
230
|
+
description: 'Regenerates subfamily groups based on the fonts in this typeface.',
|
|
231
|
+
components: { input: RegenerateSubfamiliesComponent },
|
|
232
|
+
}),
|
|
233
|
+
{
|
|
234
|
+
title: 'Subfamilies',
|
|
235
|
+
name: 'subfamilies',
|
|
236
|
+
type: 'array',
|
|
237
|
+
of: [subfamilyItem],
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
title: 'Collections',
|
|
241
|
+
name: 'collections',
|
|
242
|
+
type: 'array',
|
|
243
|
+
components: { input: AdvancedRefArray },
|
|
244
|
+
of: [{ type: 'reference', weak: true, to: [{ type: 'collection' }] }],
|
|
245
|
+
options: { sortable: true },
|
|
246
|
+
validation: Rule => Rule.unique(),
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
title: 'Pairs',
|
|
250
|
+
name: 'pairs',
|
|
251
|
+
type: 'array',
|
|
252
|
+
components: { input: AdvancedRefArray },
|
|
253
|
+
of: [{ type: 'reference', weak: true, to: [{ type: 'pair' }] }],
|
|
254
|
+
options: { sortable: true },
|
|
255
|
+
validation: Rule => Rule.unique(),
|
|
256
|
+
hidden: !pairs,
|
|
257
|
+
},
|
|
258
|
+
];
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
title: 'Styles',
|
|
262
|
+
name: 'styles',
|
|
263
|
+
type: 'object',
|
|
264
|
+
group: 'styles',
|
|
265
|
+
fields,
|
|
266
|
+
options: { collapsible: true },
|
|
267
|
+
};
|
|
268
|
+
}
|