@bleedingdev/modern-js-create 3.2.0-ultramodern.51 → 3.2.0-ultramodern.53

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.
Files changed (2) hide show
  1. package/dist/index.js +453 -858
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1436,6 +1436,8 @@ import { ultramodernLocalisedUrls } from './src/routes/ultramodern-route-metadat
1436
1436
  type ZephyrRspackConfig = Parameters<ReturnType<typeof withZephyrRspack>>[0];
1437
1437
 
1438
1438
  const zephyrEnabled = process.env['ULTRAMODERN_ZEPHYR'] !== 'false';
1439
+ const cloudflareDeployEnabled =
1440
+ process.env['MODERNJS_DEPLOY'] === 'cloudflare';
1439
1441
 
1440
1442
  const zephyrRspackPlugin = () => ({
1441
1443
  name: 'ultramodern-zephyr-rspack-plugin',
@@ -1526,13 +1528,17 @@ ${bffPluginEntry} moduleFederationPlugin(),
1526
1528
  ]);
1527
1529
  },
1528
1530
  },
1529
- deploy: {
1530
- target: 'cloudflare',
1531
- worker: {
1532
- name: cloudflareWorkerName,
1533
- ssr: true,
1534
- },
1535
- },
1531
+ ...(cloudflareDeployEnabled
1532
+ ? {
1533
+ deploy: {
1534
+ target: 'cloudflare',
1535
+ worker: {
1536
+ name: cloudflareWorkerName,
1537
+ ssr: true,
1538
+ },
1539
+ },
1540
+ }
1541
+ : {}),
1536
1542
  server: {
1537
1543
  port,
1538
1544
  publicDir: './locales',
@@ -1983,6 +1989,10 @@ function createAppEnvDts(app, remotes = remoteApps) {
1983
1989
  return `/// <reference types='@modern-js/app-tools/types' />
1984
1990
 
1985
1991
  declare const ULTRAMODERN_SITE_URL: string;
1992
+ declare module '*.svg' {
1993
+ const url: string;
1994
+ export default url;
1995
+ }
1986
1996
  ${remoteModuleDeclarations ? `\n${remoteModuleDeclarations}` : ''}`;
1987
1997
  }
1988
1998
  function createServiceModernConfigFor(service = effectService) {
@@ -2066,522 +2076,13 @@ function createCssTokenImport(scope) {
2066
2076
  return `@import '${ultramodern_workspace_packageName(scope, 'shared-design-tokens')}/tokens.css';\n`;
2067
2077
  }
2068
2078
  function createShellStyles(enableTailwind, scope) {
2069
- return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2070
-
2071
- @layer ultramodern-shell-base {
2072
- :root {
2073
- color: var(--um-color-foreground);
2074
- background: var(--um-color-canvas);
2075
- font-family:
2076
- Geist,
2077
- Inter,
2078
- ui-sans-serif,
2079
- system-ui,
2080
- -apple-system,
2081
- BlinkMacSystemFont,
2082
- "Segoe UI",
2083
- sans-serif;
2084
- }
2085
-
2086
- body {
2087
- margin: 0;
2079
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}`;
2088
2080
  }
2089
-
2090
- main {
2091
- min-height: 100vh;
2092
- padding: 2rem;
2093
- }
2094
-
2095
- nav {
2096
- display: flex;
2097
- gap: 0.75rem;
2098
- margin-bottom: 2rem;
2099
- }
2100
-
2101
- a {
2102
- color: var(--um-color-link);
2103
- }
2104
-
2105
- .commerce-shell {
2106
- background: #f1eadc;
2107
- color: #0b0a08;
2108
- min-height: 100vh;
2109
- padding: 1.5rem clamp(1rem, 4vw, 3rem) 4rem;
2110
- }
2111
-
2112
- .commerce-shell-actions {
2113
- align-items: center;
2114
- display: flex;
2115
- flex-wrap: wrap;
2116
- gap: 0.75rem;
2117
- justify-content: flex-end;
2118
- margin: -4.25rem auto 3rem;
2119
- max-width: 88rem;
2120
- }
2121
-
2122
- .commerce-language {
2123
- margin: 0;
2124
- }
2125
-
2126
- .commerce-page {
2127
- margin: 3rem auto 0;
2128
- max-width: 88rem;
2129
- }
2130
-
2131
- .commerce-hero {
2132
- padding: 4rem 0 2rem;
2133
- }
2134
-
2135
- .commerce-eyebrow {
2136
- color: #00624b;
2137
- font-size: 0.85rem;
2138
- font-weight: 850;
2139
- letter-spacing: 0.16rem;
2140
- text-transform: uppercase;
2141
- }
2142
-
2143
- .commerce-title {
2144
- font-size: clamp(2.5rem, 6vw, 4.8rem);
2145
- line-height: 0.95;
2146
- margin: 0.65rem 0 1.4rem;
2147
- max-width: 58rem;
2148
- }
2149
-
2150
- .commerce-lede {
2151
- color: #555149;
2152
- font-size: 1.2rem;
2153
- line-height: 1.65;
2154
- max-width: 42rem;
2155
- }
2156
-
2157
- .commerce-checkout {
2158
- align-items: center;
2159
- display: flex;
2160
- flex-wrap: wrap;
2161
- gap: 0.75rem;
2162
- margin-top: 1.5rem;
2163
- }
2164
-
2165
- .commerce-pill,
2166
- .commerce-button,
2167
- .commerce-link-button,
2168
- .commerce-cart-button {
2169
- align-items: center;
2170
- border-radius: 999px;
2171
- border: 0.0625rem solid rgba(23, 23, 23, 0.14);
2172
- box-shadow: 0 0.25rem 0.75rem rgba(20, 17, 10, 0.08);
2173
- color: #14120d;
2174
- display: inline-flex;
2175
- font: inherit;
2176
- font-weight: 750;
2177
- justify-content: center;
2178
- min-height: 2.5rem;
2179
- padding: 0.65rem 1.05rem;
2180
- text-decoration: none;
2181
- }
2182
-
2183
- .commerce-button {
2184
- background: #00624b;
2185
- border-color: #00624b;
2186
- color: #ffffff;
2187
- }
2188
-
2189
- .commerce-link-button,
2190
- .commerce-pill,
2191
- .commerce-cart-button {
2192
- background: rgba(255, 255, 255, 0.92);
2193
- }
2194
-
2195
- .commerce-boundary-toggle {
2196
- align-items: center;
2197
- background: rgba(255, 255, 255, 0.94);
2198
- border: 0.0625rem solid rgba(23, 23, 23, 0.12);
2199
- border-radius: 0.8rem;
2200
- bottom: 1.5rem;
2201
- box-shadow: 0 0.75rem 2rem rgba(18, 15, 10, 0.14);
2202
- color: #14120d;
2203
- display: flex;
2204
- gap: 0.65rem;
2205
- left: 1.5rem;
2206
- padding: 0.8rem 1rem;
2207
- position: fixed;
2208
- z-index: 80;
2209
- }
2210
-
2211
- .commerce-boundary-toggle input {
2212
- accent-color: #00624b;
2213
- height: 1rem;
2214
- width: 1rem;
2215
- }
2216
-
2217
- @media (max-width: 860px) {
2218
- .commerce-shell-actions {
2219
- justify-content: flex-start;
2220
- margin-top: 1rem;
2221
- }
2222
- }
2223
- }
2224
-
2225
- @layer ultramodern-shell-overlay {
2226
- .boundary-overlay {
2227
- inset: 0;
2228
- pointer-events: none;
2229
- position: fixed;
2230
- z-index: 70;
2081
+ function createRemoteStyles(enableTailwind, scope, _app) {
2082
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}`;
2231
2083
  }
2232
-
2233
- .boundary-overlay__box {
2234
- border: 0.0625rem solid var(--boundary-color);
2235
- border-radius: 0.55rem;
2236
- box-shadow:
2237
- 0 0 0 0.0625rem rgba(255, 255, 255, 0.72),
2238
- 0 0.35rem 1.25rem color-mix(in srgb, var(--boundary-color) 20%, transparent);
2239
- position: fixed;
2240
- }
2241
-
2242
- .boundary-overlay__label {
2243
- background: color-mix(in srgb, var(--boundary-color) 88%, white);
2244
- border-radius: 999px;
2245
- color: #0b0a08;
2246
- font-size: 0.7rem;
2247
- font-weight: 850;
2248
- line-height: 1;
2249
- padding: 0.3rem 0.55rem;
2250
- position: absolute;
2251
- right: 0.35rem;
2252
- top: 0.35rem;
2253
- white-space: nowrap;
2254
- }
2255
-
2256
- .boundary-overlay__box[data-label-placement="above"] .boundary-overlay__label {
2257
- bottom: calc(100% + 0.25rem);
2258
- top: auto;
2259
- }
2260
- }
2261
- `;
2262
- }
2263
- function createRemoteStyles(enableTailwind, scope, app) {
2264
- if ([
2265
- 'explore',
2266
- 'decide',
2267
- 'checkout'
2268
- ].includes(app.domain ?? '')) return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2269
-
2270
- @layer ultramodern-remote-${app.domain} {
2271
- .commerce-shell {
2272
- background: #f1eadc;
2273
- color: #0b0a08;
2274
- min-height: 100vh;
2275
- padding: 1.5rem clamp(1rem, 4vw, 3rem) 4rem;
2276
- }
2277
-
2278
- .commerce-header,
2279
- .commerce-footer {
2280
- align-items: center;
2281
- background: rgba(255, 255, 255, 0.86);
2282
- box-shadow: 0 0.625rem 1.875rem rgba(25, 20, 12, 0.08);
2283
- display: flex;
2284
- gap: 1.25rem;
2285
- justify-content: space-between;
2286
- margin: 0 auto;
2287
- max-width: 88rem;
2288
- padding: 1.25rem 1.75rem;
2289
- }
2290
-
2291
- .commerce-logo {
2292
- font-size: 1.35rem;
2293
- font-weight: 800;
2294
- }
2295
-
2296
- .commerce-nav,
2297
- .commerce-actions,
2298
- .commerce-language {
2299
- align-items: center;
2300
- display: flex;
2301
- flex-wrap: wrap;
2302
- gap: 0.75rem;
2303
- }
2304
-
2305
- .commerce-nav {
2306
- margin: 0;
2307
- }
2308
-
2309
- .commerce-pill,
2310
- .commerce-button,
2311
- .commerce-link-button,
2312
- .commerce-cart-button,
2313
- .commerce-quantity-button {
2314
- align-items: center;
2315
- border-radius: 999px;
2316
- border: 0.0625rem solid rgba(23, 23, 23, 0.14);
2317
- box-shadow: 0 0.25rem 0.75rem rgba(20, 17, 10, 0.08);
2318
- color: #14120d;
2319
- display: inline-flex;
2320
- font: inherit;
2321
- font-weight: 750;
2322
- justify-content: center;
2323
- min-height: 2.5rem;
2324
- padding: 0.65rem 1.05rem;
2325
- text-decoration: none;
2326
- }
2327
-
2328
- .commerce-button {
2329
- background: #00624b;
2330
- border-color: #00624b;
2331
- color: #ffffff;
2332
- }
2333
-
2334
- .commerce-link-button,
2335
- .commerce-pill,
2336
- .commerce-cart-button,
2337
- .commerce-quantity-button {
2338
- background: rgba(255, 255, 255, 0.92);
2339
- }
2340
-
2341
- .commerce-page {
2342
- margin: 3rem auto 0;
2343
- max-width: 88rem;
2344
- }
2345
-
2346
- .commerce-product {
2347
- align-items: center;
2348
- display: grid;
2349
- gap: clamp(2rem, 5vw, 4rem);
2350
- grid-template-columns: minmax(0, 1fr) minmax(20rem, 0.95fr);
2351
- }
2352
-
2353
- .commerce-product-media {
2354
- aspect-ratio: 1 / 0.92;
2355
- background:
2356
- linear-gradient(180deg, rgba(255, 255, 255, 0.62), rgba(255, 255, 255, 0) 42%),
2357
- linear-gradient(135deg, #97c66d 0 20%, #6f9748 20% 34%, #d6c15d 34% 36%, #6a8f3e 36% 46%, #315824 46% 64%, #8bb85e 64% 100%);
2358
- border: 1.25rem solid #ffe987;
2359
- border-radius: 1.6rem;
2360
- box-shadow: inset 0 -7rem 8rem rgba(58, 77, 35, 0.22);
2361
- overflow: hidden;
2362
- }
2363
-
2364
- .commerce-product-media::after {
2365
- background:
2366
- radial-gradient(circle at 27% 76%, #1e2422 0 5%, transparent 5.4%),
2367
- radial-gradient(circle at 55% 76%, #1e2422 0 6%, transparent 6.4%),
2368
- linear-gradient(0deg, #004b7b 0 100%);
2369
- border-radius: 1.2rem;
2370
- content: "";
2371
- display: block;
2372
- height: 19%;
2373
- margin: 58% auto 0;
2374
- width: 42%;
2375
- }
2376
-
2377
- .commerce-eyebrow {
2378
- color: #00624b;
2379
- font-size: 0.85rem;
2380
- font-weight: 850;
2381
- letter-spacing: 0.16rem;
2382
- text-transform: uppercase;
2383
- }
2384
-
2385
- .commerce-title {
2386
- font-size: clamp(2.5rem, 6vw, 4.8rem);
2387
- line-height: 0.95;
2388
- margin: 0.65rem 0 1.4rem;
2389
- }
2390
-
2391
- .commerce-lede {
2392
- color: #555149;
2393
- font-size: 1.2rem;
2394
- line-height: 1.65;
2395
- max-width: 42rem;
2396
- }
2397
-
2398
- .commerce-facts {
2399
- display: grid;
2400
- gap: 1rem;
2401
- grid-template-columns: repeat(3, minmax(0, 1fr));
2402
- margin: 2rem 0;
2403
- }
2404
-
2405
- .commerce-fact,
2406
- .commerce-card,
2407
- .commerce-cart-panel {
2408
- background: rgba(255, 255, 255, 0.92);
2409
- border-radius: 1rem;
2410
- box-shadow: 0 0.5rem 1.25rem rgba(25, 20, 12, 0.08);
2411
- padding: 1.25rem;
2412
- }
2413
-
2414
- .commerce-fact span,
2415
- .commerce-card span {
2416
- color: #767067;
2417
- display: block;
2418
- font-weight: 750;
2419
- margin-bottom: 0.45rem;
2420
- }
2421
-
2422
- .commerce-fact strong {
2423
- font-size: 1.1rem;
2424
- }
2425
-
2426
- .commerce-checkout {
2427
- align-items: center;
2428
- display: flex;
2429
- flex-wrap: wrap;
2430
- gap: 0.75rem;
2431
- }
2432
-
2433
- .commerce-section-title {
2434
- font-size: 1.8rem;
2435
- margin: 4.5rem 0 1.5rem;
2436
- }
2437
-
2438
- .commerce-grid {
2439
- display: grid;
2440
- gap: 1rem;
2441
- grid-template-columns: repeat(2, minmax(0, 1fr));
2442
- }
2443
-
2444
- .commerce-card strong {
2445
- display: block;
2446
- font-size: 1.45rem;
2447
- }
2448
-
2449
- .commerce-cart-panel {
2450
- margin-top: 2rem;
2451
- }
2452
-
2453
- .commerce-cart-line {
2454
- align-items: center;
2455
- border-top: 0.0625rem solid rgba(23, 23, 23, 0.12);
2456
- display: grid;
2457
- gap: 1rem;
2458
- grid-template-columns: minmax(0, 1fr) auto;
2459
- padding: 1rem 0;
2460
- }
2461
-
2462
- .commerce-cart-line:first-of-type {
2463
- border-top: 0;
2464
- }
2465
-
2466
- .commerce-quantity {
2467
- align-items: center;
2468
- display: flex;
2469
- gap: 0.45rem;
2470
- }
2471
-
2472
- .commerce-quantity-button {
2473
- min-height: 2rem;
2474
- min-width: 2rem;
2475
- padding: 0.25rem;
2476
- }
2477
-
2478
- .commerce-boundary-toggle {
2479
- align-items: center;
2480
- background: rgba(255, 255, 255, 0.92);
2481
- border-radius: 0.8rem;
2482
- bottom: 1.5rem;
2483
- box-shadow: 0 0.75rem 2rem rgba(18, 15, 10, 0.14);
2484
- display: flex;
2485
- gap: 0.65rem;
2486
- left: 1.5rem;
2487
- padding: 0.8rem 1rem;
2488
- position: fixed;
2489
- z-index: 80;
2490
- }
2491
-
2492
- .commerce-boundary-toggle input {
2493
- accent-color: #00624b;
2494
- height: 1rem;
2495
- width: 1rem;
2496
- }
2497
-
2498
- @media (max-width: 860px) {
2499
- .commerce-header,
2500
- .commerce-footer,
2501
- .commerce-product,
2502
- .commerce-grid,
2503
- .commerce-facts {
2504
- grid-template-columns: 1fr;
2505
- }
2506
-
2507
- .commerce-header,
2508
- .commerce-footer {
2509
- align-items: flex-start;
2510
- flex-direction: column;
2511
- }
2512
-
2513
- .commerce-product-media {
2514
- min-height: 20rem;
2515
- }
2516
- }
2517
- }
2518
- `;
2519
- return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2520
-
2521
- @layer ultramodern-remote-${app.domain ?? app.id} {
2522
- [data-app-id="${app.id}"] {
2523
- color: var(--um-color-foreground);
2524
- background: var(--um-color-surface);
2525
- font-family:
2526
- Geist,
2527
- Inter,
2528
- ui-sans-serif,
2529
- system-ui,
2530
- -apple-system,
2531
- BlinkMacSystemFont,
2532
- "Segoe UI",
2533
- sans-serif;
2534
- min-height: 100vh;
2535
- }
2536
-
2537
- [data-app-id="${app.id}"] main {
2538
- min-height: 100vh;
2539
- padding: 2rem;
2540
- }
2541
-
2542
- [data-app-id="${app.id}"] nav {
2543
- display: flex;
2544
- gap: 0.75rem;
2545
- margin-bottom: 2rem;
2546
- }
2547
-
2548
- [data-app-id="${app.id}"] a {
2549
- color: var(--um-color-link);
2550
- }
2551
-
2552
- [data-mf-remote="${app.id}"] {
2553
- border: 0.0625rem solid color-mix(in srgb, var(--um-color-accent) 30%, transparent);
2554
- border-radius: 0.5rem;
2555
- padding: 1rem;
2556
- }
2557
- }
2558
- `;
2559
- }
2560
- function createServiceStyles(enableTailwind, scope, service) {
2561
- return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}
2562
-
2563
- @layer ultramodern-effect-service {
2564
- [data-app-id="${service.id}"] {
2565
- color: var(--um-color-foreground);
2566
- background: var(--um-color-surface);
2567
- font-family:
2568
- Geist,
2569
- Inter,
2570
- ui-sans-serif,
2571
- system-ui,
2572
- -apple-system,
2573
- BlinkMacSystemFont,
2574
- "Segoe UI",
2575
- sans-serif;
2576
- min-height: 100vh;
2577
- }
2578
-
2579
- [data-app-id="${service.id}"] main {
2580
- min-height: 100vh;
2581
- padding: 2rem;
2582
- }
2583
- }
2584
- `;
2084
+ function createServiceStyles(enableTailwind, scope, _service) {
2085
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}`;
2585
2086
  }
2586
2087
  function createAppStyles(enableTailwind, scope, app) {
2587
2088
  return 'shell' === app.kind ? createShellStyles(enableTailwind, scope) : createRemoteStyles(enableTailwind, scope, app);
@@ -2602,6 +2103,86 @@ export default {
2602
2103
  } satisfies Config;
2603
2104
  `;
2604
2105
  }
2106
+ function createCommerceAssetSvg(title, palette) {
2107
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="900" viewBox="0 0 1440 900" role="img" aria-label="${title}">
2108
+ <defs>
2109
+ <linearGradient id="sky" x1="0" x2="0" y1="0" y2="1">
2110
+ <stop offset="0" stop-color="${palette.sky}"/>
2111
+ <stop offset="1" stop-color="#fff8dc"/>
2112
+ </linearGradient>
2113
+ <linearGradient id="field" x1="0" x2="1" y1="0" y2="1">
2114
+ <stop offset="0" stop-color="${palette.ground}"/>
2115
+ <stop offset="1" stop-color="${palette.accent}"/>
2116
+ </linearGradient>
2117
+ </defs>
2118
+ <rect width="1440" height="900" fill="url(#sky)"/>
2119
+ <path d="M0 566c172-78 330-102 474-72 125 26 219 91 340 106 170 21 339-74 626-43v343H0z" fill="url(#field)"/>
2120
+ <path d="M0 686c205-70 451-66 738 12 287 77 521 66 702-33v235H0z" fill="#4f7f38" opacity=".55"/>
2121
+ <g fill="none" stroke="#fff6b7" stroke-linecap="round" stroke-width="10" opacity=".55">
2122
+ <path d="M108 820c205-138 382-202 530-192"/>
2123
+ <path d="M322 862c176-134 338-198 486-193"/>
2124
+ <path d="M583 886c119-121 260-190 422-207"/>
2125
+ <path d="M868 878c95-94 207-153 336-176"/>
2126
+ </g>
2127
+ <g transform="translate(430 430)">
2128
+ <circle cx="170" cy="210" r="92" fill="#161616"/>
2129
+ <circle cx="170" cy="210" r="54" fill="#d7c46d"/>
2130
+ <circle cx="514" cy="214" r="108" fill="#161616"/>
2131
+ <circle cx="514" cy="214" r="63" fill="#d7c46d"/>
2132
+ <path d="M194 142h194l72-100h114c49 0 89 39 89 88v57H625l-51-90H452l-78 114H209z" fill="${palette.tractor}"/>
2133
+ <path d="M283 67h134l-54 73H249z" fill="#c9ecff" opacity=".72"/>
2134
+ <path d="M120 184h430v54H120z" fill="${palette.tractor}"/>
2135
+ <path d="M578 52l60-35M618 37l34 72" stroke="#171717" stroke-linecap="round" stroke-width="14"/>
2136
+ <path d="M90 236h578" stroke="#171717" stroke-linecap="round" stroke-width="18"/>
2137
+ </g>
2138
+ </svg>
2139
+ `;
2140
+ }
2141
+ function commerceAssetsForApp(app) {
2142
+ if ('shell' === app.kind) return {
2143
+ 'src/assets/hero-field.svg': createCommerceAssetSvg('Tractor crossing cultivated fields', {
2144
+ accent: '#d6b85d',
2145
+ ground: '#84ad58',
2146
+ sky: '#9fd6e8',
2147
+ tractor: '#005f73'
2148
+ })
2149
+ };
2150
+ if ('remote-explore' === app.id) return {
2151
+ 'src/assets/autonomy.svg': createCommerceAssetSvg('Autonomous tractor concept', {
2152
+ accent: '#c26a2e',
2153
+ ground: '#668f55',
2154
+ sky: '#d5e7de',
2155
+ tractor: '#f2a51a'
2156
+ }),
2157
+ 'src/assets/field-loader.svg': createCommerceAssetSvg('Field Loader 112 tractor', {
2158
+ accent: '#d6b85d',
2159
+ ground: '#84ad58',
2160
+ sky: '#9fd6e8',
2161
+ tractor: '#00624b'
2162
+ }),
2163
+ 'src/assets/orchard.svg': createCommerceAssetSvg('Orchard tractor between tight rows', {
2164
+ accent: '#b45b2d',
2165
+ ground: '#6f9b4a',
2166
+ sky: '#c9ebff',
2167
+ tractor: '#1d5d9b'
2168
+ }),
2169
+ 'src/assets/vineyard.svg': createCommerceAssetSvg('Vineyard narrow tractor', {
2170
+ accent: '#b88d58',
2171
+ ground: '#5e8a45',
2172
+ sky: '#f1dcb9',
2173
+ tractor: '#914d76'
2174
+ })
2175
+ };
2176
+ if ('remote-decide' === app.id) return {
2177
+ 'src/assets/field-loader.svg': createCommerceAssetSvg('Field Loader 112 tractor detail', {
2178
+ accent: '#d6b85d',
2179
+ ground: '#84ad58',
2180
+ sky: '#9fd6e8',
2181
+ tractor: '#00624b'
2182
+ })
2183
+ };
2184
+ return {};
2185
+ }
2605
2186
  function createLocalizedHeadComponent() {
2606
2187
  return `const fallbackLanguage = 'en';
2607
2188
  const supportedLanguages = ['en', 'cs'] as const;
@@ -2756,302 +2337,269 @@ function createShellPage() {
2756
2337
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2757
2338
  import { Helmet } from '@modern-js/runtime/head';
2758
2339
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2759
- import { useEffect, useState, type ComponentType } from 'react';
2760
- import BoundaryOverlay from '../boundary-overlay';
2340
+ import heroField from '../../assets/hero-field.svg';
2341
+ import ShellFrame from '../shell-frame';
2342
+ import { StorePicker } from '../remote-components';
2761
2343
  import { ultramodernLocalisedUrls } from '../ultramodern-route-metadata';
2762
2344
  import { ultramodernUiMarker } from '../../ultramodern-build';
2763
2345
 
2764
- const languageCodes = ['en', 'cs'] as const;
2765
-
2766
2346
  ${createLocalizedHeadComponent()}
2767
- type HomeRouteRemotes = {
2768
- Header: ComponentType;
2769
- MiniCart: ComponentType;
2770
- StorePicker: ComponentType;
2771
- };
2772
-
2773
- const useHomeRouteRemotes = () => {
2774
- const [remotes, setRemotes] = useState<HomeRouteRemotes | null>(null);
2775
-
2776
- useEffect(() => {
2777
- let mounted = true;
2778
- import('../remote-components').then(({ Header, MiniCart, StorePicker }) => {
2779
- if (mounted) {
2780
- setRemotes({ Header, MiniCart, StorePicker });
2781
- }
2782
- });
2783
-
2784
- return () => {
2785
- mounted = false;
2786
- };
2787
- }, []);
2788
-
2789
- return remotes;
2790
- };
2791
-
2792
2347
  export default function ShellHome() {
2793
2348
  const { i18nInstance, language } = useModernI18n();
2794
2349
  const t = i18nInstance['t'].bind(i18nInstance);
2795
- const location = useLocation();
2796
- const suffix = locationSuffix(location);
2797
- const remotes = useHomeRouteRemotes();
2798
- const Header = remotes?.Header;
2799
- const MiniCart = remotes?.MiniCart;
2800
- const StorePicker = remotes?.StorePicker;
2801
2350
 
2802
2351
  return (
2803
- <main className="commerce-shell">
2352
+ <ShellFrame>
2804
2353
  <LocalizedHead />
2805
- <BoundaryOverlay />
2806
- {Header ? <Header /> : null}
2807
- <div className="commerce-shell-actions">
2808
- <nav aria-label={t('shell.language.switcher')} className="commerce-language">
2809
- {languageCodes.map(code => (
2810
- <a
2811
- aria-current={language === code ? 'page' : undefined}
2812
- className="commerce-pill"
2813
- href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
2814
- key={code}
2815
- >
2816
- {t(\`shell.language.\${code}\`)}
2817
- </a>
2818
- ))}
2819
- </nav>
2820
- {MiniCart ? <MiniCart /> : null}
2821
- </div>
2822
- <section className="commerce-page commerce-hero">
2823
- <p className="commerce-eyebrow">{t('shell.hero.eyebrow')}</p>
2824
- <h1 className="commerce-title">{t('shell.title')}</h1>
2825
- <p className="commerce-lede">{t('shell.hero.lede')}</p>
2826
- <div className="commerce-checkout">
2827
- <a className="commerce-button" href={\`/\${language}/tractors/field-loader-112\`}>
2354
+ <section className="mx-auto grid max-w-7xl items-center gap-8 py-8 md:grid-cols-[0.9fr_1.1fr] lg:gap-14">
2355
+ <div className="min-w-0">
2356
+ <p className="text-xs font-black uppercase tracking-[0.18em] text-emerald-800">{t('shell.hero.eyebrow')}</p>
2357
+ <h1 className="mt-3 max-w-3xl text-5xl font-black leading-none tracking-normal text-stone-950 md:text-7xl">{t('shell.title')}</h1>
2358
+ <p className="mt-5 max-w-2xl text-lg leading-8 text-stone-600">{t('shell.hero.lede')}</p>
2359
+ <div className="mt-7 flex flex-wrap gap-3">
2360
+ <a className="inline-flex min-h-11 items-center justify-center rounded-full bg-emerald-800 px-5 font-bold text-white shadow-lg shadow-stone-900/10" href={\`/\${language}/tractors/field-loader-112\`}>
2828
2361
  {t('shell.hero.primary')}
2829
- </a>
2830
- <a className="commerce-link-button" href={\`/\${language}/tractors\`}>
2362
+ </a>
2363
+ <a className="inline-flex min-h-11 items-center justify-center rounded-full border border-stone-900/15 bg-white/90 px-5 font-bold text-stone-950 shadow-lg shadow-stone-900/10" href={\`/\${language}/tractors\`}>
2831
2364
  {t('shell.hero.secondary')}
2832
- </a>
2365
+ </a>
2366
+ </div>
2833
2367
  </div>
2368
+ <img alt="" className="aspect-[16/10] w-full rounded-3xl bg-stone-200 object-cover shadow-2xl shadow-stone-900/20" src={heroField} />
2834
2369
  </section>
2835
- {StorePicker ? <StorePicker /> : null}
2836
- <p data-testid="ultramodern-preset">presetUltramodern workspace</p>
2837
- <p data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
2370
+ <StorePicker />
2371
+ <p className="sr-only" data-testid="ultramodern-preset">presetUltramodern workspace</p>
2372
+ <p className="sr-only" data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
2838
2373
  {ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
2839
2374
  </p>
2840
- </main>
2375
+ </ShellFrame>
2841
2376
  );
2842
2377
  }
2843
2378
  `;
2844
2379
  }
2845
2380
  function createShellTractorsPage() {
2846
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2847
- import { Helmet } from '@modern-js/runtime/head';
2381
+ return `import { Helmet } from '@modern-js/runtime/head';
2848
2382
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2849
- import { useEffect, useState, type ComponentType } from 'react';
2850
- import BoundaryOverlay from '../../boundary-overlay';
2383
+ import ShellFrame from '../../shell-frame';
2384
+ import { Recommendations } from '../../remote-components';
2851
2385
  import { ultramodernLocalisedUrls } from '../../ultramodern-route-metadata';
2852
2386
 
2853
- const languageCodes = ['en', 'cs'] as const;
2854
-
2855
2387
  ${createLocalizedHeadComponent()}
2856
- type TractorsRouteRemotes = {
2857
- Header: ComponentType;
2858
- MiniCart: ComponentType;
2859
- Recommendations: ComponentType;
2860
- };
2861
-
2862
- const useTractorsRouteRemotes = () => {
2863
- const [remotes, setRemotes] = useState<TractorsRouteRemotes | null>(null);
2864
-
2865
- useEffect(() => {
2866
- let mounted = true;
2867
- import('../../remote-components').then(({ Header, MiniCart, Recommendations }) => {
2868
- if (mounted) {
2869
- setRemotes({ Header, MiniCart, Recommendations });
2870
- }
2871
- });
2872
-
2873
- return () => {
2874
- mounted = false;
2875
- };
2876
- }, []);
2877
-
2878
- return remotes;
2879
- };
2880
-
2881
2388
  export default function ShellTractorsPage() {
2882
- const { i18nInstance, language } = useModernI18n();
2883
- const t = i18nInstance['t'].bind(i18nInstance);
2884
- const location = useLocation();
2885
- const suffix = locationSuffix(location);
2886
- const remotes = useTractorsRouteRemotes();
2887
- const Header = remotes?.Header;
2888
- const MiniCart = remotes?.MiniCart;
2889
- const Recommendations = remotes?.Recommendations;
2890
-
2891
2389
  return (
2892
- <main className="commerce-shell">
2390
+ <ShellFrame>
2893
2391
  <LocalizedHead />
2894
- <BoundaryOverlay />
2895
- {Header ? <Header /> : null}
2896
- <div className="commerce-shell-actions">
2897
- <nav aria-label={t('shell.language.switcher')} className="commerce-language">
2898
- {languageCodes.map(code => (
2899
- <a
2900
- aria-current={language === code ? 'page' : undefined}
2901
- className="commerce-pill"
2902
- href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
2903
- key={code}
2904
- >
2905
- {t(\`shell.language.\${code}\`)}
2906
- </a>
2907
- ))}
2908
- </nav>
2909
- {MiniCart ? <MiniCart /> : null}
2910
- </div>
2911
- {Recommendations ? <Recommendations /> : null}
2912
- </main>
2392
+ <Recommendations />
2393
+ </ShellFrame>
2913
2394
  );
2914
2395
  }
2915
2396
  `;
2916
2397
  }
2917
2398
  function createShellProductPage() {
2918
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2919
- import { Helmet } from '@modern-js/runtime/head';
2399
+ return `import { Helmet } from '@modern-js/runtime/head';
2920
2400
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2921
- import { useEffect, useState, type ComponentType } from 'react';
2922
- import BoundaryOverlay from '../../../boundary-overlay';
2401
+ import ShellFrame from '../../../shell-frame';
2402
+ import { ProductPage } from '../../../remote-components';
2923
2403
  import { ultramodernLocalisedUrls } from '../../../ultramodern-route-metadata';
2924
2404
 
2925
- const languageCodes = ['en', 'cs'] as const;
2926
-
2927
2405
  ${createLocalizedHeadComponent()}
2928
- type ProductRouteRemotes = {
2929
- Header: ComponentType;
2930
- MiniCart: ComponentType;
2931
- ProductPage: ComponentType;
2932
- };
2933
-
2934
- const useProductRouteRemotes = () => {
2935
- const [remotes, setRemotes] = useState<ProductRouteRemotes | null>(null);
2936
-
2937
- useEffect(() => {
2938
- let mounted = true;
2939
- import('../../../remote-components').then(
2940
- ({ Header, MiniCart, ProductPage }) => {
2941
- if (mounted) {
2942
- setRemotes({ Header, MiniCart, ProductPage });
2943
- }
2944
- },
2945
- );
2946
-
2947
- return () => {
2948
- mounted = false;
2949
- };
2950
- }, []);
2951
-
2952
- return remotes;
2953
- };
2954
-
2955
2406
  export default function ShellProductPage() {
2956
- const { i18nInstance, language } = useModernI18n();
2957
- const t = i18nInstance['t'].bind(i18nInstance);
2958
- const location = useLocation();
2959
- const suffix = locationSuffix(location);
2960
- const remotes = useProductRouteRemotes();
2961
- const Header = remotes?.Header;
2962
- const MiniCart = remotes?.MiniCart;
2963
- const ProductPage = remotes?.ProductPage;
2964
-
2965
2407
  return (
2966
- <main className="commerce-shell">
2408
+ <ShellFrame>
2967
2409
  <LocalizedHead />
2968
- <BoundaryOverlay />
2969
- {Header ? <Header /> : null}
2970
- <div className="commerce-shell-actions">
2971
- <nav aria-label={t('shell.language.switcher')} className="commerce-language">
2972
- {languageCodes.map(code => (
2973
- <a
2974
- aria-current={language === code ? 'page' : undefined}
2975
- className="commerce-pill"
2976
- href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
2977
- key={code}
2978
- >
2979
- {t(\`shell.language.\${code}\`)}
2980
- </a>
2981
- ))}
2982
- </nav>
2983
- {MiniCart ? <MiniCart /> : null}
2984
- </div>
2985
- {ProductPage ? <ProductPage /> : null}
2986
- </main>
2410
+ <ProductPage />
2411
+ </ShellFrame>
2987
2412
  );
2988
2413
  }
2989
2414
  `;
2990
2415
  }
2991
2416
  function createShellCartPage() {
2992
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2993
- import { Helmet } from '@modern-js/runtime/head';
2417
+ return `import { Helmet } from '@modern-js/runtime/head';
2994
2418
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2995
- import { useEffect, useState, type ComponentType } from 'react';
2996
- import BoundaryOverlay from '../../boundary-overlay';
2419
+ import ShellFrame from '../../shell-frame';
2420
+ import { CartPage } from '../../remote-components';
2997
2421
  import { ultramodernLocalisedUrls } from '../../ultramodern-route-metadata';
2998
2422
 
2999
- const languageCodes = ['en', 'cs'] as const;
3000
-
3001
2423
  ${createLocalizedHeadComponent()}
3002
- type CartRouteRemotes = {
3003
- CartPage: ComponentType;
3004
- Header: ComponentType;
2424
+ export default function ShellCartPage() {
2425
+ return (
2426
+ <ShellFrame showCart={false}>
2427
+ <LocalizedHead />
2428
+ <CartPage />
2429
+ </ShellFrame>
2430
+ );
2431
+ }
2432
+ `;
2433
+ }
2434
+ function createShellFrameComponent() {
2435
+ return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2436
+ import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2437
+ import type { ReactNode } from 'react';
2438
+ import BoundaryOverlay from './boundary-overlay';
2439
+ import { Header, MiniCart } from './remote-components';
2440
+ import { ultramodernLocalisedUrls } from './ultramodern-route-metadata';
2441
+
2442
+ const supportedLanguages = ['en', 'cs'] as const;
2443
+ type SupportedLanguage = (typeof supportedLanguages)[number];
2444
+
2445
+ type ShellFrameProps = {
2446
+ children: ReactNode;
2447
+ showCart?: boolean;
3005
2448
  };
3006
2449
 
3007
- const useCartRouteRemotes = () => {
3008
- const [remotes, setRemotes] = useState<CartRouteRemotes | null>(null);
2450
+ const localisedUrls = ultramodernLocalisedUrls as Record<
2451
+ string,
2452
+ Record<SupportedLanguage, string>
2453
+ >;
2454
+
2455
+ const isSupportedLanguage = (value: string): value is SupportedLanguage =>
2456
+ supportedLanguages.includes(value as SupportedLanguage);
3009
2457
 
3010
- useEffect(() => {
3011
- let mounted = true;
3012
- import('../../remote-components').then(({ CartPage, Header }) => {
3013
- if (mounted) {
3014
- setRemotes({ CartPage, Header });
2458
+ const normalisePath = (pathname: string) => {
2459
+ const normalised = pathname.replace(/\\/+$/u, '').replace(/\\/+/gu, '/');
2460
+ return normalised.length > 0 ? normalised : '/';
2461
+ };
2462
+
2463
+ const stripLanguagePrefix = (pathname: string) => {
2464
+ const segments = normalisePath(pathname).split('/').filter(Boolean);
2465
+ if (segments.length > 0 && isSupportedLanguage(segments[0] ?? '')) {
2466
+ segments.shift();
2467
+ }
2468
+ return \`/\${segments.join('/')}\`;
2469
+ };
2470
+
2471
+ const escapeRegExp = (value: string) =>
2472
+ value.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
2473
+
2474
+ const paramName = (segment: string) => segment.slice(1).replace(/\\?$/u, '');
2475
+
2476
+ const matchPattern = (pathname: string, pattern: string) => {
2477
+ const names: string[] = [];
2478
+ const source = normalisePath(pattern)
2479
+ .split('/')
2480
+ .filter(Boolean)
2481
+ .map(segment => {
2482
+ if (segment.startsWith(':')) {
2483
+ names.push(paramName(segment));
2484
+ return segment.endsWith('?') ? '(?:/([^/]+))?' : '/([^/]+)';
3015
2485
  }
3016
- });
2486
+ return \`/\${escapeRegExp(segment)}\`;
2487
+ })
2488
+ .join('');
2489
+ const match = new RegExp(\`^\${source || '/'}$\`).exec(normalisePath(pathname));
3017
2490
 
3018
- return () => {
3019
- mounted = false;
3020
- };
3021
- }, []);
2491
+ if (!match) {
2492
+ return undefined;
2493
+ }
3022
2494
 
3023
- return remotes;
2495
+ return names.reduce<Record<string, string>>((params, name, index) => {
2496
+ params[name] = decodeURIComponent(match[index + 1] ?? '');
2497
+ return params;
2498
+ }, {});
3024
2499
  };
3025
2500
 
3026
- export default function ShellCartPage() {
2501
+ const buildPath = (pattern: string, params: Record<string, string>) => {
2502
+ const path = normalisePath(pattern)
2503
+ .split('/')
2504
+ .filter(Boolean)
2505
+ .map(segment => {
2506
+ if (!segment.startsWith(':')) {
2507
+ return segment;
2508
+ }
2509
+ const value = params[paramName(segment)];
2510
+ return value ? encodeURIComponent(value) : '';
2511
+ })
2512
+ .filter(Boolean)
2513
+ .join('/');
2514
+
2515
+ return \`/\${path}\`;
2516
+ };
2517
+
2518
+ const resolveLocalisedPath = (
2519
+ pathname: string,
2520
+ targetLanguage: SupportedLanguage,
2521
+ ) => {
2522
+ const pathWithoutLanguage = stripLanguagePrefix(pathname);
2523
+
2524
+ for (const entry of Object.values(localisedUrls)) {
2525
+ const targetPattern = entry[targetLanguage];
2526
+ if (!targetPattern) {
2527
+ continue;
2528
+ }
2529
+
2530
+ for (const language of supportedLanguages) {
2531
+ const sourcePattern = entry[language];
2532
+ const params = sourcePattern
2533
+ ? matchPattern(pathWithoutLanguage, sourcePattern)
2534
+ : undefined;
2535
+ if (params) {
2536
+ return buildPath(targetPattern, params);
2537
+ }
2538
+ }
2539
+ }
2540
+
2541
+ return pathWithoutLanguage;
2542
+ };
2543
+
2544
+ const localizedPath = (pathname: string, language: SupportedLanguage) => {
2545
+ const pathWithoutLanguage = resolveLocalisedPath(pathname, language);
2546
+ return pathWithoutLanguage === '/' ? \`/\${language}\` : \`/\${language}\${pathWithoutLanguage}\`;
2547
+ };
2548
+
2549
+ const locationSuffix = (location: {
2550
+ hash?: unknown;
2551
+ search?: unknown;
2552
+ searchStr?: unknown;
2553
+ }) => {
2554
+ const locationSearch =
2555
+ typeof location.searchStr === 'string'
2556
+ ? location.searchStr
2557
+ : typeof location.search === 'string'
2558
+ ? location.search
2559
+ : '';
2560
+ const locationHash = typeof location.hash === 'string' ? location.hash : '';
2561
+
2562
+ return \`\${locationSearch}\${locationHash}\`;
2563
+ };
2564
+
2565
+ export default function ShellFrame({ children, showCart = true }: ShellFrameProps) {
3027
2566
  const { i18nInstance, language } = useModernI18n();
3028
2567
  const t = i18nInstance['t'].bind(i18nInstance);
3029
2568
  const location = useLocation();
3030
2569
  const suffix = locationSuffix(location);
3031
- const remotes = useCartRouteRemotes();
3032
- const Header = remotes?.Header;
3033
- const CartPage = remotes?.CartPage;
3034
2570
 
3035
2571
  return (
3036
- <main className="commerce-shell">
3037
- <LocalizedHead />
2572
+ <main className="min-h-screen bg-um-canvas px-4 py-5 text-um-foreground sm:px-6 lg:px-12">
3038
2573
  <BoundaryOverlay />
3039
- {Header ? <Header /> : null}
3040
- <div className="commerce-shell-actions">
3041
- <nav aria-label={t('shell.language.switcher')} className="commerce-language">
3042
- {languageCodes.map(code => (
3043
- <a
3044
- aria-current={language === code ? 'page' : undefined}
3045
- className="commerce-pill"
3046
- href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
3047
- key={code}
3048
- >
3049
- {t(\`shell.language.\${code}\`)}
3050
- </a>
3051
- ))}
3052
- </nav>
2574
+ <div className="mx-auto flex min-h-20 max-w-7xl flex-wrap items-center justify-between gap-3 bg-white/90 px-4 py-3 shadow-xl shadow-stone-900/10 sm:px-6">
2575
+ <Header />
2576
+ <div className="ml-auto flex min-w-0 items-center gap-2">
2577
+ <label className="sr-only" htmlFor="ultramodern-language">
2578
+ {t('shell.language.switcher')}
2579
+ </label>
2580
+ <select
2581
+ className="h-10 rounded-full border border-stone-900/15 bg-white px-3 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5"
2582
+ id="ultramodern-language"
2583
+ onChange={event => {
2584
+ const nextLanguage = event.currentTarget.value;
2585
+ if (isSupportedLanguage(nextLanguage)) {
2586
+ window.location.assign(
2587
+ \`\${localizedPath(location.pathname, nextLanguage)}\${suffix}\`,
2588
+ );
2589
+ }
2590
+ }}
2591
+ value={language}
2592
+ >
2593
+ {supportedLanguages.map(code => (
2594
+ <option key={code} value={code}>
2595
+ {t(\`shell.language.\${code}\`)}
2596
+ </option>
2597
+ ))}
2598
+ </select>
2599
+ {showCart ? <MiniCart /> : null}
2600
+ </div>
3053
2601
  </div>
3054
- {CartPage ? <CartPage /> : null}
2602
+ {children}
3055
2603
  </main>
3056
2604
  );
3057
2605
  }
@@ -3162,7 +2710,6 @@ export default function BoundaryOverlay() {
3162
2710
 
3163
2711
  const mutationObserver = new MutationObserver(readBoxes);
3164
2712
  mutationObserver.observe(document.body, {
3165
- attributes: true,
3166
2713
  childList: true,
3167
2714
  subtree: true,
3168
2715
  });
@@ -3180,8 +2727,9 @@ export default function BoundaryOverlay() {
3180
2727
 
3181
2728
  return (
3182
2729
  <>
3183
- <label className="commerce-boundary-toggle">
2730
+ <label className="fixed bottom-5 left-5 z-[80] flex items-center gap-2 rounded-xl border border-stone-900/10 bg-white/95 px-4 py-3 text-sm font-semibold text-stone-950 shadow-2xl shadow-stone-900/15">
3184
2731
  <input
2732
+ className="size-4 accent-emerald-800"
3185
2733
  checked={enabled}
3186
2734
  onChange={event => setEnabled(event.currentTarget.checked)}
3187
2735
  type="checkbox"
@@ -3189,15 +2737,16 @@ export default function BoundaryOverlay() {
3189
2737
  <span>{toggleLabel}</span>
3190
2738
  </label>
3191
2739
  {enabled ? (
3192
- <div aria-hidden="true" className="boundary-overlay">
2740
+ <div aria-hidden="true" className="pointer-events-none fixed inset-0 z-[70]">
3193
2741
  {boxes.map(box => (
3194
2742
  <div
3195
- className="boundary-overlay__box"
2743
+ className="fixed rounded-lg border"
3196
2744
  data-label-placement={box.labelPlacement}
3197
2745
  key={box.id}
3198
2746
  style={
3199
2747
  {
3200
- '--boundary-color': box.color,
2748
+ borderColor: box.color,
2749
+ boxShadow: \`0 0 0 1px rgba(255,255,255,.72), 0 6px 20px color-mix(in srgb, \${box.color} 20%, transparent)\`,
3201
2750
  height: box.height,
3202
2751
  left: box.left,
3203
2752
  top: box.top,
@@ -3205,7 +2754,12 @@ export default function BoundaryOverlay() {
3205
2754
  } as CSSProperties
3206
2755
  }
3207
2756
  >
3208
- <span className="boundary-overlay__label">{box.label}</span>
2757
+ <span
2758
+ className={\`absolute right-1 top-1 whitespace-nowrap rounded-full px-2 py-1 text-[0.7rem] font-black leading-none text-stone-950 \${box.labelPlacement === 'above' ? 'bottom-[calc(100%+0.25rem)] top-auto' : ''}\`}
2759
+ style={{ backgroundColor: box.color }}
2760
+ >
2761
+ {box.label}
2762
+ </span>
3209
2763
  </div>
3210
2764
  ))}
3211
2765
  </div>
@@ -3234,55 +2788,70 @@ const loadRemoteComponent = async (specifier: string) => {
3234
2788
 
3235
2789
  const remoteFallback =
3236
2790
  ({ error }: { error: Error }) =>
3237
- <div data-remote-error={error.name}>Remote unavailable</div>;
2791
+ <div className="rounded-xl border border-red-900/20 bg-red-50 px-4 py-3 text-sm font-semibold text-red-900" data-remote-error={error.name}>Remote unavailable</div>;
2792
+
2793
+ const HeaderLoading = () => (
2794
+ <div className="flex min-w-0 flex-1 items-center gap-5" data-mf-boundary="explore">
2795
+ <div className="h-6 w-28 rounded-full bg-stone-200" />
2796
+ <div className="hidden h-5 w-44 rounded-full bg-stone-100 sm:block" />
2797
+ </div>
2798
+ );
2799
+
2800
+ const MiniCartLoading = () => (
2801
+ <div className="h-10 w-28 rounded-full bg-stone-100" data-mf-boundary="checkout" />
2802
+ );
2803
+
2804
+ const PanelLoading = () => (
2805
+ <section className="mx-auto mt-10 max-w-7xl rounded-2xl bg-white/75 p-6 shadow-xl shadow-stone-900/10">
2806
+ <div className="h-5 w-40 rounded-full bg-stone-200" />
2807
+ <div className="mt-5 grid gap-4 md:grid-cols-2">
2808
+ <div className="h-36 rounded-xl bg-stone-100" />
2809
+ <div className="h-36 rounded-xl bg-stone-100" />
2810
+ </div>
2811
+ </section>
2812
+ );
3238
2813
 
3239
2814
  export const Header = createLazyComponent({
3240
2815
  export: 'default',
3241
2816
  fallback: remoteFallback,
3242
2817
  instance: getInstance(),
3243
2818
  loader: () => loadRemoteComponent('explore/Header'),
3244
- loading: null,
3245
- noSSR: true,
2819
+ loading: <HeaderLoading />,
3246
2820
  });
3247
2821
  export const StorePicker = createLazyComponent({
3248
2822
  export: 'default',
3249
2823
  fallback: remoteFallback,
3250
2824
  instance: getInstance(),
3251
2825
  loader: () => loadRemoteComponent('explore/StorePicker'),
3252
- loading: null,
3253
- noSSR: true,
2826
+ loading: <PanelLoading />,
3254
2827
  });
3255
2828
  export const Recommendations = createLazyComponent({
3256
2829
  export: 'default',
3257
2830
  fallback: remoteFallback,
3258
2831
  instance: getInstance(),
3259
2832
  loader: () => loadRemoteComponent('explore/Recommendations'),
3260
- loading: null,
3261
- noSSR: true,
2833
+ loading: <PanelLoading />,
3262
2834
  });
3263
2835
  export const ProductPage = createLazyComponent({
3264
2836
  export: 'default',
3265
2837
  fallback: remoteFallback,
3266
2838
  instance: getInstance(),
3267
2839
  loader: () => loadRemoteComponent('decide/ProductPage'),
3268
- loading: null,
3269
- noSSR: true,
2840
+ loading: <PanelLoading />,
3270
2841
  });
3271
2842
  export const MiniCart = createLazyComponent({
3272
2843
  export: 'default',
3273
2844
  fallback: remoteFallback,
3274
2845
  instance: getInstance(),
3275
2846
  loader: () => loadRemoteComponent('checkout/MiniCart'),
3276
- loading: null,
3277
- noSSR: true,
2847
+ loading: <MiniCartLoading />,
3278
2848
  });
3279
2849
  export const CartPage = createLazyComponent({
3280
2850
  export: 'default',
3281
2851
  fallback: remoteFallback,
3282
2852
  instance: getInstance(),
3283
2853
  loader: () => loadRemoteComponent('checkout/CartPage'),
3284
- loading: null,
3285
- noSSR: true,
2854
+ loading: <PanelLoading />,
3286
2855
  });
3287
2856
  `;
3288
2857
  }
@@ -3328,12 +2897,13 @@ export default function ${toPascalCase(app.id)}Home() {
3328
2897
  const location = useLocation();
3329
2898
  const suffix = locationSuffix(location);
3330
2899
  ${effectBffState} return (
3331
- <main>
2900
+ <main className="min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8">
3332
2901
  <LocalizedHead />
3333
- <nav aria-label={t('${app.domain}.language.switcher')}>
2902
+ <nav aria-label={t('${app.domain}.language.switcher')} className="flex gap-3">
3334
2903
  {supportedLanguages.map(code => (
3335
2904
  <a
3336
2905
  aria-current={language === code ? 'page' : undefined}
2906
+ className="rounded-full border border-stone-900/15 bg-white px-4 py-2 text-sm font-bold text-stone-950 no-underline"
3337
2907
  href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
3338
2908
  key={code}
3339
2909
  >
@@ -3341,9 +2911,9 @@ ${effectBffState} return (
3341
2911
  </a>
3342
2912
  ))}
3343
2913
  </nav>
3344
- <h1>{t('${app.domain}.title')}</h1>
3345
- <p data-mf-role="${app.kind}">{t('${app.domain}.role')}</p>
3346
- <p data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
2914
+ <h1 className="mt-10 text-5xl font-black">{t('${app.domain}.title')}</h1>
2915
+ <p className="mt-3 text-lg text-stone-600" data-mf-role="${app.kind}">{t('${app.domain}.role')}</p>
2916
+ <p className="sr-only" data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
3347
2917
  {ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
3348
2918
  </p>
3349
2919
  ${effectBffMarkup} </main>
@@ -3371,9 +2941,9 @@ function createRemoteEntry(app) {
3371
2941
  `;
3372
2942
  return `export default function ${toPascalCase(app.domain ?? app.id)}Route() {
3373
2943
  return (
3374
- <section data-mf-remote="${app.id}" data-mf-expose="./Route">
3375
- <h2>${app.displayName}</h2>
3376
- <p>Route surface for ${app.domain ?? app.id}.</p>
2944
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10" data-mf-remote="${app.id}" data-mf-expose="./Route">
2945
+ <h2 className="text-2xl font-black">${app.displayName}</h2>
2946
+ <p className="mt-2 text-stone-600">Route surface for ${app.domain ?? app.id}.</p>
3377
2947
  </section>
3378
2948
  );
3379
2949
  }
@@ -3384,9 +2954,9 @@ function createRemoteWidget(app) {
3384
2954
  const body = 'vertical' === app.kind ? `Owns the ${app.domain} vertical route surface.` : 'Provides shared UI primitives for the workspace.';
3385
2955
  return `export default function ${componentName}() {
3386
2956
  return (
3387
- <section data-mf-remote="${app.id}">
3388
- <h2>${app.displayName}</h2>
3389
- <p>${body}</p>
2957
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10" data-mf-remote="${app.id}">
2958
+ <h2 className="text-2xl font-black">${app.displayName}</h2>
2959
+ <p className="mt-2 text-stone-600">${body}</p>
3390
2960
  </section>
3391
2961
  );
3392
2962
  }
@@ -3400,23 +2970,27 @@ export default function Header() {
3400
2970
  const t = i18nInstance['t'].bind(i18nInstance);
3401
2971
 
3402
2972
  return (
3403
- <header className="commerce-header" data-mf-boundary="explore">
3404
- <a className="commerce-logo" href={\`/\${language}\`}>Acre & Iron</a>
3405
- <nav aria-label={t('explore.header.navigation')} className="commerce-nav">
3406
- <a href={\`/\${language}/tractors\`}>{t('explore.header.machines')}</a>
3407
- <a href={\`/\${language}/stores\`}>{t('explore.header.stores')}</a>
2973
+ <header className="flex min-w-0 flex-1 flex-wrap items-center gap-x-8 gap-y-2" data-mf-boundary="explore">
2974
+ <a className="whitespace-nowrap text-xl font-black tracking-normal text-stone-950 no-underline" href={\`/\${language}\`}>Acre & Iron</a>
2975
+ <nav aria-label={t('explore.header.navigation')} className="flex items-center gap-5">
2976
+ <a className="text-sm font-extrabold text-stone-900 no-underline" href={\`/\${language}/tractors\`}>{t('explore.header.machines')}</a>
2977
+ <a className="text-sm font-extrabold text-stone-900 no-underline" href={\`/\${language}/stores\`}>{t('explore.header.stores')}</a>
3408
2978
  </nav>
3409
2979
  </header>
3410
2980
  );
3411
2981
  }
3412
2982
  `;
3413
2983
  if ('remote-explore' === app.id && './Recommendations' === expose) return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2984
+ import autonomyImage from '../assets/autonomy.svg';
2985
+ import fieldLoaderImage from '../assets/field-loader.svg';
2986
+ import orchardImage from '../assets/orchard.svg';
2987
+ import vineyardImage from '../assets/vineyard.svg';
3414
2988
 
3415
2989
  const tractors = [
3416
- { badge: 'explore.recommendations.bestRows', name: 'Orchard Tractor', slug: 'orchard-tractor' },
3417
- { badge: 'explore.recommendations.aiFirst', name: 'Autonomy Retrofit Kit', slug: 'autonomy-retrofit-kit' },
3418
- { badge: 'explore.recommendations.loaderReady', name: 'Field Loader 112', slug: 'field-loader-112' },
3419
- { badge: 'explore.recommendations.vineyard', name: 'Vineyard Narrow 80', slug: 'vineyard-narrow-80' },
2990
+ { badge: 'explore.recommendations.bestRows', image: orchardImage, name: 'Orchard Tractor', slug: 'orchard-tractor' },
2991
+ { badge: 'explore.recommendations.aiFirst', image: autonomyImage, name: 'Autonomy Retrofit Kit', slug: 'autonomy-retrofit-kit' },
2992
+ { badge: 'explore.recommendations.loaderReady', image: fieldLoaderImage, name: 'Field Loader 112', slug: 'field-loader-112' },
2993
+ { badge: 'explore.recommendations.vineyard', image: vineyardImage, name: 'Vineyard Narrow 80', slug: 'vineyard-narrow-80' },
3420
2994
  ] as const;
3421
2995
 
3422
2996
  export default function Recommendations() {
@@ -3424,13 +2998,14 @@ export default function Recommendations() {
3424
2998
  const t = i18nInstance['t'].bind(i18nInstance);
3425
2999
 
3426
3000
  return (
3427
- <section className="commerce-page" data-mf-boundary="explore">
3428
- <h2 className="commerce-section-title">{t('explore.recommendations.title')}</h2>
3429
- <div className="commerce-grid">
3001
+ <section className="mx-auto mt-12 max-w-7xl" data-mf-boundary="explore">
3002
+ <h2 className="text-3xl font-black tracking-normal text-stone-950">{t('explore.recommendations.title')}</h2>
3003
+ <div className="mt-5 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
3430
3004
  {tractors.map(tractor => (
3431
- <a className="commerce-card" href={\`/\${language}/tractors/\${tractor.slug}\`} key={tractor.slug}>
3432
- <span>{t(tractor.badge)}</span>
3433
- <strong>{tractor.name}</strong>
3005
+ <a className="block rounded-2xl bg-white/90 p-4 text-stone-950 no-underline shadow-xl shadow-stone-900/10 transition hover:-translate-y-0.5 hover:shadow-2xl" href={\`/\${language}/tractors/\${tractor.slug}\`} key={tractor.slug}>
3006
+ <img alt="" className="aspect-video w-full rounded-xl bg-stone-200 object-cover" src={tractor.image} />
3007
+ <span className="mt-4 block text-xs font-black uppercase tracking-[0.16em] text-amber-700">{t(tractor.badge)}</span>
3008
+ <strong className="mt-2 block text-xl font-black leading-tight">{tractor.name}</strong>
3434
3009
  </a>
3435
3010
  ))}
3436
3011
  </div>
@@ -3439,22 +3014,26 @@ export default function Recommendations() {
3439
3014
  }
3440
3015
  `;
3441
3016
  if ('remote-explore' === app.id && './StorePicker' === expose) return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
3017
+ import fieldLoaderImage from '../assets/field-loader.svg';
3018
+ import vineyardImage from '../assets/vineyard.svg';
3442
3019
 
3443
3020
  export default function StorePicker() {
3444
3021
  const { i18nInstance } = useModernI18n();
3445
3022
  const t = i18nInstance['t'].bind(i18nInstance);
3446
3023
 
3447
3024
  return (
3448
- <section className="commerce-page" data-mf-boundary="explore">
3449
- <h2 className="commerce-section-title">{t('explore.stores.title')}</h2>
3450
- <div className="commerce-grid">
3451
- <article className="commerce-card">
3452
- <span>{t('explore.stores.northRegion')}</span>
3453
- <strong>Bohemia Field Supply</strong>
3025
+ <section className="mx-auto mt-12 max-w-7xl" data-mf-boundary="explore">
3026
+ <h2 className="text-3xl font-black tracking-normal text-stone-950">{t('explore.stores.title')}</h2>
3027
+ <div className="mt-5 grid gap-4 md:grid-cols-2">
3028
+ <article className="rounded-2xl bg-white/90 p-4 shadow-xl shadow-stone-900/10">
3029
+ <img alt="" className="aspect-video w-full rounded-xl bg-stone-200 object-cover" src={fieldLoaderImage} />
3030
+ <span className="mt-4 block text-xs font-black uppercase tracking-[0.16em] text-emerald-800">{t('explore.stores.northRegion')}</span>
3031
+ <strong className="mt-2 block text-2xl font-black">Bohemia Field Supply</strong>
3454
3032
  </article>
3455
- <article className="commerce-card">
3456
- <span>{t('explore.stores.southRegion')}</span>
3457
- <strong>Moravia Iron Works</strong>
3033
+ <article className="rounded-2xl bg-white/90 p-4 shadow-xl shadow-stone-900/10">
3034
+ <img alt="" className="aspect-video w-full rounded-xl bg-stone-200 object-cover" src={vineyardImage} />
3035
+ <span className="mt-4 block text-xs font-black uppercase tracking-[0.16em] text-emerald-800">{t('explore.stores.southRegion')}</span>
3036
+ <strong className="mt-2 block text-2xl font-black">Moravia Iron Works</strong>
3458
3037
  </article>
3459
3038
  </div>
3460
3039
  </section>
@@ -3462,12 +3041,13 @@ export default function StorePicker() {
3462
3041
  }
3463
3042
  `;
3464
3043
  if ('remote-explore' === app.id && './Footer' === expose) return `export default function Footer() {
3465
- return <footer className="commerce-footer" data-mf-boundary="explore">Acre & Iron</footer>;
3044
+ return <footer className="mx-auto mt-12 max-w-7xl text-sm font-bold text-stone-600" data-mf-boundary="explore">Acre & Iron</footer>;
3466
3045
  }
3467
3046
  `;
3468
3047
  if ('./Widget' === expose) return createRemoteWidget(app);
3469
3048
  const componentName = `${toPascalCase(app.domain ?? app.id)}${toPascalCase(expose.replace(/^\.\//u, ''))}`;
3470
3049
  if ('remote-decide' === app.id && './ProductPage' === expose) return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
3050
+ import fieldLoaderImage from '../assets/field-loader.svg';
3471
3051
  import { AddToCart, Recommendations } from './remote-components';
3472
3052
 
3473
3053
  export default function ${componentName}() {
@@ -3476,16 +3056,16 @@ export default function ${componentName}() {
3476
3056
 
3477
3057
  return (
3478
3058
  <>
3479
- <section className="commerce-page commerce-product" data-mf-boundary="decide" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3480
- <div className="commerce-product-media" aria-hidden="true" />
3059
+ <section className="mx-auto mt-10 grid max-w-7xl items-center gap-8 md:grid-cols-[1fr_0.95fr] lg:gap-14" data-mf-boundary="decide" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3060
+ <img alt="" className="aspect-[1/0.9] w-full rounded-3xl border-[18px] border-amber-200 bg-stone-200 object-cover shadow-2xl shadow-stone-900/20" src={fieldLoaderImage} />
3481
3061
  <div>
3482
- <p className="commerce-eyebrow">{t('decide.product.eyebrow')}</p>
3483
- <h1 className="commerce-title">Field Loader 112</h1>
3484
- <p className="commerce-lede">{t('decide.product.lede')}</p>
3485
- <div className="commerce-facts">
3486
- <article className="commerce-fact"><span>{t('decide.product.price')}</span><strong>EUR 42,500</strong></article>
3487
- <article className="commerce-fact"><span>{t('decide.product.power')}</span><strong>112 hp</strong></article>
3488
- <article className="commerce-fact"><span>{t('decide.product.availability')}</span><strong>{t('decide.product.inStock')}</strong></article>
3062
+ <p className="text-xs font-black uppercase tracking-[0.18em] text-emerald-800">{t('decide.product.eyebrow')}</p>
3063
+ <h1 className="mt-3 text-5xl font-black leading-none tracking-normal text-stone-950 md:text-7xl">Field Loader 112</h1>
3064
+ <p className="mt-5 max-w-2xl text-lg leading-8 text-stone-600">{t('decide.product.lede')}</p>
3065
+ <div className="mt-8 grid gap-4 sm:grid-cols-3">
3066
+ <article className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10"><span className="block text-sm font-bold text-stone-500">{t('decide.product.price')}</span><strong className="mt-2 block text-lg font-black">EUR 42,500</strong></article>
3067
+ <article className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10"><span className="block text-sm font-bold text-stone-500">{t('decide.product.power')}</span><strong className="mt-2 block text-lg font-black">112 hp</strong></article>
3068
+ <article className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10"><span className="block text-sm font-bold text-stone-500">{t('decide.product.availability')}</span><strong className="mt-2 block text-lg font-black">{t('decide.product.inStock')}</strong></article>
3489
3069
  </div>
3490
3070
  <AddToCart />
3491
3071
  </div>
@@ -3504,11 +3084,11 @@ export default function ${componentName}() {
3504
3084
  const cart = useCartLines();
3505
3085
 
3506
3086
  return (
3507
- <div className="commerce-checkout" data-mf-boundary="checkout">
3508
- <button className="commerce-button" onClick={cart.addFieldLoader} type="button">
3087
+ <div className="mt-8 flex flex-wrap gap-3" data-mf-boundary="checkout">
3088
+ <button className="inline-flex min-h-11 items-center justify-center rounded-full bg-emerald-800 px-5 font-bold text-white shadow-lg shadow-stone-900/10" onClick={cart.addFieldLoader} type="button">
3509
3089
  {t('checkout.actions.addToCart')}
3510
3090
  </button>
3511
- <a className="commerce-link-button" href={\`/\${language}/cart\`}>
3091
+ <a className="inline-flex min-h-11 items-center justify-center rounded-full border border-stone-900/15 bg-white/90 px-5 font-bold text-stone-950 shadow-lg shadow-stone-900/10" href={\`/\${language}/cart\`}>
3512
3092
  {t('checkout.actions.viewCart')}
3513
3093
  </a>
3514
3094
  </div>
@@ -3525,7 +3105,7 @@ export default function ${componentName}() {
3525
3105
  const count = cart.lines.reduce((sum, line) => sum + line.quantity, 0);
3526
3106
 
3527
3107
  return (
3528
- <a className="commerce-cart-button" data-mf-boundary="checkout" href={\`/\${language}/cart\`}>
3108
+ <a className="inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 no-underline shadow-lg shadow-stone-900/5" data-mf-boundary="checkout" href={\`/\${language}/cart\`}>
3529
3109
  {t('checkout.cart.title')} ({count})
3530
3110
  </a>
3531
3111
  );
@@ -3540,24 +3120,24 @@ export default function ${componentName}() {
3540
3120
  const cart = useCartLines();
3541
3121
 
3542
3122
  return (
3543
- <section className="commerce-page" data-mf-boundary="checkout" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3544
- <h1 className="commerce-title">{t('checkout.cart.title')}</h1>
3545
- <div className="commerce-cart-panel">
3123
+ <section className="mx-auto mt-10 max-w-7xl" data-mf-boundary="checkout" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3124
+ <h1 className="text-5xl font-black leading-none tracking-normal text-stone-950 md:text-7xl">{t('checkout.cart.title')}</h1>
3125
+ <div className="mt-8 rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10">
3546
3126
  {cart.lines.length === 0 ? (
3547
3127
  <p>{t('checkout.cart.empty')}</p>
3548
3128
  ) : (
3549
3129
  <>
3550
3130
  {cart.lines.map(line => (
3551
- <article className="commerce-cart-line" key={line.id}>
3131
+ <article className="grid gap-4 border-t border-stone-900/10 py-4 first:border-t-0 sm:grid-cols-[1fr_auto] sm:items-center" key={line.id}>
3552
3132
  <div>
3553
- <strong>{line.name}</strong>
3554
- <p>EUR {line.price.toLocaleString('en-US')}</p>
3133
+ <strong className="text-lg font-black">{line.name}</strong>
3134
+ <p className="text-stone-600">EUR {line.price.toLocaleString('en-US')}</p>
3555
3135
  </div>
3556
- <div className="commerce-quantity">
3557
- <button className="commerce-quantity-button" onClick={() => cart.decrement(line.id)} type="button">-</button>
3558
- <span>{line.quantity}</span>
3559
- <button className="commerce-quantity-button" onClick={() => cart.increment(line.id)} type="button">+</button>
3560
- <button className="commerce-link-button" onClick={() => cart.remove(line.id)} type="button">
3136
+ <div className="flex flex-wrap items-center gap-2">
3137
+ <button className="inline-flex size-9 items-center justify-center rounded-full border border-stone-900/15 bg-white font-black" onClick={() => cart.decrement(line.id)} type="button">-</button>
3138
+ <span className="min-w-6 text-center font-black">{line.quantity}</span>
3139
+ <button className="inline-flex size-9 items-center justify-center rounded-full border border-stone-900/15 bg-white font-black" onClick={() => cart.increment(line.id)} type="button">+</button>
3140
+ <button className="inline-flex min-h-10 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 font-bold text-stone-950" onClick={() => cart.remove(line.id)} type="button">
3561
3141
  {t('checkout.actions.remove')}
3562
3142
  </button>
3563
3143
  </div>
@@ -3573,9 +3153,9 @@ export default function ${componentName}() {
3573
3153
  `;
3574
3154
  return `export default function ${componentName}() {
3575
3155
  return (
3576
- <section data-mf-remote="${app.id}" data-mf-expose="${expose}">
3577
- <h2>${app.displayName} ${expose.replace(/^\.\//u, '')}</h2>
3578
- <p>Module Federation surface owned by ${app.ownership.team}.</p>
3156
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3157
+ <h2 className="text-2xl font-black">${app.displayName} ${expose.replace(/^\.\//u, '')}</h2>
3158
+ <p className="mt-2 text-stone-600">Module Federation surface owned by ${app.ownership.team}.</p>
3579
3159
  </section>
3580
3160
  );
3581
3161
  }
@@ -3600,23 +3180,40 @@ const loadRemoteComponent = async (specifier: string) => {
3600
3180
 
3601
3181
  const remoteFallback =
3602
3182
  ({ error }: { error: Error }) =>
3603
- <div data-remote-error={error.name}>Remote unavailable</div>;
3183
+ <div className="rounded-xl border border-red-900/20 bg-red-50 px-4 py-3 text-sm font-semibold text-red-900" data-remote-error={error.name}>Remote unavailable</div>;
3184
+
3185
+ const AddToCartLoading = () => (
3186
+ <div className="mt-8 flex gap-3" data-mf-boundary="checkout">
3187
+ <div className="h-11 w-32 rounded-full bg-stone-200" />
3188
+ <div className="h-11 w-28 rounded-full bg-white/80" />
3189
+ </div>
3190
+ );
3191
+
3192
+ const RecommendationsLoading = () => (
3193
+ <section className="mx-auto mt-12 max-w-7xl" data-mf-boundary="explore">
3194
+ <div className="h-8 w-64 rounded-full bg-stone-200" />
3195
+ <div className="mt-5 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
3196
+ <div className="h-48 rounded-2xl bg-white/80" />
3197
+ <div className="h-48 rounded-2xl bg-white/80" />
3198
+ <div className="h-48 rounded-2xl bg-white/80" />
3199
+ <div className="h-48 rounded-2xl bg-white/80" />
3200
+ </div>
3201
+ </section>
3202
+ );
3604
3203
 
3605
3204
  export const AddToCart = createLazyComponent({
3606
3205
  export: 'default',
3607
3206
  fallback: remoteFallback,
3608
3207
  instance: getInstance(),
3609
3208
  loader: () => loadRemoteComponent('checkout/AddToCart'),
3610
- loading: null,
3611
- noSSR: true,
3209
+ loading: <AddToCartLoading />,
3612
3210
  });
3613
3211
  export const Recommendations = createLazyComponent({
3614
3212
  export: 'default',
3615
3213
  fallback: remoteFallback,
3616
3214
  instance: getInstance(),
3617
3215
  loader: () => loadRemoteComponent('explore/Recommendations'),
3618
- loading: null,
3619
- noSSR: true,
3216
+ loading: <RecommendationsLoading />,
3620
3217
  });
3621
3218
  `;
3622
3219
  }
@@ -3750,17 +3347,9 @@ function createAppLocaleMessages(app, language) {
3750
3347
  };
3751
3348
  }
3752
3349
  function createDesignButton() {
3753
- return `import { designTokens } from '../tokens';
3754
-
3755
- export default function Button({ label }: { label: string }) {
3350
+ return `export default function Button({ label }: { label: string }) {
3756
3351
  return (
3757
- <button
3758
- type="button"
3759
- style={{
3760
- borderRadius: designTokens.radius.control,
3761
- color: designTokens.color.foreground,
3762
- }}
3763
- >
3352
+ <button className="rounded-full text-um-foreground" type="button">
3764
3353
  {label}
3765
3354
  </button>
3766
3355
  );
@@ -3876,14 +3465,12 @@ export function useCartLines() {
3876
3465
  `;
3877
3466
  }
3878
3467
  function createSharedDesignTokensCss() {
3879
- return `@layer ultramodern-shared-tokens {
3880
- :root {
3881
- --um-color-accent: #2f8f68;
3882
- --um-color-canvas: #f1eadc;
3883
- --um-color-foreground: #133225;
3884
- --um-color-link: #166b4b;
3885
- --um-color-surface: #f6fbf7;
3886
- }
3468
+ return `@theme {
3469
+ --color-um-accent: #2f8f68;
3470
+ --color-um-canvas: #f1eadc;
3471
+ --color-um-foreground: #133225;
3472
+ --color-um-link: #166b4b;
3473
+ --color-um-surface: #f6fbf7;
3887
3474
  }
3888
3475
  `;
3889
3476
  }
@@ -5789,10 +5376,12 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
5789
5376
  }
5790
5377
  writeFile(targetDir, `${app.directory}/module-federation.config.ts`, 'shell' === app.kind ? createShellModuleFederationConfig() : createRemoteModuleFederationConfig(app));
5791
5378
  writeFile(targetDir, `${app.directory}/src/routes/layout.tsx`, createLayout(app.id));
5379
+ for (const [relativePath, content] of Object.entries(commerceAssetsForApp(app)))writeFile(targetDir, `${app.directory}/${relativePath}`, content);
5792
5380
  writeFile(targetDir, `${app.directory}/src/routes/[lang]/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
5793
5381
  for (const route of createRouteOwnedI18nPaths(app))if ('/' !== route.canonicalPath && 'shell' !== app.kind) writeFile(targetDir, createRoutePageFilePath(app, route.canonicalPath), createRouteAliasPage(route.canonicalPath));
5794
5382
  if ('shell' === app.kind) {
5795
5383
  writeFile(targetDir, `${app.directory}/src/routes/remote-components.tsx`, createShellRemoteComponents());
5384
+ writeFile(targetDir, `${app.directory}/src/routes/shell-frame.tsx`, createShellFrameComponent());
5796
5385
  writeFile(targetDir, `${app.directory}/src/routes/boundary-overlay.tsx`, createShellBoundaryOverlay());
5797
5386
  writeFile(targetDir, `${app.directory}/src/effect/recommendations-client.ts`, createShellEffectClient(scope));
5798
5387
  writeFile(targetDir, `${app.directory}/src/routes/[lang]/tractors/page.tsx`, createShellTractorsPage());
@@ -5825,7 +5414,13 @@ function writeEffectService(targetDir, scope, packageSource, enableTailwind, ser
5825
5414
  writeFile(targetDir, `${service.directory}/src/ultramodern-build.ts`, createUltramodernBuildModule(scope, service));
5826
5415
  writeFile(targetDir, `${service.directory}/src/routes/layout.tsx`, createLayout(service.id));
5827
5416
  writeFile(targetDir, `${service.directory}/src/routes/page.tsx`, `export default function ${toPascalCase(service.id)}Home() {
5828
- return <main>${service.id} Effect service</main>;
5417
+ return (
5418
+ <main className="min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8">
5419
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10">
5420
+ <h1 className="text-3xl font-black">${service.id} Effect service</h1>
5421
+ </section>
5422
+ </main>
5423
+ );
5829
5424
  }
5830
5425
  `);
5831
5426
  writeFile(targetDir, `${service.directory}/src/routes/index.css`, createServiceStyles(enableTailwind, scope, service));