@vectoriox/iox-ui 5.77.0 → 5.78.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/design-core/index.d.ts +34 -4
- package/fesm2022/vectoriox-iox-ui-design-core.mjs +34 -4
- package/fesm2022/vectoriox-iox-ui-design-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs +647 -12
- package/fesm2022/vectoriox-iox-ui-generation-core.mjs.map +1 -1
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs +38 -3
- package/fesm2022/vectoriox-iox-ui-harness-core.mjs.map +1 -1
- package/generation-core/index.d.ts +411 -7
- package/harness-core/index.d.ts +37 -2
- package/package.json +1 -1
- package/src/design-core/flavor-spec.generated.ts +34 -4
- package/src/generation-core/compose-site.ts +12 -2
- package/src/generation-core/patterns.ts +37 -4
- package/src/generation-core/serialized-node.ts +3 -0
- package/src/generation-core/showcase.ts +18 -7
- package/src/generation-core/site-spec.generated.ts +577 -0
- package/src/generation-core/validate-site-plan.ts +24 -2
- package/src/harness-core/business-types.ts +3 -0
- package/src/harness-core/harness-spec.generated.ts +32 -2
- package/src/harness-core/motion.ts +8 -1
package/harness-core/index.d.ts
CHANGED
|
@@ -155,6 +155,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
155
155
|
readonly animate: "subtle";
|
|
156
156
|
readonly between: "cinematic";
|
|
157
157
|
};
|
|
158
|
+
readonly ceiling: "expressive";
|
|
158
159
|
readonly imagery: "Your own photos only, large and uncropped; never stock.";
|
|
159
160
|
readonly pages: readonly ["home", "work (collection)", "project (detail)", "about", "contact"];
|
|
160
161
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -217,6 +218,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
217
218
|
readonly animate: "subtle";
|
|
218
219
|
readonly between: "cinematic";
|
|
219
220
|
};
|
|
221
|
+
readonly ceiling: "expressive";
|
|
220
222
|
readonly imagery: "Wide, bright room shots; details of materials.";
|
|
221
223
|
readonly pages: readonly ["home", "projects (collection)", "project (detail)", "services", "about", "contact"];
|
|
222
224
|
readonly needs: readonly ["collection", "detail", "services", "about", "contact"];
|
|
@@ -280,6 +282,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
280
282
|
readonly animate: "subtle";
|
|
281
283
|
readonly between: "fade";
|
|
282
284
|
};
|
|
285
|
+
readonly ceiling: "expressive";
|
|
283
286
|
readonly imagery: "Large project photos and drawings.";
|
|
284
287
|
readonly pages: readonly ["home", "projects (collection)", "project (detail)", "about", "contact"];
|
|
285
288
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -341,9 +344,10 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
341
344
|
readonly motion: "standard";
|
|
342
345
|
readonly moves: {
|
|
343
346
|
readonly scroll: "smooth";
|
|
344
|
-
readonly animate: "
|
|
347
|
+
readonly animate: "expressive";
|
|
345
348
|
readonly between: "slide";
|
|
346
349
|
};
|
|
350
|
+
readonly ceiling: "expressive";
|
|
347
351
|
readonly imagery: "Case-study images of your own work.";
|
|
348
352
|
readonly pages: readonly ["home", "work (collection)", "case study (detail)", "services", "about", "contact"];
|
|
349
353
|
readonly needs: readonly ["collection", "detail", "services", "about", "contact"];
|
|
@@ -398,6 +402,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
398
402
|
readonly animate: "standard";
|
|
399
403
|
readonly between: "fade";
|
|
400
404
|
};
|
|
405
|
+
readonly ceiling: "expressive";
|
|
401
406
|
readonly imagery: "Your pieces, photographed flat and true to colour.";
|
|
402
407
|
readonly pages: readonly ["home", "works (collection)", "work (detail)", "about", "contact"];
|
|
403
408
|
readonly needs: readonly ["collection", "about", "contact"];
|
|
@@ -451,9 +456,10 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
451
456
|
readonly motion: "calm";
|
|
452
457
|
readonly moves: {
|
|
453
458
|
readonly scroll: "normal";
|
|
454
|
-
readonly animate: "
|
|
459
|
+
readonly animate: "expressive";
|
|
455
460
|
readonly between: "slide";
|
|
456
461
|
};
|
|
462
|
+
readonly ceiling: "expressive";
|
|
457
463
|
readonly imagery: "Your pieces and hands at work; natural light.";
|
|
458
464
|
readonly pages: readonly ["home", "pieces (collection)", "piece (detail)", "workshops", "about", "contact"];
|
|
459
465
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -509,6 +515,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
509
515
|
readonly animate: "subtle";
|
|
510
516
|
readonly between: "cinematic";
|
|
511
517
|
};
|
|
518
|
+
readonly ceiling: "expressive";
|
|
512
519
|
readonly imagery: "Close-ups on a plain ground.";
|
|
513
520
|
readonly pages: readonly ["home", "collection", "piece (detail)", "about", "contact"];
|
|
514
521
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -565,6 +572,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
565
572
|
readonly animate: "standard";
|
|
566
573
|
readonly between: "slide";
|
|
567
574
|
};
|
|
575
|
+
readonly ceiling: "expressive";
|
|
568
576
|
readonly imagery: "Healed work, clean photos.";
|
|
569
577
|
readonly pages: readonly ["home", "work (collection)", "artists", "faq", "contact"];
|
|
570
578
|
readonly needs: readonly ["collection", "faq", "contact"];
|
|
@@ -620,6 +628,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
620
628
|
readonly animate: "subtle";
|
|
621
629
|
readonly between: "fade";
|
|
622
630
|
};
|
|
631
|
+
readonly ceiling: "standard";
|
|
623
632
|
readonly imagery: "Rooms, textures, hands; no faces needed.";
|
|
624
633
|
readonly pages: readonly ["home", "treatments (services)", "prices", "about", "contact"];
|
|
625
634
|
readonly needs: readonly ["services", "prices", "about", "contact"];
|
|
@@ -685,6 +694,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
685
694
|
readonly animate: "standard";
|
|
686
695
|
readonly between: "fade";
|
|
687
696
|
};
|
|
697
|
+
readonly ceiling: "lively";
|
|
688
698
|
readonly imagery: "Your own before-and-after photos.";
|
|
689
699
|
readonly pages: readonly ["home", "services", "prices", "gallery", "contact"];
|
|
690
700
|
readonly needs: readonly ["services", "prices", "gallery", "contact"];
|
|
@@ -744,6 +754,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
744
754
|
readonly animate: "subtle";
|
|
745
755
|
readonly between: "fade";
|
|
746
756
|
};
|
|
757
|
+
readonly ceiling: "lively";
|
|
747
758
|
readonly imagery: "The room, real classes, daylight.";
|
|
748
759
|
readonly pages: readonly ["home", "classes", "schedule", "teachers", "prices", "contact"];
|
|
749
760
|
readonly needs: readonly ["prices", "contact"];
|
|
@@ -804,6 +815,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
804
815
|
readonly animate: "lively";
|
|
805
816
|
readonly between: "slide";
|
|
806
817
|
};
|
|
818
|
+
readonly ceiling: "lively";
|
|
807
819
|
readonly imagery: "Real people training; movement.";
|
|
808
820
|
readonly pages: readonly ["home", "classes", "prices", "coaches", "contact"];
|
|
809
821
|
readonly needs: readonly ["prices", "contact"];
|
|
@@ -860,6 +872,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
860
872
|
readonly animate: "subtle";
|
|
861
873
|
readonly between: "none";
|
|
862
874
|
};
|
|
875
|
+
readonly ceiling: "subtle";
|
|
863
876
|
readonly imagery: "A calm room, daylight; your portrait.";
|
|
864
877
|
readonly pages: readonly ["home", "how I work", "about", "faq", "contact"];
|
|
865
878
|
readonly needs: readonly ["collection", "about", "faq", "contact"];
|
|
@@ -920,6 +933,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
920
933
|
readonly animate: "subtle";
|
|
921
934
|
readonly between: "fade";
|
|
922
935
|
};
|
|
936
|
+
readonly ceiling: "subtle";
|
|
923
937
|
readonly imagery: "Your team and rooms; no stock doctors.";
|
|
924
938
|
readonly pages: readonly ["home", "treatments (services)", "team", "faq", "contact"];
|
|
925
939
|
readonly needs: readonly ["services", "team", "faq", "contact"];
|
|
@@ -981,6 +995,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
981
995
|
readonly animate: "subtle";
|
|
982
996
|
readonly between: "fade";
|
|
983
997
|
};
|
|
998
|
+
readonly ceiling: "subtle";
|
|
984
999
|
readonly imagery: "Your clinic and team.";
|
|
985
1000
|
readonly pages: readonly ["home", "treatments", "team", "faq", "contact"];
|
|
986
1001
|
readonly needs: readonly ["services", "team", "faq", "contact"];
|
|
@@ -1040,6 +1055,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1040
1055
|
readonly animate: "standard";
|
|
1041
1056
|
readonly between: "fade";
|
|
1042
1057
|
};
|
|
1058
|
+
readonly ceiling: "standard";
|
|
1043
1059
|
readonly imagery: "Real animals you treat (with permission).";
|
|
1044
1060
|
readonly pages: readonly ["home", "services", "team", "faq", "contact"];
|
|
1045
1061
|
readonly needs: readonly ["services", "team", "faq", "contact"];
|
|
@@ -1095,6 +1111,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1095
1111
|
readonly animate: "standard";
|
|
1096
1112
|
readonly between: "fade";
|
|
1097
1113
|
};
|
|
1114
|
+
readonly ceiling: "expressive";
|
|
1098
1115
|
readonly imagery: "Your own food and room photos.";
|
|
1099
1116
|
readonly pages: readonly ["home", "menu", "about", "contact"];
|
|
1100
1117
|
readonly needs: readonly ["menu", "about", "contact"];
|
|
@@ -1157,6 +1174,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1157
1174
|
readonly animate: "standard";
|
|
1158
1175
|
readonly between: "slide";
|
|
1159
1176
|
};
|
|
1177
|
+
readonly ceiling: "lively";
|
|
1160
1178
|
readonly imagery: "Your bakes and drinks, close up.";
|
|
1161
1179
|
readonly pages: readonly ["home", "menu", "about", "contact"];
|
|
1162
1180
|
readonly needs: readonly ["menu", "about", "contact"];
|
|
@@ -1216,6 +1234,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1216
1234
|
readonly animate: "subtle";
|
|
1217
1235
|
readonly between: "cinematic";
|
|
1218
1236
|
};
|
|
1237
|
+
readonly ceiling: "expressive";
|
|
1219
1238
|
readonly imagery: "The cellar, the bar, the bottle.";
|
|
1220
1239
|
readonly pages: readonly ["home", "menu or wines", "our story", "visit", "contact"];
|
|
1221
1240
|
readonly needs: readonly ["menu", "visit", "contact"];
|
|
@@ -1275,6 +1294,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1275
1294
|
readonly animate: "standard";
|
|
1276
1295
|
readonly between: "slide";
|
|
1277
1296
|
};
|
|
1297
|
+
readonly ceiling: "expressive";
|
|
1278
1298
|
readonly imagery: "Product photos on plain grounds; real people wearing them.";
|
|
1279
1299
|
readonly pages: readonly ["home", "collection", "product (detail)", "about", "contact"];
|
|
1280
1300
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -1329,6 +1349,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1329
1349
|
readonly animate: "standard";
|
|
1330
1350
|
readonly between: "fade";
|
|
1331
1351
|
};
|
|
1352
|
+
readonly ceiling: "lively";
|
|
1332
1353
|
readonly imagery: "Your own arrangements in daylight.";
|
|
1333
1354
|
readonly pages: readonly ["home", "flowers (collection)", "weddings and events", "about", "contact"];
|
|
1334
1355
|
readonly needs: readonly ["collection", "about", "contact"];
|
|
@@ -1384,6 +1405,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1384
1405
|
readonly animate: "subtle";
|
|
1385
1406
|
readonly between: "fade";
|
|
1386
1407
|
};
|
|
1408
|
+
readonly ceiling: "expressive";
|
|
1387
1409
|
readonly imagery: "Pieces in real rooms and on plain grounds.";
|
|
1388
1410
|
readonly pages: readonly ["home", "collection", "product (detail)", "about", "contact"];
|
|
1389
1411
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -1439,6 +1461,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1439
1461
|
readonly animate: "subtle";
|
|
1440
1462
|
readonly between: "fade";
|
|
1441
1463
|
};
|
|
1464
|
+
readonly ceiling: "standard";
|
|
1442
1465
|
readonly imagery: "Your portrait; diagrams over stock.";
|
|
1443
1466
|
readonly pages: readonly ["home", "services", "case studies", "about", "contact"];
|
|
1444
1467
|
readonly needs: readonly ["services", "about", "contact"];
|
|
@@ -1496,6 +1519,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1496
1519
|
readonly animate: "standard";
|
|
1497
1520
|
readonly between: "fade";
|
|
1498
1521
|
};
|
|
1522
|
+
readonly ceiling: "standard";
|
|
1499
1523
|
readonly imagery: "Your portrait, working with people.";
|
|
1500
1524
|
readonly pages: readonly ["home", "how it works", "programmes", "about", "contact"];
|
|
1501
1525
|
readonly needs: readonly ["collection", "about", "contact"];
|
|
@@ -1547,6 +1571,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1547
1571
|
readonly animate: "still";
|
|
1548
1572
|
readonly between: "none";
|
|
1549
1573
|
};
|
|
1574
|
+
readonly ceiling: "subtle";
|
|
1550
1575
|
readonly imagery: "Your team; your office.";
|
|
1551
1576
|
readonly pages: readonly ["home", "practice areas (services)", "team", "about", "contact"];
|
|
1552
1577
|
readonly needs: readonly ["services", "team", "about", "contact"];
|
|
@@ -1609,6 +1634,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1609
1634
|
readonly animate: "standard";
|
|
1610
1635
|
readonly between: "slide";
|
|
1611
1636
|
};
|
|
1637
|
+
readonly ceiling: "lively";
|
|
1612
1638
|
readonly imagery: "Your own property photos; never stock.";
|
|
1613
1639
|
readonly pages: readonly ["home", "properties (collection)", "property (detail)", "about", "contact"];
|
|
1614
1640
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -1667,6 +1693,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1667
1693
|
readonly animate: "standard";
|
|
1668
1694
|
readonly between: "fade";
|
|
1669
1695
|
};
|
|
1696
|
+
readonly ceiling: "standard";
|
|
1670
1697
|
readonly imagery: "Real people you help (with permission).";
|
|
1671
1698
|
readonly pages: readonly ["home", "what we do", "stories", "get involved", "contact"];
|
|
1672
1699
|
readonly needs: readonly ["contact"];
|
|
@@ -1718,6 +1745,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1718
1745
|
readonly animate: "standard";
|
|
1719
1746
|
readonly between: "cinematic";
|
|
1720
1747
|
};
|
|
1748
|
+
readonly ceiling: "expressive";
|
|
1721
1749
|
readonly imagery: "Real events at your venue.";
|
|
1722
1750
|
readonly pages: readonly ["home", "spaces", "gallery", "faq", "contact"];
|
|
1723
1751
|
readonly needs: readonly ["gallery", "faq", "contact"];
|
|
@@ -1776,6 +1804,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1776
1804
|
readonly animate: "subtle";
|
|
1777
1805
|
readonly between: "cinematic";
|
|
1778
1806
|
};
|
|
1807
|
+
readonly ceiling: "expressive";
|
|
1779
1808
|
readonly imagery: "Rooms, views, breakfast; your own photos.";
|
|
1780
1809
|
readonly pages: readonly ["home", "rooms (collection)", "room (detail)", "about", "contact"];
|
|
1781
1810
|
readonly needs: readonly ["collection", "detail", "about", "contact"];
|
|
@@ -1834,6 +1863,7 @@ declare const SPEC_BUSINESS_TYPES: readonly [{
|
|
|
1834
1863
|
readonly animate: "lively";
|
|
1835
1864
|
readonly between: "slide";
|
|
1836
1865
|
};
|
|
1866
|
+
readonly ceiling: "lively";
|
|
1837
1867
|
readonly imagery: "Real classes (with permission).";
|
|
1838
1868
|
readonly pages: readonly ["home", "classes", "prices", "about", "contact"];
|
|
1839
1869
|
readonly needs: readonly ["prices", "about", "contact"];
|
|
@@ -2238,6 +2268,9 @@ interface BusinessType {
|
|
|
2238
2268
|
readonly motion: MotionId;
|
|
2239
2269
|
/** How its site usually scrolls, how animated it is and what plays between pages (rev 3.1). */
|
|
2240
2270
|
readonly moves: Readonly<DesignMotion>;
|
|
2271
|
+
/** SC6: the most How animated a GENERATED site of this type may start at (`motionFor`). A Scene needs Expressive,
|
|
2272
|
+
* so a type capped below it never gets one. Binds generated output only — the owner may choose any level. */
|
|
2273
|
+
readonly ceiling: DesignMotion['animate'];
|
|
2241
2274
|
readonly imagery: string;
|
|
2242
2275
|
readonly pages: ReadonlyArray<string>;
|
|
2243
2276
|
/** The needs its page set implies, in page order (derived from `pages` at contract build). */
|
|
@@ -2436,6 +2469,8 @@ interface MotionBasis {
|
|
|
2436
2469
|
references: boolean;
|
|
2437
2470
|
/** The owner asked for little movement: all three were capped. */
|
|
2438
2471
|
littleMovement: boolean;
|
|
2472
|
+
/** SC6: How animated was held at the type's ceiling (a law firm stays calm whatever the style or references). */
|
|
2473
|
+
ceiling: boolean;
|
|
2439
2474
|
}
|
|
2440
2475
|
interface MotionStart extends DesignMotion {
|
|
2441
2476
|
/** Why, in English — one line per step the start took. */
|
package/package.json
CHANGED
|
@@ -1533,6 +1533,36 @@ export const SPEC_AXES = {
|
|
|
1533
1533
|
"duration": 600
|
|
1534
1534
|
}
|
|
1535
1535
|
}
|
|
1536
|
+
},
|
|
1537
|
+
"expressive": {
|
|
1538
|
+
"label": "Expressive",
|
|
1539
|
+
"he": "נועזת",
|
|
1540
|
+
"hint": "Headings rise line by line and pictures open as they arrive; one section may hold the page and move as you scroll.",
|
|
1541
|
+
"parts": {
|
|
1542
|
+
"heroText": {
|
|
1543
|
+
"type": "fadeIn",
|
|
1544
|
+
"duration": 500
|
|
1545
|
+
},
|
|
1546
|
+
"heading": {
|
|
1547
|
+
"type": "revealText",
|
|
1548
|
+
"duration": 700
|
|
1549
|
+
},
|
|
1550
|
+
"items": {
|
|
1551
|
+
"type": "moveUp",
|
|
1552
|
+
"distance": 32,
|
|
1553
|
+
"duration": 700,
|
|
1554
|
+
"stagger": 110,
|
|
1555
|
+
"cap": 8
|
|
1556
|
+
},
|
|
1557
|
+
"media": {
|
|
1558
|
+
"type": "clipReveal",
|
|
1559
|
+
"duration": 800
|
|
1560
|
+
},
|
|
1561
|
+
"rowMedia": {
|
|
1562
|
+
"type": "clipReveal",
|
|
1563
|
+
"duration": 800
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1536
1566
|
}
|
|
1537
1567
|
},
|
|
1538
1568
|
"animationFamilies": {
|
|
@@ -1937,7 +1967,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
1937
1967
|
"pillButtons": false,
|
|
1938
1968
|
"moves": {
|
|
1939
1969
|
"scroll": "smooth",
|
|
1940
|
-
"animate": "
|
|
1970
|
+
"animate": "expressive",
|
|
1941
1971
|
"between": "slide"
|
|
1942
1972
|
},
|
|
1943
1973
|
"modes": [
|
|
@@ -2034,7 +2064,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2034
2064
|
"pillButtons": false,
|
|
2035
2065
|
"moves": {
|
|
2036
2066
|
"scroll": "normal",
|
|
2037
|
-
"animate": "
|
|
2067
|
+
"animate": "expressive",
|
|
2038
2068
|
"between": "fade"
|
|
2039
2069
|
},
|
|
2040
2070
|
"modes": [
|
|
@@ -2320,7 +2350,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2320
2350
|
"pillButtons": false,
|
|
2321
2351
|
"moves": {
|
|
2322
2352
|
"scroll": "normal",
|
|
2323
|
-
"animate": "
|
|
2353
|
+
"animate": "expressive",
|
|
2324
2354
|
"between": "slide"
|
|
2325
2355
|
},
|
|
2326
2356
|
"modes": [
|
|
@@ -2385,7 +2415,7 @@ export const SPEC_STYLE_PRESETS = [
|
|
|
2385
2415
|
"pillButtons": false,
|
|
2386
2416
|
"moves": {
|
|
2387
2417
|
"scroll": "normal",
|
|
2388
|
-
"animate": "
|
|
2418
|
+
"animate": "expressive",
|
|
2389
2419
|
"between": "slide"
|
|
2390
2420
|
},
|
|
2391
2421
|
"modes": [
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { EntranceMark, EntrancePart, planEntrances } from './entrances';
|
|
13
13
|
import { NODE_BASELINES } from './node-baselines.generated';
|
|
14
14
|
import {
|
|
15
|
-
BindScope, CardBindTarget, parsePatternPath, PatternDirective, PatternNode, PatternOpens, PatternPlaceholder, PatternRecipe, SitePattern, patternById,
|
|
15
|
+
BindScope, CardBindTarget, parsePatternPath, PatternDirective, PatternNode, PatternOpens, PatternPlaceholder, PatternRecipe, PatternTrack, SitePattern, patternById,
|
|
16
16
|
} from './patterns';
|
|
17
17
|
import { recipeListBinds } from './recipe-fields';
|
|
18
18
|
import { assertStyleSlots, ComposeError, createSerializedNode, SerializedBinding, SerializedNode, setStyleProps, walkSerialized } from './serialized-node';
|
|
@@ -575,6 +575,8 @@ function composeNode(given: PatternNode, id: string, repeater: RepeaterScope | n
|
|
|
575
575
|
// Props first: a Heading with no `es` wears its LEVEL's default style.
|
|
576
576
|
const node = create(id, type, props, pn.es ?? null);
|
|
577
577
|
if (pn.role) node.role = pn.role;
|
|
578
|
+
if (pn.tracks?.length) node.sceneTracks = pn.tracks.map(cloneTrack);
|
|
579
|
+
if (pn.phoneTracks?.length) node.scenePhoneTracks = pn.phoneTracks.map(cloneTrack);
|
|
578
580
|
markEntrance(pn, id, repeater, ctx);
|
|
579
581
|
|
|
580
582
|
// Words.
|
|
@@ -990,6 +992,13 @@ function wireOpeners(root: SerializedNode, openers: ReadonlyArray<string>): void
|
|
|
990
992
|
}
|
|
991
993
|
|
|
992
994
|
/** How a composed section moves in (M1-6b): the look's How animated (or the section's own) on the page's direction. */
|
|
995
|
+
/** SC6: a track's own copy, so a composed page never shares an array with the contract. */
|
|
996
|
+
const cloneTrack = (track: PatternTrack): Record<string, unknown> => ({
|
|
997
|
+
prop: track.prop,
|
|
998
|
+
keys: track.keys.map(([at, value]) => [at, value]),
|
|
999
|
+
...(track.from ? { from: track.from } : {}),
|
|
1000
|
+
});
|
|
1001
|
+
|
|
993
1002
|
interface SectionMotion {
|
|
994
1003
|
level: AnimateId | string | null;
|
|
995
1004
|
rtl: boolean;
|
|
@@ -1002,7 +1011,8 @@ function composePattern(pattern: SitePattern, id: string, ctx: Ctx, motion: Sect
|
|
|
1002
1011
|
if (!node) throw new ComposeError(`${id}: a pattern's root cannot be optional or a link`);
|
|
1003
1012
|
wireOpeners(node, own.openers ?? []);
|
|
1004
1013
|
wireShownWhen(node, own.shownWhen ?? []);
|
|
1005
|
-
|
|
1014
|
+
// A Scene moves by the scroll alone: the look's entrances would fade its pinned stage in on arrival (SC6).
|
|
1015
|
+
if (motion && !pattern.global && !pattern.scene) stampEntrances(node, pattern.family, own.entrances ?? [], motion);
|
|
1006
1016
|
node.label = pattern.label;
|
|
1007
1017
|
return node;
|
|
1008
1018
|
}
|
|
@@ -90,6 +90,19 @@ export interface PatternNode {
|
|
|
90
90
|
readonly side?: `${EntranceSide}`;
|
|
91
91
|
/** L0-3: a link to the page that shows this scope's item (the plan's template page of its type). */
|
|
92
92
|
readonly detail?: `${BindScope.Item}` | `${BindScope.Next}`;
|
|
93
|
+
/** SC6: a Scene layer's scene-core tracks, written to the node's `sceneTracks` (and `scenePhoneTracks`). */
|
|
94
|
+
readonly tracks?: ReadonlyArray<PatternTrack>;
|
|
95
|
+
readonly phoneTracks?: ReadonlyArray<PatternTrack>;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* SC6: one scene-core track as the contract writes it — `{ prop, keys: [[progress, value]], from? }`. Typed here, not
|
|
100
|
+
* imported: generation-core stamps it verbatim and scene-core reads (and normalizes) it where it plays.
|
|
101
|
+
*/
|
|
102
|
+
export interface PatternTrack {
|
|
103
|
+
readonly prop: string;
|
|
104
|
+
readonly keys: ReadonlyArray<readonly [number, number | string]>;
|
|
105
|
+
readonly from?: string;
|
|
93
106
|
}
|
|
94
107
|
|
|
95
108
|
|
|
@@ -138,6 +151,9 @@ export interface SitePattern {
|
|
|
138
151
|
readonly global?: `${PatternGlobalPosition}`;
|
|
139
152
|
/** A navigation pattern's phone shape (CC1): `planNavShape` adds it after the pattern is stamped. */
|
|
140
153
|
readonly phoneMenu?: 'drawer' | 'bar' | 'both';
|
|
154
|
+
/** SC6: a Scene section — held while the page scrolls, moved by the scroll. Only at How animated Expressive, at
|
|
155
|
+
* most one per page and on at most two pages (`validateSitePlan`); it never takes the look's entrances. */
|
|
156
|
+
readonly scene?: boolean;
|
|
141
157
|
readonly node: PatternNode;
|
|
142
158
|
}
|
|
143
159
|
|
|
@@ -295,7 +311,12 @@ export function patternHasForm(pattern: SitePattern): boolean {
|
|
|
295
311
|
return patternNodes(pattern).some(n => !!n.preset);
|
|
296
312
|
}
|
|
297
313
|
|
|
298
|
-
/**
|
|
314
|
+
/** SC6: the level a Scene needs — the site's How animated, never a section's own `enter` (a Scene takes no entrance). */
|
|
315
|
+
export const SCENE_LEVEL = 'expressive';
|
|
316
|
+
/** SC6: Scenes on the home page and at most this many other pages, one per page (`validateSitePlan`). */
|
|
317
|
+
export const SCENE_OTHER_PAGES = 1;
|
|
318
|
+
|
|
319
|
+
/** The library's sections (contract `site.library`), each with whether it is composed. */
|
|
299
320
|
export const SITE_LIBRARY: ReadonlyArray<{ readonly id: string; readonly family: string; readonly composed: boolean }> = SPEC_SITE_LIBRARY;
|
|
300
321
|
|
|
301
322
|
/** One pattern as the model reads it (L0-2): what it is for, what it may write and how long, and what it binds. */
|
|
@@ -316,11 +337,22 @@ export interface PatternManifestEntry {
|
|
|
316
337
|
roles: string[];
|
|
317
338
|
optionalParts: string[];
|
|
318
339
|
form: boolean;
|
|
340
|
+
/** SC6: it holds the page as it scrolls — one per page, the home page and at most one other. */
|
|
341
|
+
scene?: boolean;
|
|
319
342
|
}
|
|
320
343
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
344
|
+
export interface PatternManifestOptions {
|
|
345
|
+
/** The site's How animated: below `SCENE_LEVEL` the Scenes are left out — a model cannot choose what it never sees. */
|
|
346
|
+
animate?: string | null;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* The composed library as the model reads it — every pattern, its budgets under `density` (M1-3's manifest). Given the
|
|
351
|
+
* site's How animated (SC6), the Scenes are listed only at `SCENE_LEVEL`, marked `scene`; without it, all of them.
|
|
352
|
+
*/
|
|
353
|
+
export function patternManifest(density?: string | null, options: PatternManifestOptions = {}): PatternManifestEntry[] {
|
|
354
|
+
const scenes = !('animate' in options) || options.animate === SCENE_LEVEL;
|
|
355
|
+
return Object.entries(SITE_PATTERNS).filter(([, p]) => scenes || !p.scene).map(([id, p]) => ({
|
|
324
356
|
id, family: p.family, label: p.label, intent: p.intent, ...(p.global ? { global: p.global } : {}),
|
|
325
357
|
slots: Object.fromEntries(Object.keys(patternSlotBudgets(p)).map(slot => [slot, slotBudget(p, slot, density) as number])),
|
|
326
358
|
links: patternLinkSlots(p),
|
|
@@ -328,6 +360,7 @@ export function patternManifest(density?: string | null): PatternManifestEntry[]
|
|
|
328
360
|
roles: [...new Set(patternRoleNeeds(p).map(r => `${r.scope}.@${r.role}${r.optional ? OPTIONAL_MARK : ''}`))],
|
|
329
361
|
optionalParts: patternOptionalParts(p),
|
|
330
362
|
form: patternHasForm(p),
|
|
363
|
+
...(p.scene ? { scene: true } : {}),
|
|
331
364
|
}));
|
|
332
365
|
}
|
|
333
366
|
|
|
@@ -34,6 +34,9 @@ export interface SerializedNode {
|
|
|
34
34
|
itemKey?: string;
|
|
35
35
|
/** A targeted state's driving node (CC2: an icon's `trigger-on` → its item). */
|
|
36
36
|
stateTriggers?: Partial<Record<string, string>>;
|
|
37
|
+
/** SC6: a Scene layer's tracks (scene-core `SceneTrack`), and its phone's own. Additive. */
|
|
38
|
+
sceneTracks?: unknown[];
|
|
39
|
+
scenePhoneTracks?: unknown[];
|
|
37
40
|
bindings: SerializedBinding[];
|
|
38
41
|
interactions: unknown[];
|
|
39
42
|
isGlobal?: boolean;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { DesignChoices } from '@vectoriox/iox-ui/design-core';
|
|
2
2
|
|
|
3
|
-
import { BindScope, patternNeedsBinding, PatternGlobalPosition, patternScopes, SITE_PATTERNS } from './patterns';
|
|
3
|
+
import { BindScope, patternNeedsBinding, PatternGlobalPosition, patternScopes, SCENE_LEVEL, SITE_PATTERNS } from './patterns';
|
|
4
4
|
import { GlobalSlot, PagePlan, PageSectionPlan, SiteBusiness, SiteLocale, SitePlan, SitePlanSourceKind, SITE_PLAN_VERSION } from './site-plan.model';
|
|
5
5
|
import { STUDIO_TEMPLATE } from './templates';
|
|
6
6
|
|
|
@@ -39,7 +39,7 @@ export function showcasePages(): PagePlan[] {
|
|
|
39
39
|
const byFamily = new Map<string, string[]>();
|
|
40
40
|
const onItemPage: string[] = [];
|
|
41
41
|
for (const [id, p] of Object.entries(SITE_PATTERNS)) {
|
|
42
|
-
if (p.global) continue;
|
|
42
|
+
if (p.global || p.scene) continue;
|
|
43
43
|
if (readsRouteItem(id)) { onItemPage.push(id); continue; }
|
|
44
44
|
byFamily.set(p.family, [...(byFamily.get(p.family) ?? []), id]);
|
|
45
45
|
}
|
|
@@ -62,20 +62,31 @@ export function showcaseGlobals(): { headers: string[]; footers: string[] } {
|
|
|
62
62
|
return { headers: of(PatternGlobalPosition.Before), footers: of(PatternGlobalPosition.After) };
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
/**
|
|
65
|
+
/** SC6: the Scene patterns — each shown alone on the home page of its own plan, as a site may hold one (validateScenes). */
|
|
66
|
+
export function showcaseScenes(): string[] {
|
|
67
|
+
return Object.entries(SITE_PATTERNS).filter(([, p]) => p.scene && !p.global).map(([id]) => id);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The showcase as Site Plans — as many as it takes for every header and every footer to be composed once, then one per
|
|
72
|
+
* Scene pattern (SC6): its home page holds that Scene and nothing else, at How animated Expressive, the only level a
|
|
73
|
+
* Scene is composed at.
|
|
74
|
+
*/
|
|
66
75
|
export function showcasePlans(input: ShowcaseInput): SitePlan[] {
|
|
67
76
|
const { headers, footers } = showcaseGlobals();
|
|
68
77
|
const count = Math.max(headers.length, footers.length, 1);
|
|
69
78
|
const pages = showcasePages();
|
|
70
|
-
|
|
79
|
+
const plan = (i: number, planPages: PagePlan[], design: DesignChoices): SitePlan => ({
|
|
71
80
|
version: SITE_PLAN_VERSION,
|
|
72
81
|
source: { kind: SitePlanSourceKind.Template, templateId: 'showcase', templateVersion: 1 },
|
|
73
82
|
business: JSON.parse(JSON.stringify(input.business)),
|
|
74
83
|
...(input.locale ? { locale: input.locale } : {}),
|
|
75
|
-
design: JSON.parse(JSON.stringify(
|
|
84
|
+
design: JSON.parse(JSON.stringify(design)),
|
|
76
85
|
contentTypes: JSON.parse(JSON.stringify(STUDIO_TEMPLATE.contentTypes)),
|
|
77
86
|
dataSources: JSON.parse(JSON.stringify(STUDIO_TEMPLATE.dataSources)),
|
|
78
|
-
pages: JSON.parse(JSON.stringify(
|
|
87
|
+
pages: JSON.parse(JSON.stringify(planPages)),
|
|
79
88
|
globals: { [GlobalSlot.Header]: headers[i % headers.length], [GlobalSlot.Footer]: footers[i % footers.length] } as SitePlan['globals'],
|
|
80
|
-
})
|
|
89
|
+
});
|
|
90
|
+
const scenes = showcaseScenes().map((id, i) => plan(i, [{ key: 'home', name: 'Home', route: '/', isHome: true, inNav: false, sections: [sectionFor(id)] }], { ...input.design, animate: SCENE_LEVEL }));
|
|
91
|
+
return [...Array.from({ length: count }, (_, i) => plan(i, pages, input.design)), ...scenes];
|
|
81
92
|
}
|