@liiift-studio/sanity-font-manager 2.5.0 → 2.5.2
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/UploadModal-2AAJXZJK.js +6 -0
- package/dist/{UploadModal-NME2W53V.mjs → UploadModal-DDTVJ2MA.mjs} +1 -1
- package/dist/{chunk-646WCBRR.mjs → chunk-FT7YTFZW.mjs} +617 -182
- package/dist/{chunk-FH4QKHOH.js → chunk-YMQEM4AO.js} +583 -148
- package/dist/index.js +109 -66
- package/dist/index.mjs +66 -23
- package/package.json +1 -1
- package/src/components/BatchUploadFonts.jsx +1 -1
- package/src/components/FontReviewCard.jsx +41 -1
- package/src/components/KeyValueReferenceInput.jsx +69 -61
- package/src/components/SingleUploaderTool.jsx +3 -3
- package/src/components/UploadModal.jsx +43 -7
- package/src/components/UploadStep1Settings.jsx +1 -1
- package/src/components/UploadStep2Review.jsx +2 -0
- package/src/components/UploadStep3Execute.jsx +1 -1
- package/src/components/UploadStep3bInstances.jsx +396 -0
- package/src/index.js +1 -0
- package/src/schema/stylesField.js +20 -0
- package/src/utils/buildUploadPlan.js +1 -0
- package/src/utils/executeUploadPlan.js +1 -8
- package/src/utils/parseVariableFontInstances.js +237 -147
- package/src/utils/processFontFiles.js +5 -4
- package/src/utils/updateTypefaceDocument.js +15 -2
- package/dist/UploadModal-6LIX7XOK.js +0 -6
|
@@ -3460,8 +3460,8 @@ var require_unbrotli = __commonJS({
|
|
|
3460
3460
|
});
|
|
3461
3461
|
|
|
3462
3462
|
// src/components/UploadModal.jsx
|
|
3463
|
-
import
|
|
3464
|
-
import { Dialog, Box as
|
|
3463
|
+
import React10, { useReducer as useReducer2, useCallback as useCallback6, useState as useState7, useMemo as useMemo7, useRef as useRef3, useEffect as useEffect5 } from "react";
|
|
3464
|
+
import { Dialog, Box as Box9, Flex as Flex10, Text as Text10, Badge as Badge8, Button as Button8 } from "@sanity/ui";
|
|
3465
3465
|
|
|
3466
3466
|
// src/utils/planTypes.js
|
|
3467
3467
|
var FONT_STATUS = {
|
|
@@ -4488,14 +4488,14 @@ var extractFontMetadata = (font, title, weightKeywordList, italicKeywordList, pr
|
|
|
4488
4488
|
weightName = expandAbbreviations(weightName);
|
|
4489
4489
|
}
|
|
4490
4490
|
const fullName = getNameString(font, 4) || (ttfFallbackMeta == null ? void 0 : ttfFallbackMeta.fullName) || "";
|
|
4491
|
-
|
|
4491
|
+
const axes = getVariationAxes(font);
|
|
4492
|
+
const variableFont = axes !== null;
|
|
4493
|
+
if (!variableFont && (weightName === "" || weightName.toLowerCase() === "roman") && fullName) {
|
|
4492
4494
|
weightName = extractWeightFromFullName(font, title, ttfFallbackMeta);
|
|
4493
4495
|
if (!preserveShortenedNames) {
|
|
4494
4496
|
weightName = expandAbbreviations(weightName);
|
|
4495
4497
|
}
|
|
4496
4498
|
}
|
|
4497
|
-
const axes = getVariationAxes(font);
|
|
4498
|
-
const variableFont = axes !== null;
|
|
4499
4499
|
const trimmedTitle = title.trim();
|
|
4500
4500
|
const nameId4Remainder = fullName ? fullName.replace(trimmedTitle, "").trim() : "";
|
|
4501
4501
|
const nameId1 = getNameString(font, 1) || (ttfFallbackMeta == null ? void 0 : ttfFallbackMeta.familyName) || "";
|
|
@@ -4779,6 +4779,7 @@ async function buildUploadPlan({
|
|
|
4779
4779
|
onProgress
|
|
4780
4780
|
}) {
|
|
4781
4781
|
const plan = createEmptyPlan(settings);
|
|
4782
|
+
plan.settings.typefaceTitle = typefaceTitle;
|
|
4782
4783
|
plan.phase = PLAN_PHASE.PROCESSING;
|
|
4783
4784
|
plan.processingProgress.total = files.length;
|
|
4784
4785
|
for (let i = 0; i < files.length; i++) {
|
|
@@ -5189,7 +5190,7 @@ function UploadStep1Settings({ settings, onStartProcessing }) {
|
|
|
5189
5190
|
},
|
|
5190
5191
|
ext.toUpperCase()
|
|
5191
5192
|
),
|
|
5192
|
-
/* @__PURE__ */ React.createElement(Text, { size: 1, style: { flex: 1
|
|
5193
|
+
/* @__PURE__ */ React.createElement(Text, { size: 1, style: { flex: 1 } }, file.name),
|
|
5193
5194
|
/* @__PURE__ */ React.createElement(
|
|
5194
5195
|
Button,
|
|
5195
5196
|
{
|
|
@@ -5302,10 +5303,11 @@ function ExistingDocumentResolver({ decision, tempId, dispatch }) {
|
|
|
5302
5303
|
// src/components/FontReviewCard.jsx
|
|
5303
5304
|
var STANDARD_TYPES = ["ttf", "otf", "woff", "woff2"];
|
|
5304
5305
|
var EXTENDED_TYPES = ["eot", "svg", "css", "woff2_subset", "woff2_web"];
|
|
5305
|
-
var FontReviewCard = memo(function FontReviewCard2({ entry, dispatch, allExpanded }) {
|
|
5306
|
+
var FontReviewCard = memo(function FontReviewCard2({ entry, dispatch, allExpanded, typefaceTitle, price }) {
|
|
5306
5307
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
5307
5308
|
const [expanded, setExpanded] = useState2(false);
|
|
5308
5309
|
const [showAllFileTypes, setShowAllFileTypes] = useState2(false);
|
|
5310
|
+
const [showDocPreview, setShowDocPreview] = useState2(false);
|
|
5309
5311
|
useEffect(() => {
|
|
5310
5312
|
setExpanded(allExpanded);
|
|
5311
5313
|
}, [allExpanded]);
|
|
@@ -5513,7 +5515,32 @@ var FontReviewCard = memo(function FontReviewCard2({ entry, dispatch, allExpande
|
|
|
5513
5515
|
tempId: entry.tempId,
|
|
5514
5516
|
dispatch
|
|
5515
5517
|
}
|
|
5516
|
-
), /* @__PURE__ */ React3.createElement(
|
|
5518
|
+
), /* @__PURE__ */ React3.createElement(Stack3, { space: 2 }, /* @__PURE__ */ React3.createElement(
|
|
5519
|
+
Button3,
|
|
5520
|
+
{
|
|
5521
|
+
mode: "bleed",
|
|
5522
|
+
fontSize: 0,
|
|
5523
|
+
padding: 1,
|
|
5524
|
+
text: showDocPreview ? "Hide document preview" : "Show document preview",
|
|
5525
|
+
onClick: () => setShowDocPreview((v) => !v),
|
|
5526
|
+
style: { cursor: "pointer", alignSelf: "flex-start" }
|
|
5527
|
+
}
|
|
5528
|
+
), showDocPreview && /* @__PURE__ */ React3.createElement(Card3, { border: true, padding: 3, radius: 1, style: { fontFamily: "monospace", fontSize: 12 } }, /* @__PURE__ */ React3.createElement(Stack3, { space: 2 }, [
|
|
5529
|
+
["_id", entry.documentId],
|
|
5530
|
+
["_type", "font"],
|
|
5531
|
+
["title", entry.title],
|
|
5532
|
+
["slug", entry.documentId],
|
|
5533
|
+
["typefaceName", typefaceTitle || "\u2014"],
|
|
5534
|
+
["weightName", entry.weightName || "\u2014"],
|
|
5535
|
+
["weight", entry.weight],
|
|
5536
|
+
["style", entry.style],
|
|
5537
|
+
["subfamily", entry.subfamily || "\u2014"],
|
|
5538
|
+
["variableFont", String(entry.variableFont)],
|
|
5539
|
+
["price", price ?? "\u2014"],
|
|
5540
|
+
["sell", price > 0 ? "true" : "false"],
|
|
5541
|
+
["normalWeight", "true"],
|
|
5542
|
+
["files", (entry.files || []).map((f) => f.name).join(", ") || "\u2014"]
|
|
5543
|
+
].map(([key, value]) => /* @__PURE__ */ React3.createElement(Flex3, { key, gap: 2 }, /* @__PURE__ */ React3.createElement(Text3, { size: 0, muted: true, style: { width: 120, flexShrink: 0 } }, key), /* @__PURE__ */ React3.createElement(Text3, { size: 0, style: { wordBreak: "break-all" } }, String(value))))))), /* @__PURE__ */ React3.createElement(Flex3, { justify: "flex-end", gap: 2 }, hasUserOverrides && /* @__PURE__ */ React3.createElement(
|
|
5517
5544
|
Button3,
|
|
5518
5545
|
{
|
|
5519
5546
|
mode: "ghost",
|
|
@@ -5922,15 +5949,20 @@ function UploadStep2Review({
|
|
|
5922
5949
|
" ",
|
|
5923
5950
|
sortBy === col.key ? sortDir === "asc" ? "\u2191" : "\u2193" : ""
|
|
5924
5951
|
))
|
|
5925
|
-
), Object.entries(groupedEntries).map(([subfamily, entries]) => /* @__PURE__ */ React6.createElement(Stack4, { key: subfamily, space: 1 }, /* @__PURE__ */ React6.createElement(Card4, { padding: 2, radius: 1, style: { background: "var(--card-muted-bg-color)" } }, /* @__PURE__ */ React6.createElement(Flex6, { align: "center", gap: 2 }, /* @__PURE__ */ React6.createElement(Text6, { size: 1, weight: "semibold" }, subfamily), /* @__PURE__ */ React6.createElement(Badge4, { mode: "outline", fontSize: 0 }, entries.length))), /* @__PURE__ */ React6.createElement(Stack4, { space: 0 }, entries.map((entry) =>
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
|
|
5931
|
-
|
|
5932
|
-
|
|
5933
|
-
|
|
5952
|
+
), Object.entries(groupedEntries).map(([subfamily, entries]) => /* @__PURE__ */ React6.createElement(Stack4, { key: subfamily, space: 1 }, /* @__PURE__ */ React6.createElement(Card4, { padding: 2, radius: 1, style: { background: "var(--card-muted-bg-color)" } }, /* @__PURE__ */ React6.createElement(Flex6, { align: "center", gap: 2 }, /* @__PURE__ */ React6.createElement(Text6, { size: 1, weight: "semibold" }, subfamily), /* @__PURE__ */ React6.createElement(Badge4, { mode: "outline", fontSize: 0 }, entries.length))), /* @__PURE__ */ React6.createElement(Stack4, { space: 0 }, entries.map((entry) => {
|
|
5953
|
+
var _a2, _b2;
|
|
5954
|
+
return /* @__PURE__ */ React6.createElement(
|
|
5955
|
+
FontReviewCard_default,
|
|
5956
|
+
{
|
|
5957
|
+
key: entry.tempId,
|
|
5958
|
+
entry,
|
|
5959
|
+
dispatch,
|
|
5960
|
+
allExpanded,
|
|
5961
|
+
typefaceTitle: (_a2 = plan.settings) == null ? void 0 : _a2.typefaceTitle,
|
|
5962
|
+
price: (_b2 = plan.settings) == null ? void 0 : _b2.price
|
|
5963
|
+
}
|
|
5964
|
+
);
|
|
5965
|
+
})))), visibleEntries.length === 0 && fontEntries.length > 0 && /* @__PURE__ */ React6.createElement(Card4, { border: true, padding: 4, radius: 2 }, /* @__PURE__ */ React6.createElement(Text6, { size: 1, muted: true, align: "center" }, "No fonts match the current filter")), isReviewing && validationErrors.length > 0 && /* @__PURE__ */ React6.createElement(Card4, { tone: "caution", border: true, padding: 2, radius: 2 }, /* @__PURE__ */ React6.createElement(Stack4, { space: 1 }, validationErrors.map((err, i) => /* @__PURE__ */ React6.createElement(Text6, { key: i, size: 0, tone: "caution" }, "\u2022 ", err)))), isReviewing && processedCount > 0 && /* @__PURE__ */ React6.createElement(Flex6, { justify: "flex-end", gap: 2, style: { position: "sticky", bottom: 0, background: "var(--card-bg-color)", paddingTop: 8, paddingBottom: 4 } }, /* @__PURE__ */ React6.createElement(
|
|
5934
5966
|
Button5,
|
|
5935
5967
|
{
|
|
5936
5968
|
mode: "default",
|
|
@@ -6168,6 +6200,169 @@ async function generateFontData({ fileInput, url, fontKit, fontId, client, commi
|
|
|
6168
6200
|
|
|
6169
6201
|
// src/utils/parseVariableFontInstances.js
|
|
6170
6202
|
import { nanoid as nanoid3 } from "nanoid";
|
|
6203
|
+
var WIDTH_PREFIXES = [
|
|
6204
|
+
"XXXWide",
|
|
6205
|
+
"XXWide",
|
|
6206
|
+
"XWide",
|
|
6207
|
+
"Wide",
|
|
6208
|
+
"XXXNarrow",
|
|
6209
|
+
"XXNarrow",
|
|
6210
|
+
"XNarrow",
|
|
6211
|
+
"Narrow"
|
|
6212
|
+
];
|
|
6213
|
+
function parseInstanceName(instanceName) {
|
|
6214
|
+
let subfamily = "";
|
|
6215
|
+
let remaining = instanceName.trim();
|
|
6216
|
+
for (const prefix of WIDTH_PREFIXES) {
|
|
6217
|
+
if (remaining.toLowerCase().startsWith(prefix.toLowerCase() + " ") || remaining.toLowerCase() === prefix.toLowerCase()) {
|
|
6218
|
+
subfamily = prefix;
|
|
6219
|
+
remaining = remaining.substring(prefix.length).trim();
|
|
6220
|
+
break;
|
|
6221
|
+
}
|
|
6222
|
+
}
|
|
6223
|
+
let style = "";
|
|
6224
|
+
for (const suffix of ["Backslant", "Slant", "Italic", "Oblique"]) {
|
|
6225
|
+
if (remaining.toLowerCase().endsWith(" " + suffix.toLowerCase()) || remaining.toLowerCase() === suffix.toLowerCase()) {
|
|
6226
|
+
style = suffix;
|
|
6227
|
+
remaining = remaining.substring(0, remaining.length - suffix.length).trim();
|
|
6228
|
+
break;
|
|
6229
|
+
}
|
|
6230
|
+
}
|
|
6231
|
+
return { subfamily, weight: remaining || "Regular", style };
|
|
6232
|
+
}
|
|
6233
|
+
function filterBySubfamily(staticFonts, instanceSubfamily, typefaceName) {
|
|
6234
|
+
if (!instanceSubfamily) {
|
|
6235
|
+
return staticFonts.filter((sf) => {
|
|
6236
|
+
const sub = (sf.subfamily || "").toLowerCase();
|
|
6237
|
+
if (sub === "" || sub === "regular") return true;
|
|
6238
|
+
const afterTypeface = (sf.title || "").replace(typefaceName, "").trim();
|
|
6239
|
+
return !WIDTH_PREFIXES.some((p) => afterTypeface.toLowerCase().startsWith(p.toLowerCase()));
|
|
6240
|
+
});
|
|
6241
|
+
}
|
|
6242
|
+
const lowerSf = instanceSubfamily.toLowerCase();
|
|
6243
|
+
const expanded = (expandAbbreviations(instanceSubfamily) || "").toLowerCase();
|
|
6244
|
+
return staticFonts.filter((sf) => {
|
|
6245
|
+
const sub = (sf.subfamily || "").toLowerCase();
|
|
6246
|
+
if (sub === lowerSf || expanded && sub === expanded) return true;
|
|
6247
|
+
const afterTypeface = (sf.title || "").replace(typefaceName, "").trim().toLowerCase();
|
|
6248
|
+
if (afterTypeface.startsWith(lowerSf)) return true;
|
|
6249
|
+
if (expanded && afterTypeface.startsWith(expanded)) return true;
|
|
6250
|
+
return false;
|
|
6251
|
+
});
|
|
6252
|
+
}
|
|
6253
|
+
var WEIGHT_MAP = [
|
|
6254
|
+
{ term: "ultra", weight: 950 },
|
|
6255
|
+
{ term: "xxlight", weight: 200 },
|
|
6256
|
+
{ term: "xlight", weight: 250 },
|
|
6257
|
+
{ term: "extralight", weight: 200 },
|
|
6258
|
+
{ term: "extra light", weight: 200 },
|
|
6259
|
+
{ term: "thin", weight: 100 },
|
|
6260
|
+
{ term: "hairline", weight: 100 },
|
|
6261
|
+
{ term: "light", weight: 300 },
|
|
6262
|
+
{ term: "regular", weight: 400 },
|
|
6263
|
+
{ term: "normal", weight: 400 },
|
|
6264
|
+
{ term: "medium", weight: 500 },
|
|
6265
|
+
{ term: "semibold", weight: 600 },
|
|
6266
|
+
{ term: "semi bold", weight: 600 },
|
|
6267
|
+
{ term: "extrabold", weight: 800 },
|
|
6268
|
+
{ term: "extra bold", weight: 800 },
|
|
6269
|
+
{ term: "xbold", weight: 800 },
|
|
6270
|
+
{ term: "bold", weight: 700 },
|
|
6271
|
+
{ term: "black", weight: 900 },
|
|
6272
|
+
{ term: "heavy", weight: 900 }
|
|
6273
|
+
];
|
|
6274
|
+
function weightFromName(name) {
|
|
6275
|
+
const lower = name.toLowerCase();
|
|
6276
|
+
for (const { term, weight } of WEIGHT_MAP) {
|
|
6277
|
+
if (lower === term || lower.includes(term)) return weight;
|
|
6278
|
+
}
|
|
6279
|
+
return 400;
|
|
6280
|
+
}
|
|
6281
|
+
var STRATEGIES = [
|
|
6282
|
+
// Pass 1: Exact title match (with typeface prefix)
|
|
6283
|
+
{
|
|
6284
|
+
name: "exact-title",
|
|
6285
|
+
match: (instanceName, parsed, candidates, typefaceName) => {
|
|
6286
|
+
const withPrefix = `${typefaceName} ${instanceName}`;
|
|
6287
|
+
return candidates.find((sf) => sf.title === instanceName || sf.title === withPrefix) || null;
|
|
6288
|
+
}
|
|
6289
|
+
},
|
|
6290
|
+
// Pass 2: Title normalisation — strip typeface name and compare remainder
|
|
6291
|
+
{
|
|
6292
|
+
name: "title-normalised",
|
|
6293
|
+
match: (instanceName, parsed, candidates, typefaceName) => {
|
|
6294
|
+
return candidates.find((sf) => {
|
|
6295
|
+
const sfName = (sf.title || "").replace(typefaceName, "").trim();
|
|
6296
|
+
if (sfName.toLowerCase() === instanceName.toLowerCase()) return true;
|
|
6297
|
+
if (parsed.weight === "Regular" && !parsed.style) {
|
|
6298
|
+
if (sfName.toLowerCase() === parsed.subfamily.toLowerCase()) return true;
|
|
6299
|
+
}
|
|
6300
|
+
return false;
|
|
6301
|
+
}) || null;
|
|
6302
|
+
}
|
|
6303
|
+
},
|
|
6304
|
+
// Pass 3: Abbreviation expansion (XLight → ExtraLight, XBold → ExtraBold)
|
|
6305
|
+
{
|
|
6306
|
+
name: "abbreviation",
|
|
6307
|
+
match: (instanceName, parsed, candidates, typefaceName) => {
|
|
6308
|
+
const expandedFull = instanceName.split(" ").map((w) => expandAbbreviations(w) || w).join(" ");
|
|
6309
|
+
let found = candidates.find((sf) => {
|
|
6310
|
+
const sfName = (sf.title || "").replace(typefaceName, "").trim();
|
|
6311
|
+
return sfName.toLowerCase() === expandedFull.toLowerCase();
|
|
6312
|
+
});
|
|
6313
|
+
if (found) return found;
|
|
6314
|
+
const expandedWeight = expandAbbreviations(parsed.weight) || parsed.weight;
|
|
6315
|
+
const target = [parsed.subfamily, expandedWeight, parsed.style].filter(Boolean).join(" ");
|
|
6316
|
+
return candidates.find((sf) => {
|
|
6317
|
+
const sfName = (sf.title || "").replace(typefaceName, "").trim();
|
|
6318
|
+
return sfName.toLowerCase() === target.toLowerCase();
|
|
6319
|
+
}) || null;
|
|
6320
|
+
}
|
|
6321
|
+
},
|
|
6322
|
+
// Pass 4: fullName metadata comparison
|
|
6323
|
+
{
|
|
6324
|
+
name: "metadata-fullName",
|
|
6325
|
+
match: (instanceName, parsed, candidates, typefaceName) => {
|
|
6326
|
+
return candidates.find((sf) => {
|
|
6327
|
+
var _a;
|
|
6328
|
+
if (!((_a = sf.metaData) == null ? void 0 : _a.fullName)) return false;
|
|
6329
|
+
const typefacePattern = new RegExp(`^${typefaceName}\\s+`, "i");
|
|
6330
|
+
const stylePart = sf.metaData.fullName.replace(typefacePattern, "").trim();
|
|
6331
|
+
return instanceName.toLowerCase() === stylePart.toLowerCase();
|
|
6332
|
+
}) || null;
|
|
6333
|
+
}
|
|
6334
|
+
},
|
|
6335
|
+
// Pass 5: Weight + style matching (numeric, within subfamily)
|
|
6336
|
+
{
|
|
6337
|
+
name: "weight-style",
|
|
6338
|
+
match: (instanceName, parsed, candidates) => {
|
|
6339
|
+
const instanceWeight = weightFromName(parsed.weight);
|
|
6340
|
+
const isBackslant = parsed.style.toLowerCase() === "backslant";
|
|
6341
|
+
const isSlant = parsed.style.toLowerCase() === "slant";
|
|
6342
|
+
const isItalic = parsed.style.toLowerCase() === "italic";
|
|
6343
|
+
return candidates.find((sf) => {
|
|
6344
|
+
var _a, _b;
|
|
6345
|
+
if (Number(sf.weight) !== instanceWeight) return false;
|
|
6346
|
+
if (isBackslant) return sf.style === "Italic" && ((_a = sf.title) == null ? void 0 : _a.toLowerCase().includes("backslant"));
|
|
6347
|
+
if (isSlant) return sf.style === "Italic" && !((_b = sf.title) == null ? void 0 : _b.toLowerCase().includes("backslant"));
|
|
6348
|
+
if (isItalic) return sf.style === "Italic";
|
|
6349
|
+
return sf.style === "Regular";
|
|
6350
|
+
}) || null;
|
|
6351
|
+
}
|
|
6352
|
+
},
|
|
6353
|
+
// Pass 6: weightName string comparison
|
|
6354
|
+
{
|
|
6355
|
+
name: "weightName",
|
|
6356
|
+
match: (instanceName, parsed, candidates) => {
|
|
6357
|
+
const cleanInstance = parsed.weight.toLowerCase().trim();
|
|
6358
|
+
return candidates.find((sf) => {
|
|
6359
|
+
if (!sf.weightName) return false;
|
|
6360
|
+
const cleanWeight = sf.weightName.toLowerCase().replace(/italic|slant|backslant/gi, "").trim();
|
|
6361
|
+
return cleanInstance === cleanWeight;
|
|
6362
|
+
}) || null;
|
|
6363
|
+
}
|
|
6364
|
+
}
|
|
6365
|
+
];
|
|
6171
6366
|
var parseVariableFontInstances = async (font, client) => {
|
|
6172
6367
|
if (!font.variableFont || !font.variableInstances) return [];
|
|
6173
6368
|
let variableInstances;
|
|
@@ -6182,14 +6377,7 @@ var parseVariableFontInstances = async (font, client) => {
|
|
|
6182
6377
|
const typeface = await client.fetch(
|
|
6183
6378
|
`*[_type == 'typeface' && title == $typefaceName][0]{
|
|
6184
6379
|
'fonts': styles.fonts[]-> {
|
|
6185
|
-
_id,
|
|
6186
|
-
title,
|
|
6187
|
-
subfamily,
|
|
6188
|
-
style,
|
|
6189
|
-
weight,
|
|
6190
|
-
weightName,
|
|
6191
|
-
metaData,
|
|
6192
|
-
variableFont
|
|
6380
|
+
_id, title, subfamily, style, weight, weightName, metaData, variableFont
|
|
6193
6381
|
}
|
|
6194
6382
|
}`,
|
|
6195
6383
|
{ typefaceName: font.typefaceName }
|
|
@@ -6201,127 +6389,49 @@ var parseVariableFontInstances = async (font, client) => {
|
|
|
6201
6389
|
console.warn("Typeface not found or no fonts in curated list, falling back to all fonts query");
|
|
6202
6390
|
staticFonts = await client.fetch(
|
|
6203
6391
|
`*[_type == 'font' && typefaceName == $typefaceName && variableFont != true]{
|
|
6204
|
-
_id,
|
|
6205
|
-
title,
|
|
6206
|
-
subfamily,
|
|
6207
|
-
style,
|
|
6208
|
-
weight,
|
|
6209
|
-
weightName,
|
|
6210
|
-
metaData
|
|
6392
|
+
_id, title, subfamily, style, weight, weightName, metaData
|
|
6211
6393
|
}`,
|
|
6212
6394
|
{ typefaceName: font.typefaceName }
|
|
6213
6395
|
);
|
|
6214
6396
|
}
|
|
6215
|
-
|
|
6216
|
-
console.log("
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6225
|
-
|
|
6226
|
-
|
|
6227
|
-
|
|
6228
|
-
|
|
6229
|
-
|
|
6230
|
-
|
|
6231
|
-
|
|
6232
|
-
|
|
6233
|
-
}
|
|
6234
|
-
if (variableName) {
|
|
6235
|
-
const words = variableName.split(/\s+/).map((w) => w.trim()).filter(Boolean);
|
|
6236
|
-
if (words.length > 0) {
|
|
6237
|
-
const regex = new RegExp(`\\b(${words.join("|")})\\b`, "gi");
|
|
6238
|
-
const stripped = fullName.replace(regex, "").replace(/\s{2,}/g, " ").trim();
|
|
6239
|
-
if (stripped !== "") fullName = stripped;
|
|
6240
|
-
}
|
|
6241
|
-
}
|
|
6242
|
-
if (fullName.startsWith(font.typefaceName)) {
|
|
6243
|
-
fullName = fullName.substring(font.typefaceName.length).trim();
|
|
6244
|
-
}
|
|
6245
|
-
if (((_d = sf.style) == null ? void 0 : _d.toLowerCase()) === "italic" && !fullName.toLowerCase().endsWith("italic") && !fullName.toLowerCase().endsWith("slanted")) {
|
|
6246
|
-
fullName = fullName + " Italic";
|
|
6247
|
-
}
|
|
6248
|
-
if (fullName.trim().toLowerCase().endsWith("regular")) {
|
|
6249
|
-
if (instanceName.trim().toLowerCase() + " regular" === fullName.trim().toLowerCase()) return true;
|
|
6250
|
-
}
|
|
6251
|
-
if (fullName.trim().toLowerCase().startsWith("regular")) {
|
|
6252
|
-
if ("regular " + instanceName.trim().toLowerCase() === fullName.trim().toLowerCase()) return true;
|
|
6253
|
-
}
|
|
6254
|
-
if (fullName.trim().toLowerCase().endsWith("italic")) {
|
|
6255
|
-
if (instanceName.trim().toLowerCase().endsWith("italic")) {
|
|
6256
|
-
const k = instanceName.trim().toLowerCase().slice(0, -6).trim() + " regular italic";
|
|
6257
|
-
if (k === fullName.trim().toLowerCase()) return true;
|
|
6258
|
-
}
|
|
6259
|
-
}
|
|
6260
|
-
return fullName.trim().toLowerCase() === instanceName.trim().toLowerCase();
|
|
6261
|
-
});
|
|
6262
|
-
}
|
|
6263
|
-
if (!matchingFont) {
|
|
6264
|
-
const expandedName = instanceName.split(" ").map((word) => expandAbbreviations(word)).join(" ");
|
|
6265
|
-
matchingFont = staticFonts.find((sf) => {
|
|
6266
|
-
const nameWithoutTypeface = sf.title.replace(font.typefaceName, "").trim();
|
|
6267
|
-
return nameWithoutTypeface === expandedName;
|
|
6268
|
-
});
|
|
6269
|
-
}
|
|
6270
|
-
if (!matchingFont) {
|
|
6271
|
-
const isItalic = instanceName.toLowerCase().includes("italic");
|
|
6272
|
-
const weightTerms = [
|
|
6273
|
-
{ term: "thin", weight: "100" },
|
|
6274
|
-
{ term: "extralight", weight: "200" },
|
|
6275
|
-
{ term: "extra light", weight: "200" },
|
|
6276
|
-
{ term: "light", weight: "300" },
|
|
6277
|
-
{ term: "regular", weight: "400" },
|
|
6278
|
-
{ term: "normal", weight: "400" },
|
|
6279
|
-
{ term: "medium", weight: "500" },
|
|
6280
|
-
{ term: "semibold", weight: "600" },
|
|
6281
|
-
{ term: "semi bold", weight: "600" },
|
|
6282
|
-
{ term: "bold", weight: "700" },
|
|
6283
|
-
{ term: "extrabold", weight: "800" },
|
|
6284
|
-
{ term: "extra bold", weight: "800" },
|
|
6285
|
-
{ term: "black", weight: "900" },
|
|
6286
|
-
{ term: "heavy", weight: "900" }
|
|
6287
|
-
];
|
|
6288
|
-
let instanceWeight = "400";
|
|
6289
|
-
for (const { term, weight } of weightTerms) {
|
|
6290
|
-
if (instanceName.toLowerCase().includes(term)) {
|
|
6291
|
-
instanceWeight = weight;
|
|
6292
|
-
break;
|
|
6293
|
-
}
|
|
6397
|
+
const instanceNames = Object.keys(variableInstances);
|
|
6398
|
+
console.log("Variable font instances:", instanceNames.length);
|
|
6399
|
+
console.log("Available static fonts:", staticFonts.length);
|
|
6400
|
+
const parsedInstances = instanceNames.map((name) => ({
|
|
6401
|
+
name,
|
|
6402
|
+
parsed: parseInstanceName(name)
|
|
6403
|
+
}));
|
|
6404
|
+
const results = /* @__PURE__ */ new Map();
|
|
6405
|
+
const claimedFontIds = /* @__PURE__ */ new Set();
|
|
6406
|
+
for (const strategy of STRATEGIES) {
|
|
6407
|
+
const unmatched = parsedInstances.filter((inst) => !results.has(inst.name));
|
|
6408
|
+
if (unmatched.length === 0) break;
|
|
6409
|
+
const passMatches = [];
|
|
6410
|
+
for (const inst of unmatched) {
|
|
6411
|
+
const subfamilyCandidates = filterBySubfamily(staticFonts, inst.parsed.subfamily, font.typefaceName).filter((sf) => !claimedFontIds.has(sf._id));
|
|
6412
|
+
const match = strategy.match(inst.name, inst.parsed, subfamilyCandidates, font.typefaceName, font);
|
|
6413
|
+
if (match) {
|
|
6414
|
+
passMatches.push({ instanceName: inst.name, font: match, strategy: strategy.name });
|
|
6294
6415
|
}
|
|
6295
|
-
matchingFont = staticFonts.find(
|
|
6296
|
-
(sf) => sf.weight === instanceWeight && (isItalic && sf.style === "Italic" || !isItalic && sf.style === "Regular")
|
|
6297
|
-
);
|
|
6298
|
-
}
|
|
6299
|
-
if (!matchingFont) {
|
|
6300
|
-
matchingFont = staticFonts.find((sf) => {
|
|
6301
|
-
if (!sf.weightName) return false;
|
|
6302
|
-
const cleanInstance = instanceName.toLowerCase().replace(/italic/i, "").trim();
|
|
6303
|
-
const cleanWeight = sf.weightName.toLowerCase().replace(/italic/i, "").trim();
|
|
6304
|
-
return cleanInstance === cleanWeight;
|
|
6305
|
-
});
|
|
6306
6416
|
}
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
var _a;
|
|
6313
|
-
if (!((_a = sf.metaData) == null ? void 0 : _a.fullName)) return false;
|
|
6314
|
-
const typefacePattern = new RegExp(`^${font.typefaceName}\\s+`, "i");
|
|
6315
|
-
const stylePart = sf.metaData.fullName.replace(typefacePattern, "").trim();
|
|
6316
|
-
return instanceName.toLowerCase() === stylePart.toLowerCase();
|
|
6317
|
-
});
|
|
6417
|
+
for (const m of passMatches) {
|
|
6418
|
+
if (!claimedFontIds.has(m.font._id) && !results.has(m.instanceName)) {
|
|
6419
|
+
results.set(m.instanceName, { fontId: m.font._id, strategy: m.strategy });
|
|
6420
|
+
claimedFontIds.add(m.font._id);
|
|
6421
|
+
}
|
|
6318
6422
|
}
|
|
6319
|
-
|
|
6320
|
-
|
|
6423
|
+
}
|
|
6424
|
+
const matched = [...results.values()].length;
|
|
6425
|
+
console.log(`[parseVariableFontInstances] Matched ${matched}/${instanceNames.length} instances across ${STRATEGIES.length} passes`);
|
|
6426
|
+
const instanceMappings = instanceNames.map((instanceName) => {
|
|
6427
|
+
const result = results.get(instanceName);
|
|
6428
|
+
const matchedFont = result ? staticFonts.find((sf) => sf._id === result.fontId) : null;
|
|
6429
|
+
console.log(`Instance "${instanceName}" \u2192 ${matchedFont ? `${matchedFont.title} (${result.strategy})` : "No match"}`);
|
|
6430
|
+
return {
|
|
6321
6431
|
key: instanceName,
|
|
6322
|
-
value:
|
|
6432
|
+
value: matchedFont ? { _type: "reference", _ref: matchedFont._id, _weak: true } : null,
|
|
6323
6433
|
_key: nanoid3()
|
|
6324
|
-
}
|
|
6434
|
+
};
|
|
6325
6435
|
});
|
|
6326
6436
|
return instanceMappings;
|
|
6327
6437
|
};
|
|
@@ -6332,9 +6442,20 @@ import { nanoid as nanoid4 } from "nanoid";
|
|
|
6332
6442
|
var updateTypefaceDocument = async (doc_id, fontRefs, variableRefs, subfamilies, uniqueSubfamilies, subfamiliesArray, preferredStyleRef, newPreferredStyle, stylesObject, client, setStatus, setError) => {
|
|
6333
6443
|
console.log("Updating typeface document with new fonts:", { fontRefs, variableRefs, subfamilies, uniqueSubfamilies });
|
|
6334
6444
|
setStatus("Updating typeface references...");
|
|
6445
|
+
const dedupeRefs = (existing, incoming) => {
|
|
6446
|
+
const merged = [...existing || []];
|
|
6447
|
+
const existingRefs = new Set(merged.map((r) => r._ref).filter(Boolean));
|
|
6448
|
+
incoming.forEach((ref) => {
|
|
6449
|
+
if (ref._ref && !existingRefs.has(ref._ref)) {
|
|
6450
|
+
merged.push(ref);
|
|
6451
|
+
existingRefs.add(ref._ref);
|
|
6452
|
+
}
|
|
6453
|
+
});
|
|
6454
|
+
return merged;
|
|
6455
|
+
};
|
|
6335
6456
|
let patch = {
|
|
6336
|
-
"styles.fonts": stylesObject.fonts
|
|
6337
|
-
"styles.variableFont": (stylesObject == null ? void 0 : stylesObject.variableFont
|
|
6457
|
+
"styles.fonts": dedupeRefs(stylesObject.fonts, fontRefs),
|
|
6458
|
+
"styles.variableFont": dedupeRefs(stylesObject == null ? void 0 : stylesObject.variableFont, variableRefs)
|
|
6338
6459
|
};
|
|
6339
6460
|
setStatus("Organising font subfamilies...");
|
|
6340
6461
|
subfamiliesArray = subfamiliesArray || [];
|
|
@@ -6539,7 +6660,7 @@ async function executeUploadPlan({
|
|
|
6539
6660
|
return result;
|
|
6540
6661
|
}
|
|
6541
6662
|
async function executeSingleFont({ entry, plan, client, progress, onProgress }) {
|
|
6542
|
-
var _a, _b, _c, _d
|
|
6663
|
+
var _a, _b, _c, _d;
|
|
6543
6664
|
const fontProgress = progress[entry.tempId];
|
|
6544
6665
|
fontProgress.status = EXECUTION_STATUS.UPLOADING_ASSETS;
|
|
6545
6666
|
if (onProgress) {
|
|
@@ -6656,7 +6777,7 @@ async function executeSingleFont({ entry, plan, client, progress, onProgress })
|
|
|
6656
6777
|
_key: nanoid5(),
|
|
6657
6778
|
title: entry.title,
|
|
6658
6779
|
slug: { _type: "slug", current: fontDocId },
|
|
6659
|
-
typefaceName:
|
|
6780
|
+
typefaceName: plan.settings.typefaceTitle || entry.title,
|
|
6660
6781
|
style: entry.style,
|
|
6661
6782
|
variableFont: entry.variableFont,
|
|
6662
6783
|
weightName: entry.weightName,
|
|
@@ -6667,7 +6788,6 @@ async function executeSingleFont({ entry, plan, client, progress, onProgress })
|
|
|
6667
6788
|
normalWeight: true,
|
|
6668
6789
|
fileInput
|
|
6669
6790
|
};
|
|
6670
|
-
fontDoc.typefaceName = ((_j = (_i = (_h = Object.values(plan.fonts)[0]) == null ? void 0 : _h.decisions) == null ? void 0 : _i.title) == null ? void 0 : _j.original) ? plan.settings.typefaceTitle || fontDoc.typefaceName : fontDoc.typefaceName;
|
|
6671
6791
|
if (entry.metaData) fontDoc.metaData = entry.metaData;
|
|
6672
6792
|
if (entry.metrics) fontDoc.metrics = entry.metrics;
|
|
6673
6793
|
if (entry.variableAxes) fontDoc.variableAxes = entry.variableAxes;
|
|
@@ -6896,14 +7016,299 @@ function UploadStep3Execute({
|
|
|
6896
7016
|
)))), execState.status !== "complete" && execState.status !== "error" && /* @__PURE__ */ React7.createElement(Card5, { tone: "caution", border: true, radius: 2, padding: 2 }, /* @__PURE__ */ React7.createElement(Flex7, { align: "center", gap: 2 }, /* @__PURE__ */ React7.createElement(WarningOutlineIcon, { style: { flexShrink: 0 } }), /* @__PURE__ */ React7.createElement(Text7, { size: 1, weight: "semibold" }, "Do not close or reload this tab"))), /* @__PURE__ */ React7.createElement(Box6, { style: { maxHeight: 400, overflowY: "auto" } }, /* @__PURE__ */ React7.createElement(Stack5, { space: 1 }, fontEntries.map((entry) => {
|
|
6897
7017
|
const progress = execState.progress[entry.tempId];
|
|
6898
7018
|
const status = (progress == null ? void 0 : progress.status) || EXECUTION_STATUS.QUEUED;
|
|
6899
|
-
return /* @__PURE__ */ React7.createElement(Card5, { key: entry.tempId, border: true, radius: 1, padding: 2 }, /* @__PURE__ */ React7.createElement(Flex7, { align: "center", gap: 2 }, /* @__PURE__ */ React7.createElement(Text7, { size: 1, style: {
|
|
7019
|
+
return /* @__PURE__ */ React7.createElement(Card5, { key: entry.tempId, border: true, radius: 1, padding: 2 }, /* @__PURE__ */ React7.createElement(Flex7, { align: "center", gap: 2 }, /* @__PURE__ */ React7.createElement(Text7, { size: 1, style: { flex: 1 } }, entry.title), /* @__PURE__ */ React7.createElement(Box6, { style: { width: 120, flexShrink: 0, textAlign: "right" } }, status === EXECUTION_STATUS.QUEUED && /* @__PURE__ */ React7.createElement(Badge5, { mode: "outline", fontSize: 0 }, "Queued"), status === EXECUTION_STATUS.UPLOADING_ASSETS && /* @__PURE__ */ React7.createElement(Flex7, { gap: 1, align: "center", justify: "flex-end" }, /* @__PURE__ */ React7.createElement(Text7, { size: 0, muted: true }, (progress == null ? void 0 : progress.currentFile) || "Uploading..."), /* @__PURE__ */ React7.createElement(Spinner2, { style: { width: 12, height: 12 } })), (status === EXECUTION_STATUS.GENERATING_CSS || status === EXECUTION_STATUS.GENERATING_METADATA) && /* @__PURE__ */ React7.createElement(Flex7, { gap: 1, align: "center", justify: "flex-end" }, /* @__PURE__ */ React7.createElement(Text7, { size: 0, muted: true }, status === EXECUTION_STATUS.GENERATING_CSS ? "CSS" : "Metadata"), /* @__PURE__ */ React7.createElement(Spinner2, { style: { width: 12, height: 12 } })), status === EXECUTION_STATUS.CREATING_DOCUMENT && /* @__PURE__ */ React7.createElement(Flex7, { gap: 1, align: "center", justify: "flex-end" }, /* @__PURE__ */ React7.createElement(Text7, { size: 0, muted: true }, "Creating doc"), /* @__PURE__ */ React7.createElement(Spinner2, { style: { width: 12, height: 12 } })), status === EXECUTION_STATUS.COMPLETE && /* @__PURE__ */ React7.createElement(Badge5, { tone: "positive", fontSize: 0 }, "Done"), status === EXECUTION_STATUS.ERROR && /* @__PURE__ */ React7.createElement(Badge5, { tone: "critical", fontSize: 0 }, "Failed"))), status === EXECUTION_STATUS.ERROR && (progress == null ? void 0 : progress.error) && /* @__PURE__ */ React7.createElement(Text7, { size: 0, muted: true, style: { marginTop: 4 } }, progress.error));
|
|
6900
7020
|
}))), execState.error && /* @__PURE__ */ React7.createElement(Card5, { tone: "critical", border: true, padding: 3, radius: 2 }, /* @__PURE__ */ React7.createElement(Text7, { size: 1 }, execState.error)));
|
|
6901
7021
|
}
|
|
6902
7022
|
|
|
7023
|
+
// src/components/UploadStep3bInstances.jsx
|
|
7024
|
+
import React8, { useState as useState5, useEffect as useEffect4, useCallback as useCallback4, useMemo as useMemo6 } from "react";
|
|
7025
|
+
import { Box as Box7, Stack as Stack6, Flex as Flex8, Text as Text8, Card as Card6, Badge as Badge6, Button as Button6, Spinner as Spinner3, Autocomplete } from "@sanity/ui";
|
|
7026
|
+
import { CheckmarkCircleIcon as CheckmarkCircleIcon2, CloseCircleIcon, SearchIcon as SearchIcon2 } from "@sanity/icons";
|
|
7027
|
+
import { nanoid as nanoid6 } from "nanoid";
|
|
7028
|
+
function UploadStep3bInstances({
|
|
7029
|
+
plan,
|
|
7030
|
+
executionResult,
|
|
7031
|
+
client,
|
|
7032
|
+
typefaceTitle,
|
|
7033
|
+
onComplete
|
|
7034
|
+
}) {
|
|
7035
|
+
const [loading, setLoading] = useState5(true);
|
|
7036
|
+
const [saving, setSaving] = useState5(false);
|
|
7037
|
+
const [vfMappings, setVfMappings] = useState5({});
|
|
7038
|
+
const [allStaticFonts, setAllStaticFonts] = useState5([]);
|
|
7039
|
+
const [filterUnmatched, setFilterUnmatched] = useState5(false);
|
|
7040
|
+
const vfEntries = useMemo6(
|
|
7041
|
+
() => Object.values(plan.fonts).filter((f) => f.variableFont && f.status !== "error"),
|
|
7042
|
+
[plan.fonts]
|
|
7043
|
+
);
|
|
7044
|
+
const runMatching = useCallback4(async () => {
|
|
7045
|
+
var _a;
|
|
7046
|
+
setLoading(true);
|
|
7047
|
+
const mappings = {};
|
|
7048
|
+
let staticFonts = [];
|
|
7049
|
+
try {
|
|
7050
|
+
const typeface = await client.fetch(
|
|
7051
|
+
`*[_type == 'typeface' && title == $typefaceTitle][0]{
|
|
7052
|
+
'fonts': styles.fonts[]-> {
|
|
7053
|
+
_id, title, subfamily, style, weight, weightName, metaData, variableFont
|
|
7054
|
+
}
|
|
7055
|
+
}`,
|
|
7056
|
+
{ typefaceTitle }
|
|
7057
|
+
);
|
|
7058
|
+
if (((_a = typeface == null ? void 0 : typeface.fonts) == null ? void 0 : _a.length) > 0) {
|
|
7059
|
+
staticFonts = typeface.fonts.filter((f) => !f.variableFont);
|
|
7060
|
+
}
|
|
7061
|
+
if (staticFonts.length === 0) {
|
|
7062
|
+
staticFonts = await client.fetch(
|
|
7063
|
+
`*[_type == 'font' && typefaceName == $typefaceTitle && variableFont != true]{
|
|
7064
|
+
_id, title, subfamily, style, weight, weightName, metaData
|
|
7065
|
+
}`,
|
|
7066
|
+
{ typefaceTitle }
|
|
7067
|
+
);
|
|
7068
|
+
}
|
|
7069
|
+
} catch (err) {
|
|
7070
|
+
console.error("[InstanceMapper] Failed to fetch static fonts:", err);
|
|
7071
|
+
}
|
|
7072
|
+
const deduped = /* @__PURE__ */ new Map();
|
|
7073
|
+
staticFonts.forEach((f) => {
|
|
7074
|
+
if (f._id && !deduped.has(f._id)) deduped.set(f._id, f);
|
|
7075
|
+
});
|
|
7076
|
+
staticFonts = [...deduped.values()];
|
|
7077
|
+
console.log(`[InstanceMapper] Found ${staticFonts.length} static fonts for "${typefaceTitle}"`);
|
|
7078
|
+
setAllStaticFonts(staticFonts);
|
|
7079
|
+
for (const vf of vfEntries) {
|
|
7080
|
+
try {
|
|
7081
|
+
const vfDoc = await client.fetch(
|
|
7082
|
+
`*[_id == $id][0]{
|
|
7083
|
+
_id, title, typefaceName, variableFont, variableInstances, metaData
|
|
7084
|
+
}`,
|
|
7085
|
+
{ id: vf.documentId }
|
|
7086
|
+
);
|
|
7087
|
+
if (!vfDoc) {
|
|
7088
|
+
console.warn(`[InstanceMapper] VF document not found: ${vf.documentId}`);
|
|
7089
|
+
mappings[vf.tempId] = [];
|
|
7090
|
+
continue;
|
|
7091
|
+
}
|
|
7092
|
+
console.log(`[InstanceMapper] Running matcher for VF: ${vfDoc.title}, variableInstances: ${vfDoc.variableInstances ? "present" : "missing"}`);
|
|
7093
|
+
const instanceMappings = await parseVariableFontInstances(vfDoc, client);
|
|
7094
|
+
console.log(`[InstanceMapper] Matched ${instanceMappings.filter((m) => m.value).length}/${instanceMappings.length} instances for ${vfDoc.title}`);
|
|
7095
|
+
mappings[vf.tempId] = instanceMappings.map((m) => {
|
|
7096
|
+
var _a2;
|
|
7097
|
+
return {
|
|
7098
|
+
instanceName: m.key,
|
|
7099
|
+
matchedFontId: ((_a2 = m.value) == null ? void 0 : _a2._ref) || "",
|
|
7100
|
+
matchedFontTitle: "",
|
|
7101
|
+
_key: m._key || nanoid6()
|
|
7102
|
+
};
|
|
7103
|
+
});
|
|
7104
|
+
} catch (err) {
|
|
7105
|
+
console.error(`[InstanceMapper] Error matching VF ${vf.documentId}:`, err);
|
|
7106
|
+
mappings[vf.tempId] = [];
|
|
7107
|
+
}
|
|
7108
|
+
}
|
|
7109
|
+
const allMatchedIds = /* @__PURE__ */ new Set();
|
|
7110
|
+
Object.values(mappings).forEach((m) => m.forEach((i) => {
|
|
7111
|
+
if (i.matchedFontId) allMatchedIds.add(i.matchedFontId);
|
|
7112
|
+
}));
|
|
7113
|
+
if (allMatchedIds.size > 0) {
|
|
7114
|
+
try {
|
|
7115
|
+
const titles = await client.fetch(`*[_id in $ids]{ _id, title }`, { ids: [...allMatchedIds] });
|
|
7116
|
+
const titleMap = {};
|
|
7117
|
+
titles.forEach((t) => {
|
|
7118
|
+
titleMap[t._id] = t.title;
|
|
7119
|
+
});
|
|
7120
|
+
Object.values(mappings).forEach((m) => {
|
|
7121
|
+
m.forEach((i) => {
|
|
7122
|
+
if (i.matchedFontId) i.matchedFontTitle = titleMap[i.matchedFontId] || i.matchedFontId;
|
|
7123
|
+
});
|
|
7124
|
+
});
|
|
7125
|
+
} catch (err) {
|
|
7126
|
+
console.warn("[InstanceMapper] Failed to resolve font titles:", err);
|
|
7127
|
+
}
|
|
7128
|
+
}
|
|
7129
|
+
setVfMappings(mappings);
|
|
7130
|
+
setLoading(false);
|
|
7131
|
+
}, [vfEntries, client, typefaceTitle]);
|
|
7132
|
+
useEffect4(() => {
|
|
7133
|
+
runMatching();
|
|
7134
|
+
}, [runMatching]);
|
|
7135
|
+
const claimedFontIds = useMemo6(() => {
|
|
7136
|
+
const claimed = /* @__PURE__ */ new Set();
|
|
7137
|
+
Object.values(vfMappings).forEach((mappings) => {
|
|
7138
|
+
mappings.forEach((m) => {
|
|
7139
|
+
if (m.matchedFontId) claimed.add(m.matchedFontId);
|
|
7140
|
+
});
|
|
7141
|
+
});
|
|
7142
|
+
return claimed;
|
|
7143
|
+
}, [vfMappings]);
|
|
7144
|
+
const handleMappingChange = useCallback4((vfTempId, instanceKey, fontId) => {
|
|
7145
|
+
const font = allStaticFonts.find((sf) => sf._id === fontId);
|
|
7146
|
+
setVfMappings((prev) => ({
|
|
7147
|
+
...prev,
|
|
7148
|
+
[vfTempId]: prev[vfTempId].map(
|
|
7149
|
+
(m) => m._key === instanceKey ? { ...m, matchedFontId: fontId, matchedFontTitle: (font == null ? void 0 : font.title) || fontId } : m
|
|
7150
|
+
)
|
|
7151
|
+
}));
|
|
7152
|
+
}, [allStaticFonts]);
|
|
7153
|
+
const handleSave = useCallback4(async () => {
|
|
7154
|
+
setSaving(true);
|
|
7155
|
+
const errors = [];
|
|
7156
|
+
for (const vf of vfEntries) {
|
|
7157
|
+
const mappings = vfMappings[vf.tempId] || [];
|
|
7158
|
+
const references = mappings.filter((m) => m.matchedFontId).map((m) => ({
|
|
7159
|
+
_key: nanoid6(),
|
|
7160
|
+
_type: "object",
|
|
7161
|
+
key: m.instanceName,
|
|
7162
|
+
value: {
|
|
7163
|
+
_type: "reference",
|
|
7164
|
+
_ref: m.matchedFontId,
|
|
7165
|
+
_weak: true
|
|
7166
|
+
}
|
|
7167
|
+
}));
|
|
7168
|
+
try {
|
|
7169
|
+
await client.patch(vf.documentId).set({
|
|
7170
|
+
variableInstanceReferences: references
|
|
7171
|
+
}).commit();
|
|
7172
|
+
console.log(`Patched VF instance mappings: ${vf.documentId} (${references.length} instances)`);
|
|
7173
|
+
} catch (err) {
|
|
7174
|
+
console.error(`Failed to patch VF ${vf.documentId}:`, err);
|
|
7175
|
+
errors.push({ vfTitle: vf.title, error: err.message });
|
|
7176
|
+
}
|
|
7177
|
+
}
|
|
7178
|
+
setSaving(false);
|
|
7179
|
+
onComplete({ success: errors.length === 0, errors });
|
|
7180
|
+
}, [vfEntries, vfMappings, client, onComplete]);
|
|
7181
|
+
const totalInstances = Object.values(vfMappings).reduce((sum, m) => sum + m.length, 0);
|
|
7182
|
+
const matchedInstances = Object.values(vfMappings).reduce(
|
|
7183
|
+
(sum, m) => sum + m.filter((i) => i.matchedFontId).length,
|
|
7184
|
+
0
|
|
7185
|
+
);
|
|
7186
|
+
const unmatchedInstances = totalInstances - matchedInstances;
|
|
7187
|
+
const getAutocompleteOptions = useCallback4((currentFontId) => {
|
|
7188
|
+
return allStaticFonts.filter((sf) => !claimedFontIds.has(sf._id) || sf._id === currentFontId).map((sf) => ({
|
|
7189
|
+
value: sf._id,
|
|
7190
|
+
payload: sf
|
|
7191
|
+
}));
|
|
7192
|
+
}, [allStaticFonts, claimedFontIds]);
|
|
7193
|
+
if (loading) {
|
|
7194
|
+
return /* @__PURE__ */ React8.createElement(Card6, { border: true, padding: 4, radius: 2 }, /* @__PURE__ */ React8.createElement(Flex8, { align: "center", gap: 3, justify: "center" }, /* @__PURE__ */ React8.createElement(Spinner3, null), /* @__PURE__ */ React8.createElement(Text8, { size: 1 }, "Matching variable font instances to static fonts...")));
|
|
7195
|
+
}
|
|
7196
|
+
if (vfEntries.length === 0) {
|
|
7197
|
+
onComplete({ success: true, errors: [] });
|
|
7198
|
+
return null;
|
|
7199
|
+
}
|
|
7200
|
+
return /* @__PURE__ */ React8.createElement(Stack6, { space: 4 }, /* @__PURE__ */ React8.createElement(Stack6, { space: 2 }, /* @__PURE__ */ React8.createElement(Text8, { size: 2, weight: "semibold" }, "Map Variable Font Instances"), /* @__PURE__ */ React8.createElement(Text8, { size: 1, muted: true }, "Review the auto-matched instances below. Each named instance should map to its corresponding static font document.")), /* @__PURE__ */ React8.createElement(Flex8, { gap: 2, align: "center" }, /* @__PURE__ */ React8.createElement(
|
|
7201
|
+
Button6,
|
|
7202
|
+
{
|
|
7203
|
+
mode: "ghost",
|
|
7204
|
+
tone: "primary",
|
|
7205
|
+
icon: SearchIcon2,
|
|
7206
|
+
text: "Re-run Matching",
|
|
7207
|
+
fontSize: 0,
|
|
7208
|
+
padding: 2,
|
|
7209
|
+
onClick: runMatching,
|
|
7210
|
+
disabled: loading,
|
|
7211
|
+
style: { cursor: "pointer" }
|
|
7212
|
+
}
|
|
7213
|
+
), /* @__PURE__ */ React8.createElement(Badge6, { tone: "positive", fontSize: 0 }, matchedInstances, " matched"), unmatchedInstances > 0 && /* @__PURE__ */ React8.createElement(
|
|
7214
|
+
Badge6,
|
|
7215
|
+
{
|
|
7216
|
+
tone: "critical",
|
|
7217
|
+
fontSize: 0,
|
|
7218
|
+
style: { cursor: "pointer" },
|
|
7219
|
+
onClick: () => setFilterUnmatched((v) => !v)
|
|
7220
|
+
},
|
|
7221
|
+
unmatchedInstances,
|
|
7222
|
+
" unmatched ",
|
|
7223
|
+
filterUnmatched ? "(showing)" : ""
|
|
7224
|
+
), filterUnmatched && /* @__PURE__ */ React8.createElement(
|
|
7225
|
+
Badge6,
|
|
7226
|
+
{
|
|
7227
|
+
mode: "outline",
|
|
7228
|
+
fontSize: 0,
|
|
7229
|
+
style: { cursor: "pointer" },
|
|
7230
|
+
onClick: () => setFilterUnmatched(false)
|
|
7231
|
+
},
|
|
7232
|
+
"Clear filter"
|
|
7233
|
+
), /* @__PURE__ */ React8.createElement(Badge6, { mode: "outline", fontSize: 0 }, allStaticFonts.length, " fonts available")), vfEntries.map((vf) => {
|
|
7234
|
+
const mappings = vfMappings[vf.tempId] || [];
|
|
7235
|
+
const displayMappings = filterUnmatched ? mappings.filter((m) => !m.matchedFontId) : mappings;
|
|
7236
|
+
const vfMatched = mappings.filter((m) => m.matchedFontId).length;
|
|
7237
|
+
return /* @__PURE__ */ React8.createElement(Card6, { key: vf.tempId, border: true, padding: 3, radius: 2 }, /* @__PURE__ */ React8.createElement(Stack6, { space: 3 }, /* @__PURE__ */ React8.createElement(Flex8, { align: "center", gap: 2 }, /* @__PURE__ */ React8.createElement(Badge6, { tone: "primary", fontSize: 0 }, "VF"), /* @__PURE__ */ React8.createElement(Text8, { size: 1, weight: "semibold" }, vf.title), /* @__PURE__ */ React8.createElement(Text8, { size: 0, muted: true, style: { marginLeft: "auto" } }, vfMatched, "/", mappings.length, " matched")), /* @__PURE__ */ React8.createElement(Flex8, { align: "center", gap: 2, paddingY: 1, style: { borderBottom: "1px solid var(--card-border-color)" } }, /* @__PURE__ */ React8.createElement(Box7, { style: { width: 20 } }), /* @__PURE__ */ React8.createElement(Text8, { size: 0, weight: "semibold", muted: true, style: { flex: 1 } }, "Instance"), /* @__PURE__ */ React8.createElement(Text8, { size: 0, weight: "semibold", muted: true, style: { flex: 2 } }, "Static Font Document")), /* @__PURE__ */ React8.createElement(Stack6, { space: 1 }, displayMappings.map((mapping) => {
|
|
7238
|
+
const isMatched = !!mapping.matchedFontId;
|
|
7239
|
+
const options = getAutocompleteOptions(mapping.matchedFontId);
|
|
7240
|
+
return /* @__PURE__ */ React8.createElement(
|
|
7241
|
+
Flex8,
|
|
7242
|
+
{
|
|
7243
|
+
key: mapping._key,
|
|
7244
|
+
align: "center",
|
|
7245
|
+
gap: 2,
|
|
7246
|
+
paddingY: 2,
|
|
7247
|
+
style: { borderBottom: "1px solid var(--card-border-color)" }
|
|
7248
|
+
},
|
|
7249
|
+
/* @__PURE__ */ React8.createElement(Box7, { style: { width: 20, flexShrink: 0 } }, isMatched ? /* @__PURE__ */ React8.createElement(CheckmarkCircleIcon2, { style: { color: "#43b649", fontSize: 16 } }) : /* @__PURE__ */ React8.createElement(CloseCircleIcon, { style: { color: "#f03e2f", fontSize: 16 } })),
|
|
7250
|
+
/* @__PURE__ */ React8.createElement(Text8, { size: 1, style: { flex: 1, whiteSpace: "nowrap" } }, mapping.instanceName),
|
|
7251
|
+
/* @__PURE__ */ React8.createElement(Box7, { style: { flex: 2 } }, /* @__PURE__ */ React8.createElement(
|
|
7252
|
+
Autocomplete,
|
|
7253
|
+
{
|
|
7254
|
+
id: `instance-${mapping._key}`,
|
|
7255
|
+
options,
|
|
7256
|
+
value: mapping.matchedFontId,
|
|
7257
|
+
placeholder: "Search for a font...",
|
|
7258
|
+
icon: SearchIcon2,
|
|
7259
|
+
fontSize: 1,
|
|
7260
|
+
filterOption: (query, option) => {
|
|
7261
|
+
var _a, _b, _c, _d;
|
|
7262
|
+
const sf = option.payload;
|
|
7263
|
+
const q = query.toLowerCase();
|
|
7264
|
+
return ((_a = sf.title) == null ? void 0 : _a.toLowerCase().includes(q)) || ((_b = sf._id) == null ? void 0 : _b.toLowerCase().includes(q)) || ((_c = sf.weightName) == null ? void 0 : _c.toLowerCase().includes(q)) || String(sf.weight).includes(q) || ((_d = sf.subfamily) == null ? void 0 : _d.toLowerCase().includes(q));
|
|
7265
|
+
},
|
|
7266
|
+
renderOption: (option) => {
|
|
7267
|
+
const sf = option.payload;
|
|
7268
|
+
const isClaimed = claimedFontIds.has(sf._id) && sf._id !== mapping.matchedFontId;
|
|
7269
|
+
return /* @__PURE__ */ React8.createElement(Card6, { as: "button", padding: 2, style: { opacity: isClaimed ? 0.4 : 1 } }, /* @__PURE__ */ React8.createElement(Flex8, { align: "center", gap: 2 }, /* @__PURE__ */ React8.createElement(Text8, { size: 1 }, sf.title), /* @__PURE__ */ React8.createElement(Text8, { size: 0, muted: true }, sf.weight, " ", sf.style), sf.subfamily && sf.subfamily !== "Regular" && /* @__PURE__ */ React8.createElement(Badge6, { mode: "outline", fontSize: 0 }, sf.subfamily)));
|
|
7270
|
+
},
|
|
7271
|
+
renderValue: (value, option) => {
|
|
7272
|
+
if (option == null ? void 0 : option.payload) return option.payload.title;
|
|
7273
|
+
if (mapping.matchedFontTitle) return mapping.matchedFontTitle;
|
|
7274
|
+
const font = allStaticFonts.find((sf) => sf._id === value);
|
|
7275
|
+
return (font == null ? void 0 : font.title) || value;
|
|
7276
|
+
},
|
|
7277
|
+
onSelect: (value) => handleMappingChange(vf.tempId, mapping._key, value),
|
|
7278
|
+
openButton: true
|
|
7279
|
+
}
|
|
7280
|
+
))
|
|
7281
|
+
);
|
|
7282
|
+
})), mappings.length === 0 && /* @__PURE__ */ React8.createElement(Text8, { size: 1, muted: true }, "No named instances found in this variable font.")));
|
|
7283
|
+
}), /* @__PURE__ */ React8.createElement(Flex8, { justify: "flex-end", gap: 2, style: { position: "sticky", bottom: 0, background: "var(--card-bg-color)", paddingTop: 8, paddingBottom: 4 } }, /* @__PURE__ */ React8.createElement(
|
|
7284
|
+
Button6,
|
|
7285
|
+
{
|
|
7286
|
+
mode: "ghost",
|
|
7287
|
+
text: "Skip \u2014 I'll map instances later",
|
|
7288
|
+
fontSize: 1,
|
|
7289
|
+
padding: 3,
|
|
7290
|
+
onClick: () => onComplete({ success: true, errors: [], skipped: true }),
|
|
7291
|
+
style: { cursor: "pointer" }
|
|
7292
|
+
}
|
|
7293
|
+
), /* @__PURE__ */ React8.createElement(
|
|
7294
|
+
Button6,
|
|
7295
|
+
{
|
|
7296
|
+
mode: "default",
|
|
7297
|
+
tone: "positive",
|
|
7298
|
+
text: saving ? "Saving..." : `Save Mappings (${matchedInstances}/${totalInstances})`,
|
|
7299
|
+
fontSize: 1,
|
|
7300
|
+
padding: 3,
|
|
7301
|
+
disabled: saving,
|
|
7302
|
+
onClick: handleSave,
|
|
7303
|
+
style: { cursor: "pointer" }
|
|
7304
|
+
}
|
|
7305
|
+
)));
|
|
7306
|
+
}
|
|
7307
|
+
|
|
6903
7308
|
// src/components/UploadSummary.jsx
|
|
6904
|
-
import
|
|
6905
|
-
import { Stack as
|
|
6906
|
-
import { CheckmarkCircleIcon as
|
|
7309
|
+
import React9, { useState as useState6, useCallback as useCallback5 } from "react";
|
|
7310
|
+
import { Stack as Stack7, Flex as Flex9, Text as Text9, Card as Card7, Badge as Badge7, Button as Button7, Box as Box8, Spinner as Spinner4 } from "@sanity/ui";
|
|
7311
|
+
import { CheckmarkCircleIcon as CheckmarkCircleIcon3, WarningOutlineIcon as WarningOutlineIcon2, ResetIcon as ResetIcon2 } from "@sanity/icons";
|
|
6907
7312
|
function UploadSummary({
|
|
6908
7313
|
plan,
|
|
6909
7314
|
result,
|
|
@@ -6915,12 +7320,12 @@ function UploadSummary({
|
|
|
6915
7320
|
preferredStyleRef
|
|
6916
7321
|
}) {
|
|
6917
7322
|
var _a;
|
|
6918
|
-
const [retryingPatch, setRetryingPatch] =
|
|
6919
|
-
const [patchRetryResult, setPatchRetryResult] =
|
|
7323
|
+
const [retryingPatch, setRetryingPatch] = useState6(false);
|
|
7324
|
+
const [patchRetryResult, setPatchRetryResult] = useState6(null);
|
|
6920
7325
|
const hasFailedFonts = ((_a = result == null ? void 0 : result.failedFonts) == null ? void 0 : _a.length) > 0;
|
|
6921
7326
|
const hasTypefacePatchError = (result == null ? void 0 : result.typefacePatchError) && !(patchRetryResult == null ? void 0 : patchRetryResult.success);
|
|
6922
7327
|
const allSuccess = (result == null ? void 0 : result.success) && !hasTypefacePatchError;
|
|
6923
|
-
const handleRetryTypefacePatch =
|
|
7328
|
+
const handleRetryTypefacePatch = useCallback5(async () => {
|
|
6924
7329
|
var _a2, _b;
|
|
6925
7330
|
if (!result || !client || !docId) return;
|
|
6926
7331
|
setRetryingPatch(true);
|
|
@@ -6956,11 +7361,11 @@ function UploadSummary({
|
|
|
6956
7361
|
}
|
|
6957
7362
|
setRetryingPatch(false);
|
|
6958
7363
|
}, [result, client, docId, plan, stylesObject, preferredStyleRef]);
|
|
6959
|
-
return /* @__PURE__ */
|
|
7364
|
+
return /* @__PURE__ */ React9.createElement(Stack7, { space: 4 }, /* @__PURE__ */ React9.createElement(Flex9, { align: "center", gap: 3, ref: (el) => {
|
|
6960
7365
|
var _a2;
|
|
6961
7366
|
return (_a2 = el == null ? void 0 : el.focus) == null ? void 0 : _a2.call(el);
|
|
6962
|
-
}, tabIndex: -1 }, allSuccess ? /* @__PURE__ */
|
|
6963
|
-
|
|
7367
|
+
}, tabIndex: -1 }, allSuccess ? /* @__PURE__ */ React9.createElement(CheckmarkCircleIcon3, { style: { color: "#43b649", fontSize: 28 } }) : /* @__PURE__ */ React9.createElement(WarningOutlineIcon2, { style: { color: "#f03e2f", fontSize: 28 } }), /* @__PURE__ */ React9.createElement(Text9, { size: 2, weight: "semibold" }, allSuccess ? "Upload Complete" : "Upload Completed with Issues")), result && /* @__PURE__ */ React9.createElement(Card7, { border: true, padding: 4, radius: 2 }, /* @__PURE__ */ React9.createElement(Stack7, { space: 3 }, /* @__PURE__ */ React9.createElement(Flex9, { gap: 2, wrap: "wrap" }, result.created > 0 && /* @__PURE__ */ React9.createElement(Badge7, { tone: "positive", fontSize: 1 }, result.created, " created"), result.updated > 0 && /* @__PURE__ */ React9.createElement(Badge7, { tone: "caution", fontSize: 1 }, result.updated, " updated"), result.failed > 0 && /* @__PURE__ */ React9.createElement(Badge7, { tone: "critical", fontSize: 1 }, result.failed, " failed"), result.skipped > 0 && /* @__PURE__ */ React9.createElement(Badge7, { mode: "outline", fontSize: 1 }, result.skipped, " skipped")))), hasFailedFonts && /* @__PURE__ */ React9.createElement(Stack7, { space: 3 }, /* @__PURE__ */ React9.createElement(Flex9, { align: "center", justify: "space-between" }, /* @__PURE__ */ React9.createElement(Flex9, { align: "center", gap: 2 }, /* @__PURE__ */ React9.createElement(Text9, { size: 1, weight: "semibold" }, "Failed Fonts"), /* @__PURE__ */ React9.createElement(Badge7, { tone: "critical", fontSize: 0 }, result.failedFonts.length)), /* @__PURE__ */ React9.createElement(
|
|
7368
|
+
Button7,
|
|
6964
7369
|
{
|
|
6965
7370
|
mode: "ghost",
|
|
6966
7371
|
tone: "primary",
|
|
@@ -6970,8 +7375,8 @@ function UploadSummary({
|
|
|
6970
7375
|
padding: 2,
|
|
6971
7376
|
onClick: () => onRetry(result.failedFonts.map((f) => f.tempId).filter(Boolean))
|
|
6972
7377
|
}
|
|
6973
|
-
)), /* @__PURE__ */
|
|
6974
|
-
|
|
7378
|
+
)), /* @__PURE__ */ React9.createElement(Stack7, { space: 2 }, result.failedFonts.map((f, i) => /* @__PURE__ */ React9.createElement(Card7, { key: i, tone: "critical", border: true, padding: 3, radius: 2 }, /* @__PURE__ */ React9.createElement(Stack7, { space: 2 }, /* @__PURE__ */ React9.createElement(Flex9, { align: "center", gap: 2 }, /* @__PURE__ */ React9.createElement(Text9, { size: 1, weight: "semibold" }, f.title), f.failedAt && f.failedAt !== "unknown" && /* @__PURE__ */ React9.createElement(Badge7, { tone: "critical", fontSize: 0, mode: "outline" }, "Failed at: ", f.failedAt)), /* @__PURE__ */ React9.createElement(Text9, { size: 1 }, f.error)))))), hasTypefacePatchError && /* @__PURE__ */ React9.createElement(Card7, { tone: "caution", border: true, padding: 4, radius: 2 }, /* @__PURE__ */ React9.createElement(Stack7, { space: 3 }, /* @__PURE__ */ React9.createElement(Text9, { size: 1, weight: "semibold" }, "Typeface Document Not Updated"), /* @__PURE__ */ React9.createElement(Text9, { size: 1 }, result.created + result.updated, " font document", result.created + result.updated === 1 ? "" : "s", " created/updated successfully, but the typeface document could not be patched to reference them."), /* @__PURE__ */ React9.createElement(Text9, { size: 1, muted: true }, result.typefacePatchError), /* @__PURE__ */ React9.createElement(Flex9, { gap: 2 }, /* @__PURE__ */ React9.createElement(
|
|
7379
|
+
Button7,
|
|
6975
7380
|
{
|
|
6976
7381
|
mode: "default",
|
|
6977
7382
|
tone: "primary",
|
|
@@ -6980,8 +7385,8 @@ function UploadSummary({
|
|
|
6980
7385
|
disabled: retryingPatch,
|
|
6981
7386
|
onClick: handleRetryTypefacePatch
|
|
6982
7387
|
}
|
|
6983
|
-
), retryingPatch && /* @__PURE__ */
|
|
6984
|
-
|
|
7388
|
+
), retryingPatch && /* @__PURE__ */ React9.createElement(Spinner4, null)))), (patchRetryResult == null ? void 0 : patchRetryResult.success) && /* @__PURE__ */ React9.createElement(Card7, { tone: "positive", border: true, padding: 3, radius: 2 }, /* @__PURE__ */ React9.createElement(Text9, { size: 1 }, "Typeface document updated successfully on retry.")), patchRetryResult && !patchRetryResult.success && /* @__PURE__ */ React9.createElement(Card7, { tone: "critical", border: true, padding: 3, radius: 2 }, /* @__PURE__ */ React9.createElement(Text9, { size: 1 }, "Retry failed: ", patchRetryResult.error)), /* @__PURE__ */ React9.createElement(Flex9, { justify: "flex-end" }, /* @__PURE__ */ React9.createElement(
|
|
7389
|
+
Button7,
|
|
6985
7390
|
{
|
|
6986
7391
|
mode: "default",
|
|
6987
7392
|
tone: "primary",
|
|
@@ -6995,7 +7400,8 @@ function UploadSummary({
|
|
|
6995
7400
|
var STEPS = [
|
|
6996
7401
|
{ key: 1, label: "Upload Files" },
|
|
6997
7402
|
{ key: 2, label: "Review" },
|
|
6998
|
-
{ key: 3, label: "Upload" }
|
|
7403
|
+
{ key: 3, label: "Upload" },
|
|
7404
|
+
{ key: 4, label: "Map Instances" }
|
|
6999
7405
|
];
|
|
7000
7406
|
function phaseToStep(phase) {
|
|
7001
7407
|
switch (phase) {
|
|
@@ -7028,15 +7434,22 @@ function UploadModal({
|
|
|
7028
7434
|
slug
|
|
7029
7435
|
}) {
|
|
7030
7436
|
const [plan, dispatch] = useReducer2(planReducer, null, () => createEmptyPlan());
|
|
7031
|
-
const [processingCancelled, setProcessingCancelled] =
|
|
7032
|
-
const [executionResult, setExecutionResult] =
|
|
7033
|
-
const [retryTempIds, setRetryTempIds] =
|
|
7437
|
+
const [processingCancelled, setProcessingCancelled] = useState7(false);
|
|
7438
|
+
const [executionResult, setExecutionResult] = useState7(null);
|
|
7439
|
+
const [retryTempIds, setRetryTempIds] = useState7(null);
|
|
7440
|
+
const [instanceMappingPhase, setInstanceMappingPhase] = useState7(false);
|
|
7441
|
+
const [instanceMappingResult, setInstanceMappingResult] = useState7(null);
|
|
7034
7442
|
const cancelRef = useRef3(false);
|
|
7035
7443
|
const focusRef = useRef3(null);
|
|
7036
|
-
const { weightKeywordList, italicKeywordList } =
|
|
7037
|
-
const
|
|
7444
|
+
const { weightKeywordList, italicKeywordList } = useMemo7(() => generateStyleKeywords(), []);
|
|
7445
|
+
const hasVFs = useMemo7(
|
|
7446
|
+
() => Object.values(plan.fonts).some((f) => f.variableFont && f.status !== "error"),
|
|
7447
|
+
[plan.fonts]
|
|
7448
|
+
);
|
|
7449
|
+
const baseStep = phaseToStep(plan.phase);
|
|
7450
|
+
const currentStep = instanceMappingPhase ? 4 : plan.phase === PLAN_PHASE.COMPLETE && !instanceMappingResult ? baseStep : baseStep;
|
|
7038
7451
|
const isExecuting = plan.phase === PLAN_PHASE.EXECUTING;
|
|
7039
|
-
|
|
7452
|
+
useEffect5(() => {
|
|
7040
7453
|
if (!open || !isExecuting) return;
|
|
7041
7454
|
const handler = (e) => {
|
|
7042
7455
|
e.preventDefault();
|
|
@@ -7045,12 +7458,12 @@ function UploadModal({
|
|
|
7045
7458
|
window.addEventListener("beforeunload", handler);
|
|
7046
7459
|
return () => window.removeEventListener("beforeunload", handler);
|
|
7047
7460
|
}, [open, isExecuting]);
|
|
7048
|
-
|
|
7461
|
+
useEffect5(() => {
|
|
7049
7462
|
if (focusRef.current) {
|
|
7050
7463
|
focusRef.current.focus();
|
|
7051
7464
|
}
|
|
7052
7465
|
}, [currentStep]);
|
|
7053
|
-
const handleClose =
|
|
7466
|
+
const handleClose = useCallback6(() => {
|
|
7054
7467
|
if (isExecuting) return;
|
|
7055
7468
|
const hasFonts = Object.keys(plan.fonts).length > 0;
|
|
7056
7469
|
if (hasFonts && plan.phase !== PLAN_PHASE.COMPLETE) {
|
|
@@ -7060,8 +7473,8 @@ function UploadModal({
|
|
|
7060
7473
|
setExecutionResult(null);
|
|
7061
7474
|
onClose();
|
|
7062
7475
|
}, [plan, isExecuting, onClose]);
|
|
7063
|
-
const handleStartProcessing =
|
|
7064
|
-
dispatch({ type: "SET_SETTINGS", settings });
|
|
7476
|
+
const handleStartProcessing = useCallback6(async (files, settings) => {
|
|
7477
|
+
dispatch({ type: "SET_SETTINGS", settings: { ...settings, typefaceTitle } });
|
|
7065
7478
|
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.PROCESSING, totalFiles: files.length });
|
|
7066
7479
|
cancelRef.current = false;
|
|
7067
7480
|
setProcessingCancelled(false);
|
|
@@ -7094,20 +7507,29 @@ function UploadModal({
|
|
|
7094
7507
|
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.REVIEWING });
|
|
7095
7508
|
}
|
|
7096
7509
|
}, [typefaceTitle, docId, client, stylesObject, weightKeywordList, italicKeywordList]);
|
|
7097
|
-
const handleCancelProcessing =
|
|
7510
|
+
const handleCancelProcessing = useCallback6(() => {
|
|
7098
7511
|
cancelRef.current = true;
|
|
7099
7512
|
setProcessingCancelled(true);
|
|
7100
7513
|
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.IDLE });
|
|
7101
7514
|
}, []);
|
|
7102
|
-
const handleStartExecution =
|
|
7515
|
+
const handleStartExecution = useCallback6(() => {
|
|
7103
7516
|
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.EXECUTING });
|
|
7104
7517
|
}, []);
|
|
7105
|
-
const handleExecutionComplete =
|
|
7518
|
+
const handleExecutionComplete = useCallback6((result) => {
|
|
7106
7519
|
setExecutionResult(result);
|
|
7107
|
-
|
|
7520
|
+
if (hasVFs && result.success !== false) {
|
|
7521
|
+
setInstanceMappingPhase(true);
|
|
7522
|
+
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.COMPLETE });
|
|
7523
|
+
} else {
|
|
7524
|
+
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.COMPLETE });
|
|
7525
|
+
}
|
|
7526
|
+
}, [hasVFs]);
|
|
7527
|
+
const handleInstanceMappingComplete = useCallback6((result) => {
|
|
7528
|
+
setInstanceMappingResult(result);
|
|
7529
|
+
setInstanceMappingPhase(false);
|
|
7108
7530
|
}, []);
|
|
7109
7531
|
if (!open) return null;
|
|
7110
|
-
const handleStepClick =
|
|
7532
|
+
const handleStepClick = useCallback6((stepKey) => {
|
|
7111
7533
|
if (isExecuting) return;
|
|
7112
7534
|
if (stepKey === currentStep) return;
|
|
7113
7535
|
if (stepKey === 1 && currentStep > 1) {
|
|
@@ -7117,16 +7539,16 @@ function UploadModal({
|
|
|
7117
7539
|
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.IDLE });
|
|
7118
7540
|
}
|
|
7119
7541
|
}, [currentStep, isExecuting, plan.fonts, dispatch]);
|
|
7120
|
-
return /* @__PURE__ */
|
|
7542
|
+
return /* @__PURE__ */ React10.createElement(
|
|
7121
7543
|
Dialog,
|
|
7122
7544
|
{
|
|
7123
7545
|
id: "upload-modal",
|
|
7124
|
-
header: /* @__PURE__ */
|
|
7546
|
+
header: /* @__PURE__ */ React10.createElement(Flex10, { direction: "column", gap: 3, style: { width: "100%" } }, /* @__PURE__ */ React10.createElement(Text10, { weight: "semibold", size: 2 }, "Upload Fonts"), /* @__PURE__ */ React10.createElement(Flex10, { gap: 1, style: { width: "100%" } }, STEPS.filter((step) => step.key !== 4 || hasVFs).map((step, i) => {
|
|
7125
7547
|
const isActive = currentStep === step.key;
|
|
7126
7548
|
const isCompleted = currentStep > step.key;
|
|
7127
7549
|
const isClickable = !isExecuting && step.key < currentStep;
|
|
7128
|
-
return /* @__PURE__ */
|
|
7129
|
-
|
|
7550
|
+
return /* @__PURE__ */ React10.createElement(
|
|
7551
|
+
Box9,
|
|
7130
7552
|
{
|
|
7131
7553
|
key: step.key,
|
|
7132
7554
|
as: isClickable ? "button" : "div",
|
|
@@ -7144,8 +7566,8 @@ function UploadModal({
|
|
|
7144
7566
|
opacity: !isActive && !isCompleted ? 0.6 : 1
|
|
7145
7567
|
}
|
|
7146
7568
|
},
|
|
7147
|
-
/* @__PURE__ */
|
|
7148
|
-
|
|
7569
|
+
/* @__PURE__ */ React10.createElement(
|
|
7570
|
+
Text10,
|
|
7149
7571
|
{
|
|
7150
7572
|
size: 1,
|
|
7151
7573
|
weight: isActive ? "bold" : "medium",
|
|
@@ -7162,13 +7584,13 @@ function UploadModal({
|
|
|
7162
7584
|
onClickOutside: () => {
|
|
7163
7585
|
}
|
|
7164
7586
|
},
|
|
7165
|
-
/* @__PURE__ */
|
|
7587
|
+
/* @__PURE__ */ React10.createElement(Box9, { padding: 4 }, currentStep === 1 && /* @__PURE__ */ React10.createElement(
|
|
7166
7588
|
UploadStep1Settings,
|
|
7167
7589
|
{
|
|
7168
7590
|
settings: plan.settings,
|
|
7169
7591
|
onStartProcessing: handleStartProcessing
|
|
7170
7592
|
}
|
|
7171
|
-
), currentStep === 2 && /* @__PURE__ */
|
|
7593
|
+
), currentStep === 2 && /* @__PURE__ */ React10.createElement(
|
|
7172
7594
|
UploadStep2Review,
|
|
7173
7595
|
{
|
|
7174
7596
|
plan,
|
|
@@ -7177,7 +7599,7 @@ function UploadModal({
|
|
|
7177
7599
|
onStartExecution: handleStartExecution,
|
|
7178
7600
|
processingCancelled
|
|
7179
7601
|
}
|
|
7180
|
-
), currentStep === 3 && plan.phase !== PLAN_PHASE.COMPLETE && /* @__PURE__ */
|
|
7602
|
+
), currentStep === 3 && plan.phase !== PLAN_PHASE.COMPLETE && /* @__PURE__ */ React10.createElement(
|
|
7181
7603
|
UploadStep3Execute,
|
|
7182
7604
|
{
|
|
7183
7605
|
key: retryTempIds ? "retry" : "initial",
|
|
@@ -7192,15 +7614,27 @@ function UploadModal({
|
|
|
7192
7614
|
handleExecutionComplete(result);
|
|
7193
7615
|
}
|
|
7194
7616
|
}
|
|
7195
|
-
), plan.phase === PLAN_PHASE.COMPLETE && /* @__PURE__ */
|
|
7617
|
+
), plan.phase === PLAN_PHASE.COMPLETE && instanceMappingPhase && /* @__PURE__ */ React10.createElement(
|
|
7618
|
+
UploadStep3bInstances,
|
|
7619
|
+
{
|
|
7620
|
+
plan,
|
|
7621
|
+
executionResult,
|
|
7622
|
+
client,
|
|
7623
|
+
typefaceTitle,
|
|
7624
|
+
onComplete: handleInstanceMappingComplete
|
|
7625
|
+
}
|
|
7626
|
+
), plan.phase === PLAN_PHASE.COMPLETE && !instanceMappingPhase && /* @__PURE__ */ React10.createElement(
|
|
7196
7627
|
UploadSummary,
|
|
7197
7628
|
{
|
|
7198
7629
|
plan,
|
|
7199
7630
|
result: executionResult,
|
|
7631
|
+
instanceMappingResult,
|
|
7200
7632
|
onClose: handleClose,
|
|
7201
7633
|
onRetry: (failedTempIds) => {
|
|
7202
7634
|
setRetryTempIds(failedTempIds || null);
|
|
7203
7635
|
setExecutionResult(null);
|
|
7636
|
+
setInstanceMappingPhase(false);
|
|
7637
|
+
setInstanceMappingResult(null);
|
|
7204
7638
|
dispatch({ type: "SET_PHASE", phase: PLAN_PHASE.EXECUTING });
|
|
7205
7639
|
},
|
|
7206
7640
|
client,
|
|
@@ -7271,6 +7705,7 @@ export {
|
|
|
7271
7705
|
createInitialExecutionState,
|
|
7272
7706
|
executionReducer,
|
|
7273
7707
|
UploadStep3Execute,
|
|
7708
|
+
UploadStep3bInstances,
|
|
7274
7709
|
UploadSummary,
|
|
7275
7710
|
UploadModal
|
|
7276
7711
|
};
|