brand-intent 0.4.0 → 0.4.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/package.json +1 -1
- package/parser/brandParser.ts +13 -11
- package/parser/compositionParser.ts +10 -1
package/package.json
CHANGED
package/parser/brandParser.ts
CHANGED
|
@@ -45,8 +45,8 @@ export interface ParsedBrand {
|
|
|
45
45
|
dividers?: Record<string, ParsedDividerDef>;
|
|
46
46
|
/** Named typography styles: name → style definition */
|
|
47
47
|
typographies?: Record<string, ParsedTypographyDef>;
|
|
48
|
-
/** Brand-declared assets: curated logos, photos, videos with labels and metadata */
|
|
49
|
-
assets?: { logos?: ParsedAssetDef[]; photos?: ParsedAssetDef[]; videos?: ParsedAssetDef[] };
|
|
48
|
+
/** Brand-declared assets: curated logos, photos, videos, illustrations with labels and metadata */
|
|
49
|
+
assets?: { logos?: ParsedAssetDef[]; photos?: ParsedAssetDef[]; videos?: ParsedAssetDef[]; illustrations?: ParsedAssetDef[] };
|
|
50
50
|
/** Label badge style — padding (top/right/bottom/left in cqh) and corner radius (cqh) */
|
|
51
51
|
label?: ParsedBadgeStyle;
|
|
52
52
|
/** CTA pill style — padding (top/right/bottom/left in cqh) and corner radius (cqh, or 999 for full pill) */
|
|
@@ -146,7 +146,7 @@ export function parseBrandFile(content: string, fileName: string): ParsedBrand {
|
|
|
146
146
|
tokensSource: 'figma',
|
|
147
147
|
};
|
|
148
148
|
|
|
149
|
-
type ActiveBlock = 'none' | 'brand-colors' | 'theme' | 'spacing' | 'divider' | 'typography' | 'font' | 'logo' | 'photo' | 'video' | 'label' | 'cta';
|
|
149
|
+
type ActiveBlock = 'none' | 'brand-colors' | 'theme' | 'spacing' | 'divider' | 'typography' | 'font' | 'logo' | 'photo' | 'video' | 'illustration' | 'label' | 'cta';
|
|
150
150
|
let activeBlock: ActiveBlock = 'none';
|
|
151
151
|
let currentThemeName = '';
|
|
152
152
|
let currentDividerName = '';
|
|
@@ -164,6 +164,7 @@ export function parseBrandFile(content: string, fileName: string): ParsedBrand {
|
|
|
164
164
|
const logosRaw: Array<{ id: string; props: Record<string, string> }> = [];
|
|
165
165
|
const photosRaw: Array<{ id: string; props: Record<string, string> }> = [];
|
|
166
166
|
const videosRaw: Array<{ id: string; props: Record<string, string> }> = [];
|
|
167
|
+
const illustrationsRaw: Array<{ id: string; props: Record<string, string> }> = [];
|
|
167
168
|
let currentAssetId = '';
|
|
168
169
|
const labelRaw: Record<string, string> = {};
|
|
169
170
|
const ctaRaw: Record<string, string> = {};
|
|
@@ -264,18 +265,18 @@ export function parseBrandFile(content: string, fileName: string): ParsedBrand {
|
|
|
264
265
|
}
|
|
265
266
|
continue;
|
|
266
267
|
}
|
|
267
|
-
if ((activeBlock === 'logo' || activeBlock === 'photo' || activeBlock === 'video') && currentAssetId) {
|
|
268
|
+
if ((activeBlock === 'logo' || activeBlock === 'photo' || activeBlock === 'video' || activeBlock === 'illustration') && currentAssetId) {
|
|
268
269
|
const colonIdx = raw.indexOf(':');
|
|
269
270
|
if (colonIdx !== -1) {
|
|
270
271
|
const key = raw.slice(0, colonIdx).trim();
|
|
271
272
|
const value = raw.slice(colonIdx + 1).trim();
|
|
272
|
-
const arr = activeBlock === 'logo' ? logosRaw : activeBlock === 'photo' ? photosRaw : videosRaw;
|
|
273
|
+
const arr = activeBlock === 'logo' ? logosRaw : activeBlock === 'photo' ? photosRaw : activeBlock === 'video' ? videosRaw : illustrationsRaw;
|
|
273
274
|
const last = arr[arr.length - 1];
|
|
274
275
|
if (last && last.id === currentAssetId) last.props[key] = value;
|
|
275
276
|
} else {
|
|
276
277
|
const trimmed = raw.trim();
|
|
277
278
|
if (trimmed === 'animated' || trimmed === 'loop') {
|
|
278
|
-
const arr = activeBlock === 'logo' ? logosRaw : activeBlock === 'photo' ? photosRaw : videosRaw;
|
|
279
|
+
const arr = activeBlock === 'logo' ? logosRaw : activeBlock === 'photo' ? photosRaw : activeBlock === 'video' ? videosRaw : illustrationsRaw;
|
|
279
280
|
const last = arr[arr.length - 1];
|
|
280
281
|
if (last && last.id === currentAssetId) last.props[trimmed] = 'true';
|
|
281
282
|
}
|
|
@@ -341,13 +342,13 @@ export function parseBrandFile(content: string, fileName: string): ParsedBrand {
|
|
|
341
342
|
continue;
|
|
342
343
|
}
|
|
343
344
|
|
|
344
|
-
// logo/photo/video <id> — starts an asset block
|
|
345
|
-
const assetMatch = raw.match(/^(logo|photo|video)\s+(\S+)/);
|
|
345
|
+
// logo/photo/video/illustration <id> — starts an asset block
|
|
346
|
+
const assetMatch = raw.match(/^(logo|photo|video|illustration)\s+(\S+)/);
|
|
346
347
|
if (assetMatch) {
|
|
347
348
|
const [, type, id] = assetMatch;
|
|
348
349
|
currentAssetId = id;
|
|
349
|
-
activeBlock = type as 'logo' | 'photo' | 'video';
|
|
350
|
-
const arr = type === 'logo' ? logosRaw : type === 'photo' ? photosRaw : videosRaw;
|
|
350
|
+
activeBlock = type as 'logo' | 'photo' | 'video' | 'illustration';
|
|
351
|
+
const arr = type === 'logo' ? logosRaw : type === 'photo' ? photosRaw : type === 'video' ? videosRaw : illustrationsRaw;
|
|
351
352
|
arr.push({ id, props: {} });
|
|
352
353
|
continue;
|
|
353
354
|
}
|
|
@@ -510,11 +511,12 @@ export function parseBrandFile(content: string, fileName: string): ParsedBrand {
|
|
|
510
511
|
if (raw.props['loop'] === 'true') def.loop = true;
|
|
511
512
|
return def;
|
|
512
513
|
};
|
|
513
|
-
if (logosRaw.length > 0 || photosRaw.length > 0 || videosRaw.length > 0) {
|
|
514
|
+
if (logosRaw.length > 0 || photosRaw.length > 0 || videosRaw.length > 0 || illustrationsRaw.length > 0) {
|
|
514
515
|
result.assets = {};
|
|
515
516
|
if (logosRaw.length > 0) result.assets.logos = logosRaw.map(toAssetDef);
|
|
516
517
|
if (photosRaw.length > 0) result.assets.photos = photosRaw.map(toAssetDef);
|
|
517
518
|
if (videosRaw.length > 0) result.assets.videos = videosRaw.map(toAssetDef);
|
|
519
|
+
if (illustrationsRaw.length > 0) result.assets.illustrations = illustrationsRaw.map(toAssetDef);
|
|
518
520
|
}
|
|
519
521
|
|
|
520
522
|
// Finalise label / cta badge styles
|
|
@@ -34,6 +34,8 @@ export interface ParsedIllustration {
|
|
|
34
34
|
fit: 'width' | 'height';
|
|
35
35
|
/** Scale as fraction 0–1 (e.g. 0.9 = 90% of canvas dimension). */
|
|
36
36
|
scale: number;
|
|
37
|
+
/** Offset from anchor position in % of canvas [x, y]. Positive = right/down. */
|
|
38
|
+
offset?: [number, number];
|
|
37
39
|
}
|
|
38
40
|
|
|
39
41
|
const ILLUSTRATION_ANCHORS = new Set<string>([
|
|
@@ -296,7 +298,14 @@ export function parseCompositionFile(content: string, fileName: string): ParsedC
|
|
|
296
298
|
if (!scaleMatch) throw new Error(`${fileName}:${lineNum}: invalid illustration scale "${scaleStr}" (expected e.g. "90%")`);
|
|
297
299
|
const scale = parseFloat(scaleMatch[1]) / 100;
|
|
298
300
|
if (scale <= 0 || scale > 2) throw new Error(`${fileName}:${lineNum}: illustration scale out of range (expected 1%–200%)`);
|
|
299
|
-
|
|
301
|
+
const illu: ParsedIllustration = { anchor: anchor as IllustrationAnchor, fit: fitStr === 'fit-width' ? 'width' : 'height', scale };
|
|
302
|
+
// Optional: "offset X Y" in % of canvas (positive = right/down)
|
|
303
|
+
if (parts.length >= 5 && parts[3] === 'offset') {
|
|
304
|
+
const ox = parseFloat(parts[4]);
|
|
305
|
+
const oy = parts.length >= 6 ? parseFloat(parts[5]) : 0;
|
|
306
|
+
if (!isNaN(ox) && !isNaN(oy)) illu.offset = [ox, oy];
|
|
307
|
+
}
|
|
308
|
+
illustration = illu;
|
|
300
309
|
continue;
|
|
301
310
|
}
|
|
302
311
|
|