@bleedingdev/modern-js-create 3.2.0-ultramodern.52 → 3.2.0-ultramodern.54

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 +521 -919
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -1095,6 +1095,7 @@ function appDependencies(scope, packageSource, app) {
1095
1095
  dependencies['@modern-js/plugin-bff'] = modernPackageSpecifier('@modern-js/plugin-bff', packageSource);
1096
1096
  for (const remote of verticalEffectApps())dependencies[ultramodern_workspace_packageName(scope, remote.packageSuffix)] = WORKSPACE_PACKAGE_VERSION;
1097
1097
  }
1098
+ for (const remote of resolveRemoteRefs(app))dependencies[ultramodern_workspace_packageName(scope, remote.packageSuffix)] = WORKSPACE_PACKAGE_VERSION;
1098
1099
  if (appHasEffectApi(app)) dependencies['@modern-js/plugin-bff'] = modernPackageSpecifier('@modern-js/plugin-bff', packageSource);
1099
1100
  return dependencies;
1100
1101
  }
@@ -1305,6 +1306,10 @@ function createPackageTsConfig(packageDir, includeApi = false) {
1305
1306
  };
1306
1307
  }
1307
1308
  function createAppPackage(scope, app, packageSource, enableTailwind) {
1309
+ const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
1310
+ expose,
1311
+ source
1312
+ ]));
1308
1313
  const packageJson = {
1309
1314
  private: true,
1310
1315
  name: ultramodern_workspace_packageName(scope, app.packageSuffix),
@@ -1332,13 +1337,14 @@ function createAppPackage(scope, app, packageSource, enableTailwind) {
1332
1337
  dependencies: appDependencies(scope, packageSource, app),
1333
1338
  devDependencies: appDevDependencies(packageSource, enableTailwind)
1334
1339
  };
1335
- if (appHasEffectApi(app)) packageJson.exports = {
1340
+ if (appHasEffectApi(app)) Object.assign(packageExports, {
1336
1341
  './effect/client': `./src/effect/${app.effectApi.stem}-client.ts`,
1337
1342
  './shared/effect/api': './shared/effect/api.ts'
1338
- };
1339
- else if ('shell' === app.kind) packageJson.exports = {
1343
+ });
1344
+ else if ('shell' === app.kind) Object.assign(packageExports, {
1340
1345
  './effect/clients': './src/effect/recommendations-client.ts'
1341
- };
1346
+ });
1347
+ if (Object.keys(packageExports).length > 0) packageJson.exports = packageExports;
1342
1348
  return packageJson;
1343
1349
  }
1344
1350
  function createServicePackage(scope, packageSource, enableTailwind, service = effectService) {
@@ -1436,6 +1442,8 @@ import { ultramodernLocalisedUrls } from './src/routes/ultramodern-route-metadat
1436
1442
  type ZephyrRspackConfig = Parameters<ReturnType<typeof withZephyrRspack>>[0];
1437
1443
 
1438
1444
  const zephyrEnabled = process.env['ULTRAMODERN_ZEPHYR'] !== 'false';
1445
+ const cloudflareDeployEnabled =
1446
+ process.env['MODERNJS_DEPLOY'] === 'cloudflare';
1439
1447
 
1440
1448
  const zephyrRspackPlugin = () => ({
1441
1449
  name: 'ultramodern-zephyr-rspack-plugin',
@@ -1526,13 +1534,17 @@ ${bffPluginEntry} moduleFederationPlugin(),
1526
1534
  ]);
1527
1535
  },
1528
1536
  },
1529
- deploy: {
1530
- target: 'cloudflare',
1531
- worker: {
1532
- name: cloudflareWorkerName,
1533
- ssr: true,
1534
- },
1535
- },
1537
+ ...(cloudflareDeployEnabled
1538
+ ? {
1539
+ deploy: {
1540
+ target: 'cloudflare',
1541
+ worker: {
1542
+ name: cloudflareWorkerName,
1543
+ ssr: true,
1544
+ },
1545
+ },
1546
+ }
1547
+ : {}),
1536
1548
  server: {
1537
1549
  port,
1538
1550
  publicDir: './locales',
@@ -1983,6 +1995,10 @@ function createAppEnvDts(app, remotes = remoteApps) {
1983
1995
  return `/// <reference types='@modern-js/app-tools/types' />
1984
1996
 
1985
1997
  declare const ULTRAMODERN_SITE_URL: string;
1998
+ declare module '*.svg' {
1999
+ const url: string;
2000
+ export default url;
2001
+ }
1986
2002
  ${remoteModuleDeclarations ? `\n${remoteModuleDeclarations}` : ''}`;
1987
2003
  }
1988
2004
  function createServiceModernConfigFor(service = effectService) {
@@ -2066,522 +2082,13 @@ function createCssTokenImport(scope) {
2066
2082
  return `@import '${ultramodern_workspace_packageName(scope, 'shared-design-tokens')}/tokens.css';\n`;
2067
2083
  }
2068
2084
  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;
2088
- }
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
- }
2085
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}`;
2222
2086
  }
2087
+ function createRemoteStyles(enableTailwind, scope, _app) {
2088
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}`;
2223
2089
  }
2224
-
2225
- @layer ultramodern-shell-overlay {
2226
- .boundary-overlay {
2227
- inset: 0;
2228
- pointer-events: none;
2229
- position: fixed;
2230
- z-index: 70;
2231
- }
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
- `;
2090
+ function createServiceStyles(enableTailwind, scope, _service) {
2091
+ return `${enableTailwind ? "@import 'tailwindcss';\n" : ''}${createCssTokenImport(scope)}`;
2585
2092
  }
2586
2093
  function createAppStyles(enableTailwind, scope, app) {
2587
2094
  return 'shell' === app.kind ? createShellStyles(enableTailwind, scope) : createRemoteStyles(enableTailwind, scope, app);
@@ -2602,6 +2109,86 @@ export default {
2602
2109
  } satisfies Config;
2603
2110
  `;
2604
2111
  }
2112
+ function createCommerceAssetSvg(title, palette) {
2113
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="900" viewBox="0 0 1440 900" role="img" aria-label="${title}">
2114
+ <defs>
2115
+ <linearGradient id="sky" x1="0" x2="0" y1="0" y2="1">
2116
+ <stop offset="0" stop-color="${palette.sky}"/>
2117
+ <stop offset="1" stop-color="#fff8dc"/>
2118
+ </linearGradient>
2119
+ <linearGradient id="field" x1="0" x2="1" y1="0" y2="1">
2120
+ <stop offset="0" stop-color="${palette.ground}"/>
2121
+ <stop offset="1" stop-color="${palette.accent}"/>
2122
+ </linearGradient>
2123
+ </defs>
2124
+ <rect width="1440" height="900" fill="url(#sky)"/>
2125
+ <path d="M0 566c172-78 330-102 474-72 125 26 219 91 340 106 170 21 339-74 626-43v343H0z" fill="url(#field)"/>
2126
+ <path d="M0 686c205-70 451-66 738 12 287 77 521 66 702-33v235H0z" fill="#4f7f38" opacity=".55"/>
2127
+ <g fill="none" stroke="#fff6b7" stroke-linecap="round" stroke-width="10" opacity=".55">
2128
+ <path d="M108 820c205-138 382-202 530-192"/>
2129
+ <path d="M322 862c176-134 338-198 486-193"/>
2130
+ <path d="M583 886c119-121 260-190 422-207"/>
2131
+ <path d="M868 878c95-94 207-153 336-176"/>
2132
+ </g>
2133
+ <g transform="translate(430 430)">
2134
+ <circle cx="170" cy="210" r="92" fill="#161616"/>
2135
+ <circle cx="170" cy="210" r="54" fill="#d7c46d"/>
2136
+ <circle cx="514" cy="214" r="108" fill="#161616"/>
2137
+ <circle cx="514" cy="214" r="63" fill="#d7c46d"/>
2138
+ <path d="M194 142h194l72-100h114c49 0 89 39 89 88v57H625l-51-90H452l-78 114H209z" fill="${palette.tractor}"/>
2139
+ <path d="M283 67h134l-54 73H249z" fill="#c9ecff" opacity=".72"/>
2140
+ <path d="M120 184h430v54H120z" fill="${palette.tractor}"/>
2141
+ <path d="M578 52l60-35M618 37l34 72" stroke="#171717" stroke-linecap="round" stroke-width="14"/>
2142
+ <path d="M90 236h578" stroke="#171717" stroke-linecap="round" stroke-width="18"/>
2143
+ </g>
2144
+ </svg>
2145
+ `;
2146
+ }
2147
+ function commerceAssetsForApp(app) {
2148
+ if ('shell' === app.kind) return {
2149
+ 'src/assets/hero-field.svg': createCommerceAssetSvg('Tractor crossing cultivated fields', {
2150
+ accent: '#d6b85d',
2151
+ ground: '#84ad58',
2152
+ sky: '#9fd6e8',
2153
+ tractor: '#005f73'
2154
+ })
2155
+ };
2156
+ if ('remote-explore' === app.id) return {
2157
+ 'src/assets/autonomy.svg': createCommerceAssetSvg('Autonomous tractor concept', {
2158
+ accent: '#c26a2e',
2159
+ ground: '#668f55',
2160
+ sky: '#d5e7de',
2161
+ tractor: '#f2a51a'
2162
+ }),
2163
+ 'src/assets/field-loader.svg': createCommerceAssetSvg('Field Loader 112 tractor', {
2164
+ accent: '#d6b85d',
2165
+ ground: '#84ad58',
2166
+ sky: '#9fd6e8',
2167
+ tractor: '#00624b'
2168
+ }),
2169
+ 'src/assets/orchard.svg': createCommerceAssetSvg('Orchard tractor between tight rows', {
2170
+ accent: '#b45b2d',
2171
+ ground: '#6f9b4a',
2172
+ sky: '#c9ebff',
2173
+ tractor: '#1d5d9b'
2174
+ }),
2175
+ 'src/assets/vineyard.svg': createCommerceAssetSvg('Vineyard narrow tractor', {
2176
+ accent: '#b88d58',
2177
+ ground: '#5e8a45',
2178
+ sky: '#f1dcb9',
2179
+ tractor: '#914d76'
2180
+ })
2181
+ };
2182
+ if ('remote-decide' === app.id) return {
2183
+ 'src/assets/field-loader.svg': createCommerceAssetSvg('Field Loader 112 tractor detail', {
2184
+ accent: '#d6b85d',
2185
+ ground: '#84ad58',
2186
+ sky: '#9fd6e8',
2187
+ tractor: '#00624b'
2188
+ })
2189
+ };
2190
+ return {};
2191
+ }
2605
2192
  function createLocalizedHeadComponent() {
2606
2193
  return `const fallbackLanguage = 'en';
2607
2194
  const supportedLanguages = ['en', 'cs'] as const;
@@ -2756,302 +2343,269 @@ function createShellPage() {
2756
2343
  return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2757
2344
  import { Helmet } from '@modern-js/runtime/head';
2758
2345
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2759
- import { useEffect, useState, type ComponentType } from 'react';
2760
- import BoundaryOverlay from '../boundary-overlay';
2346
+ import heroField from '../../assets/hero-field.svg';
2347
+ import ShellFrame from '../shell-frame';
2348
+ import { StorePicker } from '../remote-components';
2761
2349
  import { ultramodernLocalisedUrls } from '../ultramodern-route-metadata';
2762
2350
  import { ultramodernUiMarker } from '../../ultramodern-build';
2763
2351
 
2764
- const languageCodes = ['en', 'cs'] as const;
2765
-
2766
2352
  ${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
2353
  export default function ShellHome() {
2793
2354
  const { i18nInstance, language } = useModernI18n();
2794
2355
  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
2356
 
2802
2357
  return (
2803
- <main className="commerce-shell">
2358
+ <ShellFrame>
2804
2359
  <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\`}>
2360
+ <section className="mx-auto grid max-w-7xl items-center gap-8 py-8 md:grid-cols-[0.9fr_1.1fr] lg:gap-14">
2361
+ <div className="min-w-0">
2362
+ <p className="text-xs font-black uppercase tracking-[0.18em] text-emerald-800">{t('shell.hero.eyebrow')}</p>
2363
+ <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>
2364
+ <p className="mt-5 max-w-2xl text-lg leading-8 text-stone-600">{t('shell.hero.lede')}</p>
2365
+ <div className="mt-7 flex flex-wrap gap-3">
2366
+ <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
2367
  {t('shell.hero.primary')}
2829
- </a>
2830
- <a className="commerce-link-button" href={\`/\${language}/tractors\`}>
2368
+ </a>
2369
+ <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
2370
  {t('shell.hero.secondary')}
2832
- </a>
2371
+ </a>
2372
+ </div>
2833
2373
  </div>
2374
+ <img alt="" className="aspect-[16/10] w-full rounded-3xl bg-stone-200 object-cover shadow-2xl shadow-stone-900/20" src={heroField} />
2834
2375
  </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">
2376
+ <StorePicker />
2377
+ <p className="sr-only" data-testid="ultramodern-preset">presetUltramodern workspace</p>
2378
+ <p className="sr-only" data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
2838
2379
  {ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
2839
2380
  </p>
2840
- </main>
2381
+ </ShellFrame>
2841
2382
  );
2842
2383
  }
2843
2384
  `;
2844
2385
  }
2845
2386
  function createShellTractorsPage() {
2846
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2847
- import { Helmet } from '@modern-js/runtime/head';
2387
+ return `import { Helmet } from '@modern-js/runtime/head';
2848
2388
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2849
- import { useEffect, useState, type ComponentType } from 'react';
2850
- import BoundaryOverlay from '../../boundary-overlay';
2389
+ import ShellFrame from '../../shell-frame';
2390
+ import { Recommendations } from '../../remote-components';
2851
2391
  import { ultramodernLocalisedUrls } from '../../ultramodern-route-metadata';
2852
2392
 
2853
- const languageCodes = ['en', 'cs'] as const;
2854
-
2855
2393
  ${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
2394
  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
2395
  return (
2892
- <main className="commerce-shell">
2396
+ <ShellFrame>
2893
2397
  <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>
2398
+ <Recommendations />
2399
+ </ShellFrame>
2913
2400
  );
2914
2401
  }
2915
2402
  `;
2916
2403
  }
2917
2404
  function createShellProductPage() {
2918
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2919
- import { Helmet } from '@modern-js/runtime/head';
2405
+ return `import { Helmet } from '@modern-js/runtime/head';
2920
2406
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2921
- import { useEffect, useState, type ComponentType } from 'react';
2922
- import BoundaryOverlay from '../../../boundary-overlay';
2407
+ import ShellFrame from '../../../shell-frame';
2408
+ import { ProductPage } from '../../../remote-components';
2923
2409
  import { ultramodernLocalisedUrls } from '../../../ultramodern-route-metadata';
2924
2410
 
2925
- const languageCodes = ['en', 'cs'] as const;
2926
-
2927
2411
  ${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
2412
  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
2413
  return (
2966
- <main className="commerce-shell">
2414
+ <ShellFrame>
2967
2415
  <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>
2416
+ <ProductPage />
2417
+ </ShellFrame>
2987
2418
  );
2988
2419
  }
2989
2420
  `;
2990
2421
  }
2991
2422
  function createShellCartPage() {
2992
- return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2993
- import { Helmet } from '@modern-js/runtime/head';
2423
+ return `import { Helmet } from '@modern-js/runtime/head';
2994
2424
  import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2995
- import { useEffect, useState, type ComponentType } from 'react';
2996
- import BoundaryOverlay from '../../boundary-overlay';
2425
+ import ShellFrame from '../../shell-frame';
2426
+ import { CartPage } from '../../remote-components';
2997
2427
  import { ultramodernLocalisedUrls } from '../../ultramodern-route-metadata';
2998
2428
 
2999
- const languageCodes = ['en', 'cs'] as const;
3000
-
3001
2429
  ${createLocalizedHeadComponent()}
3002
- type CartRouteRemotes = {
3003
- CartPage: ComponentType;
3004
- Header: ComponentType;
2430
+ export default function ShellCartPage() {
2431
+ return (
2432
+ <ShellFrame showCart={false}>
2433
+ <LocalizedHead />
2434
+ <CartPage />
2435
+ </ShellFrame>
2436
+ );
2437
+ }
2438
+ `;
2439
+ }
2440
+ function createShellFrameComponent() {
2441
+ return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2442
+ import { useLocation } from '@modern-js/plugin-tanstack/runtime';
2443
+ import type { ReactNode } from 'react';
2444
+ import BoundaryOverlay from './boundary-overlay';
2445
+ import { Header, MiniCart } from './remote-components';
2446
+ import { ultramodernLocalisedUrls } from './ultramodern-route-metadata';
2447
+
2448
+ const supportedLanguages = ['en', 'cs'] as const;
2449
+ type SupportedLanguage = (typeof supportedLanguages)[number];
2450
+
2451
+ type ShellFrameProps = {
2452
+ children: ReactNode;
2453
+ showCart?: boolean;
3005
2454
  };
3006
2455
 
3007
- const useCartRouteRemotes = () => {
3008
- const [remotes, setRemotes] = useState<CartRouteRemotes | null>(null);
2456
+ const localisedUrls = ultramodernLocalisedUrls as Record<
2457
+ string,
2458
+ Record<SupportedLanguage, string>
2459
+ >;
3009
2460
 
3010
- useEffect(() => {
3011
- let mounted = true;
3012
- import('../../remote-components').then(({ CartPage, Header }) => {
3013
- if (mounted) {
3014
- setRemotes({ CartPage, Header });
2461
+ const isSupportedLanguage = (value: string): value is SupportedLanguage =>
2462
+ supportedLanguages.includes(value as SupportedLanguage);
2463
+
2464
+ const normalisePath = (pathname: string) => {
2465
+ const normalised = pathname.replace(/\\/+$/u, '').replace(/\\/+/gu, '/');
2466
+ return normalised.length > 0 ? normalised : '/';
2467
+ };
2468
+
2469
+ const stripLanguagePrefix = (pathname: string) => {
2470
+ const segments = normalisePath(pathname).split('/').filter(Boolean);
2471
+ if (segments.length > 0 && isSupportedLanguage(segments[0] ?? '')) {
2472
+ segments.shift();
2473
+ }
2474
+ return \`/\${segments.join('/')}\`;
2475
+ };
2476
+
2477
+ const escapeRegExp = (value: string) =>
2478
+ value.replace(/[.*+?^\${}()|[\\]\\\\]/g, '\\\\$&');
2479
+
2480
+ const paramName = (segment: string) => segment.slice(1).replace(/\\?$/u, '');
2481
+
2482
+ const matchPattern = (pathname: string, pattern: string) => {
2483
+ const names: string[] = [];
2484
+ const source = normalisePath(pattern)
2485
+ .split('/')
2486
+ .filter(Boolean)
2487
+ .map(segment => {
2488
+ if (segment.startsWith(':')) {
2489
+ names.push(paramName(segment));
2490
+ return segment.endsWith('?') ? '(?:/([^/]+))?' : '/([^/]+)';
3015
2491
  }
3016
- });
2492
+ return \`/\${escapeRegExp(segment)}\`;
2493
+ })
2494
+ .join('');
2495
+ const match = new RegExp(\`^\${source || '/'}$\`).exec(normalisePath(pathname));
3017
2496
 
3018
- return () => {
3019
- mounted = false;
3020
- };
3021
- }, []);
2497
+ if (!match) {
2498
+ return undefined;
2499
+ }
3022
2500
 
3023
- return remotes;
2501
+ return names.reduce<Record<string, string>>((params, name, index) => {
2502
+ params[name] = decodeURIComponent(match[index + 1] ?? '');
2503
+ return params;
2504
+ }, {});
3024
2505
  };
3025
2506
 
3026
- export default function ShellCartPage() {
2507
+ const buildPath = (pattern: string, params: Record<string, string>) => {
2508
+ const path = normalisePath(pattern)
2509
+ .split('/')
2510
+ .filter(Boolean)
2511
+ .map(segment => {
2512
+ if (!segment.startsWith(':')) {
2513
+ return segment;
2514
+ }
2515
+ const value = params[paramName(segment)];
2516
+ return value ? encodeURIComponent(value) : '';
2517
+ })
2518
+ .filter(Boolean)
2519
+ .join('/');
2520
+
2521
+ return \`/\${path}\`;
2522
+ };
2523
+
2524
+ const resolveLocalisedPath = (
2525
+ pathname: string,
2526
+ targetLanguage: SupportedLanguage,
2527
+ ) => {
2528
+ const pathWithoutLanguage = stripLanguagePrefix(pathname);
2529
+
2530
+ for (const entry of Object.values(localisedUrls)) {
2531
+ const targetPattern = entry[targetLanguage];
2532
+ if (!targetPattern) {
2533
+ continue;
2534
+ }
2535
+
2536
+ for (const language of supportedLanguages) {
2537
+ const sourcePattern = entry[language];
2538
+ const params = sourcePattern
2539
+ ? matchPattern(pathWithoutLanguage, sourcePattern)
2540
+ : undefined;
2541
+ if (params) {
2542
+ return buildPath(targetPattern, params);
2543
+ }
2544
+ }
2545
+ }
2546
+
2547
+ return pathWithoutLanguage;
2548
+ };
2549
+
2550
+ const localizedPath = (pathname: string, language: SupportedLanguage) => {
2551
+ const pathWithoutLanguage = resolveLocalisedPath(pathname, language);
2552
+ return pathWithoutLanguage === '/' ? \`/\${language}\` : \`/\${language}\${pathWithoutLanguage}\`;
2553
+ };
2554
+
2555
+ const locationSuffix = (location: {
2556
+ hash?: unknown;
2557
+ search?: unknown;
2558
+ searchStr?: unknown;
2559
+ }) => {
2560
+ const locationSearch =
2561
+ typeof location.searchStr === 'string'
2562
+ ? location.searchStr
2563
+ : typeof location.search === 'string'
2564
+ ? location.search
2565
+ : '';
2566
+ const locationHash = typeof location.hash === 'string' ? location.hash : '';
2567
+
2568
+ return \`\${locationSearch}\${locationHash}\`;
2569
+ };
2570
+
2571
+ export default function ShellFrame({ children, showCart = true }: ShellFrameProps) {
3027
2572
  const { i18nInstance, language } = useModernI18n();
3028
2573
  const t = i18nInstance['t'].bind(i18nInstance);
3029
2574
  const location = useLocation();
3030
2575
  const suffix = locationSuffix(location);
3031
- const remotes = useCartRouteRemotes();
3032
- const Header = remotes?.Header;
3033
- const CartPage = remotes?.CartPage;
3034
2576
 
3035
2577
  return (
3036
- <main className="commerce-shell">
3037
- <LocalizedHead />
2578
+ <main className="min-h-screen bg-um-canvas px-4 py-5 text-um-foreground sm:px-6 lg:px-12">
3038
2579
  <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>
2580
+ <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">
2581
+ <Header />
2582
+ <div className="ml-auto flex min-w-0 items-center gap-2">
2583
+ <label className="sr-only" htmlFor="ultramodern-language">
2584
+ {t('shell.language.switcher')}
2585
+ </label>
2586
+ <select
2587
+ 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"
2588
+ id="ultramodern-language"
2589
+ onChange={event => {
2590
+ const nextLanguage = event.currentTarget.value;
2591
+ if (isSupportedLanguage(nextLanguage)) {
2592
+ window.location.assign(
2593
+ \`\${localizedPath(location.pathname, nextLanguage)}\${suffix}\`,
2594
+ );
2595
+ }
2596
+ }}
2597
+ value={language}
2598
+ >
2599
+ {supportedLanguages.map(code => (
2600
+ <option key={code} value={code}>
2601
+ {t(\`shell.language.\${code}\`)}
2602
+ </option>
2603
+ ))}
2604
+ </select>
2605
+ {showCart ? <MiniCart /> : null}
2606
+ </div>
3053
2607
  </div>
3054
- {CartPage ? <CartPage /> : null}
2608
+ {children}
3055
2609
  </main>
3056
2610
  );
3057
2611
  }
@@ -3179,8 +2733,9 @@ export default function BoundaryOverlay() {
3179
2733
 
3180
2734
  return (
3181
2735
  <>
3182
- <label className="commerce-boundary-toggle">
2736
+ <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">
3183
2737
  <input
2738
+ className="size-4 accent-emerald-800"
3184
2739
  checked={enabled}
3185
2740
  onChange={event => setEnabled(event.currentTarget.checked)}
3186
2741
  type="checkbox"
@@ -3188,15 +2743,16 @@ export default function BoundaryOverlay() {
3188
2743
  <span>{toggleLabel}</span>
3189
2744
  </label>
3190
2745
  {enabled ? (
3191
- <div aria-hidden="true" className="boundary-overlay">
2746
+ <div aria-hidden="true" className="pointer-events-none fixed inset-0 z-[70]">
3192
2747
  {boxes.map(box => (
3193
2748
  <div
3194
- className="boundary-overlay__box"
2749
+ className="fixed rounded-lg border"
3195
2750
  data-label-placement={box.labelPlacement}
3196
2751
  key={box.id}
3197
2752
  style={
3198
2753
  {
3199
- '--boundary-color': box.color,
2754
+ borderColor: box.color,
2755
+ boxShadow: \`0 0 0 1px rgba(255,255,255,.72), 0 6px 20px color-mix(in srgb, \${box.color} 20%, transparent)\`,
3200
2756
  height: box.height,
3201
2757
  left: box.left,
3202
2758
  top: box.top,
@@ -3204,7 +2760,12 @@ export default function BoundaryOverlay() {
3204
2760
  } as CSSProperties
3205
2761
  }
3206
2762
  >
3207
- <span className="boundary-overlay__label">{box.label}</span>
2763
+ <span
2764
+ 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' : ''}\`}
2765
+ style={{ backgroundColor: box.color }}
2766
+ >
2767
+ {box.label}
2768
+ </span>
3208
2769
  </div>
3209
2770
  ))}
3210
2771
  </div>
@@ -3214,13 +2775,19 @@ export default function BoundaryOverlay() {
3214
2775
  }
3215
2776
  `;
3216
2777
  }
3217
- function createShellRemoteComponents() {
2778
+ function createShellRemoteComponents(scope) {
3218
2779
  return `import { createLazyComponent } from '@module-federation/modern-js-v3/react';
3219
2780
  import { getInstance, loadRemote } from '@module-federation/modern-js-v3/runtime';
3220
- import type { JSX } from 'react';
2781
+ import { Suspense, useEffect, useMemo, useState, type ComponentType } from 'react';
2782
+ import HeaderServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/Header';
2783
+ import StorePickerServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/StorePicker';
2784
+ import RecommendationsServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/Recommendations';
2785
+ import ProductPageServer from '${ultramodern_workspace_packageName(scope, 'remote-decide')}/ProductPage';
2786
+ import MiniCartServer from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/MiniCart';
2787
+ import CartPageServer from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/CartPage';
3221
2788
 
3222
2789
  type RemoteComponentModule = {
3223
- default: () => JSX.Element;
2790
+ default: ComponentType;
3224
2791
  };
3225
2792
 
3226
2793
  const loadRemoteComponent = async (specifier: string) => {
@@ -3233,56 +2800,54 @@ const loadRemoteComponent = async (specifier: string) => {
3233
2800
 
3234
2801
  const remoteFallback =
3235
2802
  ({ error }: { error: Error }) =>
3236
- <div data-remote-error={error.name}>Remote unavailable</div>;
3237
-
3238
- export const Header = createLazyComponent({
3239
- export: 'default',
3240
- fallback: remoteFallback,
3241
- instance: getInstance(),
3242
- loader: () => loadRemoteComponent('explore/Header'),
3243
- loading: null,
3244
- noSSR: true,
3245
- });
3246
- export const StorePicker = createLazyComponent({
3247
- export: 'default',
3248
- fallback: remoteFallback,
3249
- instance: getInstance(),
3250
- loader: () => loadRemoteComponent('explore/StorePicker'),
3251
- loading: null,
3252
- noSSR: true,
3253
- });
3254
- export const Recommendations = createLazyComponent({
3255
- export: 'default',
3256
- fallback: remoteFallback,
3257
- instance: getInstance(),
3258
- loader: () => loadRemoteComponent('explore/Recommendations'),
3259
- loading: null,
3260
- noSSR: true,
3261
- });
3262
- export const ProductPage = createLazyComponent({
3263
- export: 'default',
3264
- fallback: remoteFallback,
3265
- instance: getInstance(),
3266
- loader: () => loadRemoteComponent('decide/ProductPage'),
3267
- loading: null,
3268
- noSSR: true,
3269
- });
3270
- export const MiniCart = createLazyComponent({
3271
- export: 'default',
3272
- fallback: remoteFallback,
3273
- instance: getInstance(),
3274
- loader: () => loadRemoteComponent('checkout/MiniCart'),
3275
- loading: null,
3276
- noSSR: true,
3277
- });
3278
- export const CartPage = createLazyComponent({
3279
- export: 'default',
3280
- fallback: remoteFallback,
3281
- instance: getInstance(),
3282
- loader: () => loadRemoteComponent('checkout/CartPage'),
3283
- loading: null,
3284
- noSSR: true,
3285
- });
2803
+ <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>;
2804
+
2805
+ const createHydratedRemote = (
2806
+ ServerComponent: ComponentType,
2807
+ specifier: string,
2808
+ ) => {
2809
+ return function HydratedRemote() {
2810
+ const [hydrated, setHydrated] = useState(false);
2811
+
2812
+ useEffect(() => {
2813
+ setHydrated(true);
2814
+ }, []);
2815
+
2816
+ const FederatedComponent = useMemo(() => {
2817
+ if (!hydrated) {
2818
+ return undefined;
2819
+ }
2820
+ const instance = getInstance();
2821
+ if (!instance) {
2822
+ return undefined;
2823
+ }
2824
+ return createLazyComponent({
2825
+ export: 'default',
2826
+ fallback: remoteFallback,
2827
+ instance,
2828
+ loader: () => loadRemoteComponent(specifier),
2829
+ loading: <ServerComponent />,
2830
+ });
2831
+ }, [hydrated]);
2832
+
2833
+ if (!FederatedComponent) {
2834
+ return <ServerComponent />;
2835
+ }
2836
+
2837
+ return (
2838
+ <Suspense fallback={<ServerComponent />}>
2839
+ <FederatedComponent />
2840
+ </Suspense>
2841
+ );
2842
+ };
2843
+ };
2844
+
2845
+ export const Header = createHydratedRemote(HeaderServer, 'explore/Header');
2846
+ export const StorePicker = createHydratedRemote(StorePickerServer, 'explore/StorePicker');
2847
+ export const Recommendations = createHydratedRemote(RecommendationsServer, 'explore/Recommendations');
2848
+ export const ProductPage = createHydratedRemote(ProductPageServer, 'decide/ProductPage');
2849
+ export const MiniCart = createHydratedRemote(MiniCartServer, 'checkout/MiniCart');
2850
+ export const CartPage = createHydratedRemote(CartPageServer, 'checkout/CartPage');
3286
2851
  `;
3287
2852
  }
3288
2853
  function createRemotePage(app) {
@@ -3327,12 +2892,13 @@ export default function ${toPascalCase(app.id)}Home() {
3327
2892
  const location = useLocation();
3328
2893
  const suffix = locationSuffix(location);
3329
2894
  ${effectBffState} return (
3330
- <main>
2895
+ <main className="min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8">
3331
2896
  <LocalizedHead />
3332
- <nav aria-label={t('${app.domain}.language.switcher')}>
2897
+ <nav aria-label={t('${app.domain}.language.switcher')} className="flex gap-3">
3333
2898
  {supportedLanguages.map(code => (
3334
2899
  <a
3335
2900
  aria-current={language === code ? 'page' : undefined}
2901
+ className="rounded-full border border-stone-900/15 bg-white px-4 py-2 text-sm font-bold text-stone-950 no-underline"
3336
2902
  href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
3337
2903
  key={code}
3338
2904
  >
@@ -3340,9 +2906,9 @@ ${effectBffState} return (
3340
2906
  </a>
3341
2907
  ))}
3342
2908
  </nav>
3343
- <h1>{t('${app.domain}.title')}</h1>
3344
- <p data-mf-role="${app.kind}">{t('${app.domain}.role')}</p>
3345
- <p data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
2909
+ <h1 className="mt-10 text-5xl font-black">{t('${app.domain}.title')}</h1>
2910
+ <p className="mt-3 text-lg text-stone-600" data-mf-role="${app.kind}">{t('${app.domain}.role')}</p>
2911
+ <p className="sr-only" data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
3346
2912
  {ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
3347
2913
  </p>
3348
2914
  ${effectBffMarkup} </main>
@@ -3370,9 +2936,9 @@ function createRemoteEntry(app) {
3370
2936
  `;
3371
2937
  return `export default function ${toPascalCase(app.domain ?? app.id)}Route() {
3372
2938
  return (
3373
- <section data-mf-remote="${app.id}" data-mf-expose="./Route">
3374
- <h2>${app.displayName}</h2>
3375
- <p>Route surface for ${app.domain ?? app.id}.</p>
2939
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10" data-mf-remote="${app.id}" data-mf-expose="./Route">
2940
+ <h2 className="text-2xl font-black">${app.displayName}</h2>
2941
+ <p className="mt-2 text-stone-600">Route surface for ${app.domain ?? app.id}.</p>
3376
2942
  </section>
3377
2943
  );
3378
2944
  }
@@ -3383,9 +2949,9 @@ function createRemoteWidget(app) {
3383
2949
  const body = 'vertical' === app.kind ? `Owns the ${app.domain} vertical route surface.` : 'Provides shared UI primitives for the workspace.';
3384
2950
  return `export default function ${componentName}() {
3385
2951
  return (
3386
- <section data-mf-remote="${app.id}">
3387
- <h2>${app.displayName}</h2>
3388
- <p>${body}</p>
2952
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10" data-mf-remote="${app.id}">
2953
+ <h2 className="text-2xl font-black">${app.displayName}</h2>
2954
+ <p className="mt-2 text-stone-600">${body}</p>
3389
2955
  </section>
3390
2956
  );
3391
2957
  }
@@ -3399,23 +2965,27 @@ export default function Header() {
3399
2965
  const t = i18nInstance['t'].bind(i18nInstance);
3400
2966
 
3401
2967
  return (
3402
- <header className="commerce-header" data-mf-boundary="explore">
3403
- <a className="commerce-logo" href={\`/\${language}\`}>Acre & Iron</a>
3404
- <nav aria-label={t('explore.header.navigation')} className="commerce-nav">
3405
- <a href={\`/\${language}/tractors\`}>{t('explore.header.machines')}</a>
3406
- <a href={\`/\${language}/stores\`}>{t('explore.header.stores')}</a>
2968
+ <header className="flex min-w-0 flex-1 flex-wrap items-center gap-x-8 gap-y-2" data-mf-boundary="explore">
2969
+ <a className="whitespace-nowrap text-xl font-black tracking-normal text-stone-950 no-underline" href={\`/\${language}\`}>Acre & Iron</a>
2970
+ <nav aria-label={t('explore.header.navigation')} className="flex items-center gap-5">
2971
+ <a className="text-sm font-extrabold text-stone-900 no-underline" href={\`/\${language}/tractors\`}>{t('explore.header.machines')}</a>
2972
+ <a className="text-sm font-extrabold text-stone-900 no-underline" href={\`/\${language}/stores\`}>{t('explore.header.stores')}</a>
3407
2973
  </nav>
3408
2974
  </header>
3409
2975
  );
3410
2976
  }
3411
2977
  `;
3412
2978
  if ('remote-explore' === app.id && './Recommendations' === expose) return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
2979
+ import autonomyImage from '../assets/autonomy.svg';
2980
+ import fieldLoaderImage from '../assets/field-loader.svg';
2981
+ import orchardImage from '../assets/orchard.svg';
2982
+ import vineyardImage from '../assets/vineyard.svg';
3413
2983
 
3414
2984
  const tractors = [
3415
- { badge: 'explore.recommendations.bestRows', name: 'Orchard Tractor', slug: 'orchard-tractor' },
3416
- { badge: 'explore.recommendations.aiFirst', name: 'Autonomy Retrofit Kit', slug: 'autonomy-retrofit-kit' },
3417
- { badge: 'explore.recommendations.loaderReady', name: 'Field Loader 112', slug: 'field-loader-112' },
3418
- { badge: 'explore.recommendations.vineyard', name: 'Vineyard Narrow 80', slug: 'vineyard-narrow-80' },
2985
+ { badge: 'explore.recommendations.bestRows', image: orchardImage, name: 'Orchard Tractor', slug: 'orchard-tractor' },
2986
+ { badge: 'explore.recommendations.aiFirst', image: autonomyImage, name: 'Autonomy Retrofit Kit', slug: 'autonomy-retrofit-kit' },
2987
+ { badge: 'explore.recommendations.loaderReady', image: fieldLoaderImage, name: 'Field Loader 112', slug: 'field-loader-112' },
2988
+ { badge: 'explore.recommendations.vineyard', image: vineyardImage, name: 'Vineyard Narrow 80', slug: 'vineyard-narrow-80' },
3419
2989
  ] as const;
3420
2990
 
3421
2991
  export default function Recommendations() {
@@ -3423,13 +2993,14 @@ export default function Recommendations() {
3423
2993
  const t = i18nInstance['t'].bind(i18nInstance);
3424
2994
 
3425
2995
  return (
3426
- <section className="commerce-page" data-mf-boundary="explore">
3427
- <h2 className="commerce-section-title">{t('explore.recommendations.title')}</h2>
3428
- <div className="commerce-grid">
2996
+ <section className="mx-auto mt-12 max-w-7xl" data-mf-boundary="explore">
2997
+ <h2 className="text-3xl font-black tracking-normal text-stone-950">{t('explore.recommendations.title')}</h2>
2998
+ <div className="mt-5 grid gap-4 md:grid-cols-2 xl:grid-cols-4">
3429
2999
  {tractors.map(tractor => (
3430
- <a className="commerce-card" href={\`/\${language}/tractors/\${tractor.slug}\`} key={tractor.slug}>
3431
- <span>{t(tractor.badge)}</span>
3432
- <strong>{tractor.name}</strong>
3000
+ <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}>
3001
+ <img alt="" className="aspect-video w-full rounded-xl bg-stone-200 object-cover" src={tractor.image} />
3002
+ <span className="mt-4 block text-xs font-black uppercase tracking-[0.16em] text-amber-700">{t(tractor.badge)}</span>
3003
+ <strong className="mt-2 block text-xl font-black leading-tight">{tractor.name}</strong>
3433
3004
  </a>
3434
3005
  ))}
3435
3006
  </div>
@@ -3438,22 +3009,26 @@ export default function Recommendations() {
3438
3009
  }
3439
3010
  `;
3440
3011
  if ('remote-explore' === app.id && './StorePicker' === expose) return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
3012
+ import fieldLoaderImage from '../assets/field-loader.svg';
3013
+ import vineyardImage from '../assets/vineyard.svg';
3441
3014
 
3442
3015
  export default function StorePicker() {
3443
3016
  const { i18nInstance } = useModernI18n();
3444
3017
  const t = i18nInstance['t'].bind(i18nInstance);
3445
3018
 
3446
3019
  return (
3447
- <section className="commerce-page" data-mf-boundary="explore">
3448
- <h2 className="commerce-section-title">{t('explore.stores.title')}</h2>
3449
- <div className="commerce-grid">
3450
- <article className="commerce-card">
3451
- <span>{t('explore.stores.northRegion')}</span>
3452
- <strong>Bohemia Field Supply</strong>
3020
+ <section className="mx-auto mt-12 max-w-7xl" data-mf-boundary="explore">
3021
+ <h2 className="text-3xl font-black tracking-normal text-stone-950">{t('explore.stores.title')}</h2>
3022
+ <div className="mt-5 grid gap-4 md:grid-cols-2">
3023
+ <article className="rounded-2xl bg-white/90 p-4 shadow-xl shadow-stone-900/10">
3024
+ <img alt="" className="aspect-video w-full rounded-xl bg-stone-200 object-cover" src={fieldLoaderImage} />
3025
+ <span className="mt-4 block text-xs font-black uppercase tracking-[0.16em] text-emerald-800">{t('explore.stores.northRegion')}</span>
3026
+ <strong className="mt-2 block text-2xl font-black">Bohemia Field Supply</strong>
3453
3027
  </article>
3454
- <article className="commerce-card">
3455
- <span>{t('explore.stores.southRegion')}</span>
3456
- <strong>Moravia Iron Works</strong>
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={vineyardImage} />
3030
+ <span className="mt-4 block text-xs font-black uppercase tracking-[0.16em] text-emerald-800">{t('explore.stores.southRegion')}</span>
3031
+ <strong className="mt-2 block text-2xl font-black">Moravia Iron Works</strong>
3457
3032
  </article>
3458
3033
  </div>
3459
3034
  </section>
@@ -3461,12 +3036,13 @@ export default function StorePicker() {
3461
3036
  }
3462
3037
  `;
3463
3038
  if ('remote-explore' === app.id && './Footer' === expose) return `export default function Footer() {
3464
- return <footer className="commerce-footer" data-mf-boundary="explore">Acre & Iron</footer>;
3039
+ return <footer className="mx-auto mt-12 max-w-7xl text-sm font-bold text-stone-600" data-mf-boundary="explore">Acre & Iron</footer>;
3465
3040
  }
3466
3041
  `;
3467
3042
  if ('./Widget' === expose) return createRemoteWidget(app);
3468
3043
  const componentName = `${toPascalCase(app.domain ?? app.id)}${toPascalCase(expose.replace(/^\.\//u, ''))}`;
3469
3044
  if ('remote-decide' === app.id && './ProductPage' === expose) return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
3045
+ import fieldLoaderImage from '../assets/field-loader.svg';
3470
3046
  import { AddToCart, Recommendations } from './remote-components';
3471
3047
 
3472
3048
  export default function ${componentName}() {
@@ -3475,16 +3051,16 @@ export default function ${componentName}() {
3475
3051
 
3476
3052
  return (
3477
3053
  <>
3478
- <section className="commerce-page commerce-product" data-mf-boundary="decide" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3479
- <div className="commerce-product-media" aria-hidden="true" />
3054
+ <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}">
3055
+ <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} />
3480
3056
  <div>
3481
- <p className="commerce-eyebrow">{t('decide.product.eyebrow')}</p>
3482
- <h1 className="commerce-title">Field Loader 112</h1>
3483
- <p className="commerce-lede">{t('decide.product.lede')}</p>
3484
- <div className="commerce-facts">
3485
- <article className="commerce-fact"><span>{t('decide.product.price')}</span><strong>EUR 42,500</strong></article>
3486
- <article className="commerce-fact"><span>{t('decide.product.power')}</span><strong>112 hp</strong></article>
3487
- <article className="commerce-fact"><span>{t('decide.product.availability')}</span><strong>{t('decide.product.inStock')}</strong></article>
3057
+ <p className="text-xs font-black uppercase tracking-[0.18em] text-emerald-800">{t('decide.product.eyebrow')}</p>
3058
+ <h1 className="mt-3 text-5xl font-black leading-none tracking-normal text-stone-950 md:text-7xl">Field Loader 112</h1>
3059
+ <p className="mt-5 max-w-2xl text-lg leading-8 text-stone-600">{t('decide.product.lede')}</p>
3060
+ <div className="mt-8 grid gap-4 sm:grid-cols-3">
3061
+ <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>
3062
+ <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>
3063
+ <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>
3488
3064
  </div>
3489
3065
  <AddToCart />
3490
3066
  </div>
@@ -3503,11 +3079,11 @@ export default function ${componentName}() {
3503
3079
  const cart = useCartLines();
3504
3080
 
3505
3081
  return (
3506
- <div className="commerce-checkout" data-mf-boundary="checkout">
3507
- <button className="commerce-button" onClick={cart.addFieldLoader} type="button">
3082
+ <div className="mt-8 flex flex-wrap gap-3" data-mf-boundary="checkout">
3083
+ <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">
3508
3084
  {t('checkout.actions.addToCart')}
3509
3085
  </button>
3510
- <a className="commerce-link-button" href={\`/\${language}/cart\`}>
3086
+ <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\`}>
3511
3087
  {t('checkout.actions.viewCart')}
3512
3088
  </a>
3513
3089
  </div>
@@ -3524,7 +3100,7 @@ export default function ${componentName}() {
3524
3100
  const count = cart.lines.reduce((sum, line) => sum + line.quantity, 0);
3525
3101
 
3526
3102
  return (
3527
- <a className="commerce-cart-button" data-mf-boundary="checkout" href={\`/\${language}/cart\`}>
3103
+ <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\`}>
3528
3104
  {t('checkout.cart.title')} ({count})
3529
3105
  </a>
3530
3106
  );
@@ -3539,24 +3115,24 @@ export default function ${componentName}() {
3539
3115
  const cart = useCartLines();
3540
3116
 
3541
3117
  return (
3542
- <section className="commerce-page" data-mf-boundary="checkout" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3543
- <h1 className="commerce-title">{t('checkout.cart.title')}</h1>
3544
- <div className="commerce-cart-panel">
3118
+ <section className="mx-auto mt-10 max-w-7xl" data-mf-boundary="checkout" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3119
+ <h1 className="text-5xl font-black leading-none tracking-normal text-stone-950 md:text-7xl">{t('checkout.cart.title')}</h1>
3120
+ <div className="mt-8 rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10">
3545
3121
  {cart.lines.length === 0 ? (
3546
3122
  <p>{t('checkout.cart.empty')}</p>
3547
3123
  ) : (
3548
3124
  <>
3549
3125
  {cart.lines.map(line => (
3550
- <article className="commerce-cart-line" key={line.id}>
3126
+ <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}>
3551
3127
  <div>
3552
- <strong>{line.name}</strong>
3553
- <p>EUR {line.price.toLocaleString('en-US')}</p>
3128
+ <strong className="text-lg font-black">{line.name}</strong>
3129
+ <p className="text-stone-600">EUR {line.price.toLocaleString('en-US')}</p>
3554
3130
  </div>
3555
- <div className="commerce-quantity">
3556
- <button className="commerce-quantity-button" onClick={() => cart.decrement(line.id)} type="button">-</button>
3557
- <span>{line.quantity}</span>
3558
- <button className="commerce-quantity-button" onClick={() => cart.increment(line.id)} type="button">+</button>
3559
- <button className="commerce-link-button" onClick={() => cart.remove(line.id)} type="button">
3131
+ <div className="flex flex-wrap items-center gap-2">
3132
+ <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>
3133
+ <span className="min-w-6 text-center font-black">{line.quantity}</span>
3134
+ <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>
3135
+ <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">
3560
3136
  {t('checkout.actions.remove')}
3561
3137
  </button>
3562
3138
  </div>
@@ -3572,21 +3148,23 @@ export default function ${componentName}() {
3572
3148
  `;
3573
3149
  return `export default function ${componentName}() {
3574
3150
  return (
3575
- <section data-mf-remote="${app.id}" data-mf-expose="${expose}">
3576
- <h2>${app.displayName} ${expose.replace(/^\.\//u, '')}</h2>
3577
- <p>Module Federation surface owned by ${app.ownership.team}.</p>
3151
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10" data-mf-remote="${app.id}" data-mf-expose="${expose}">
3152
+ <h2 className="text-2xl font-black">${app.displayName} ${expose.replace(/^\.\//u, '')}</h2>
3153
+ <p className="mt-2 text-stone-600">Module Federation surface owned by ${app.ownership.team}.</p>
3578
3154
  </section>
3579
3155
  );
3580
3156
  }
3581
3157
  `;
3582
3158
  }
3583
- function createDecideRemoteComponents() {
3159
+ function createDecideRemoteComponents(scope) {
3584
3160
  return `import { createLazyComponent } from '@module-federation/modern-js-v3/react';
3585
3161
  import { getInstance, loadRemote } from '@module-federation/modern-js-v3/runtime';
3586
- import type { JSX } from 'react';
3162
+ import { Suspense, useEffect, useMemo, useState, type ComponentType } from 'react';
3163
+ import RecommendationsServer from '${ultramodern_workspace_packageName(scope, 'remote-explore')}/Recommendations';
3164
+ import AddToCartServer from '${ultramodern_workspace_packageName(scope, 'remote-checkout')}/AddToCart';
3587
3165
 
3588
3166
  type RemoteComponentModule = {
3589
- default: () => JSX.Element;
3167
+ default: ComponentType;
3590
3168
  };
3591
3169
 
3592
3170
  const loadRemoteComponent = async (specifier: string) => {
@@ -3599,24 +3177,50 @@ const loadRemoteComponent = async (specifier: string) => {
3599
3177
 
3600
3178
  const remoteFallback =
3601
3179
  ({ error }: { error: Error }) =>
3602
- <div data-remote-error={error.name}>Remote unavailable</div>;
3603
-
3604
- export const AddToCart = createLazyComponent({
3605
- export: 'default',
3606
- fallback: remoteFallback,
3607
- instance: getInstance(),
3608
- loader: () => loadRemoteComponent('checkout/AddToCart'),
3609
- loading: null,
3610
- noSSR: true,
3611
- });
3612
- export const Recommendations = createLazyComponent({
3613
- export: 'default',
3614
- fallback: remoteFallback,
3615
- instance: getInstance(),
3616
- loader: () => loadRemoteComponent('explore/Recommendations'),
3617
- loading: null,
3618
- noSSR: true,
3619
- });
3180
+ <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>;
3181
+
3182
+ const createHydratedRemote = (
3183
+ ServerComponent: ComponentType,
3184
+ specifier: string,
3185
+ ) => {
3186
+ return function HydratedRemote() {
3187
+ const [hydrated, setHydrated] = useState(false);
3188
+
3189
+ useEffect(() => {
3190
+ setHydrated(true);
3191
+ }, []);
3192
+
3193
+ const FederatedComponent = useMemo(() => {
3194
+ if (!hydrated) {
3195
+ return undefined;
3196
+ }
3197
+ const instance = getInstance();
3198
+ if (!instance) {
3199
+ return undefined;
3200
+ }
3201
+ return createLazyComponent({
3202
+ export: 'default',
3203
+ fallback: remoteFallback,
3204
+ instance,
3205
+ loader: () => loadRemoteComponent(specifier),
3206
+ loading: <ServerComponent />,
3207
+ });
3208
+ }, [hydrated]);
3209
+
3210
+ if (!FederatedComponent) {
3211
+ return <ServerComponent />;
3212
+ }
3213
+
3214
+ return (
3215
+ <Suspense fallback={<ServerComponent />}>
3216
+ <FederatedComponent />
3217
+ </Suspense>
3218
+ );
3219
+ };
3220
+ };
3221
+
3222
+ export const AddToCart = createHydratedRemote(AddToCartServer, 'checkout/AddToCart');
3223
+ export const Recommendations = createHydratedRemote(RecommendationsServer, 'explore/Recommendations');
3620
3224
  `;
3621
3225
  }
3622
3226
  function remoteComponentOutputPath(app, expose) {
@@ -3749,17 +3353,9 @@ function createAppLocaleMessages(app, language) {
3749
3353
  };
3750
3354
  }
3751
3355
  function createDesignButton() {
3752
- return `import { designTokens } from '../tokens';
3753
-
3754
- export default function Button({ label }: { label: string }) {
3356
+ return `export default function Button({ label }: { label: string }) {
3755
3357
  return (
3756
- <button
3757
- type="button"
3758
- style={{
3759
- borderRadius: designTokens.radius.control,
3760
- color: designTokens.color.foreground,
3761
- }}
3762
- >
3358
+ <button className="rounded-full text-um-foreground" type="button">
3763
3359
  {label}
3764
3360
  </button>
3765
3361
  );
@@ -3875,14 +3471,12 @@ export function useCartLines() {
3875
3471
  `;
3876
3472
  }
3877
3473
  function createSharedDesignTokensCss() {
3878
- return `@layer ultramodern-shared-tokens {
3879
- :root {
3880
- --um-color-accent: #2f8f68;
3881
- --um-color-canvas: #f1eadc;
3882
- --um-color-foreground: #133225;
3883
- --um-color-link: #166b4b;
3884
- --um-color-surface: #f6fbf7;
3885
- }
3474
+ return `@theme {
3475
+ --color-um-accent: #2f8f68;
3476
+ --color-um-canvas: #f1eadc;
3477
+ --color-um-foreground: #133225;
3478
+ --color-um-link: #166b4b;
3479
+ --color-um-surface: #f6fbf7;
3886
3480
  }
3887
3481
  `;
3888
3482
  }
@@ -5788,10 +5382,12 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
5788
5382
  }
5789
5383
  writeFile(targetDir, `${app.directory}/module-federation.config.ts`, 'shell' === app.kind ? createShellModuleFederationConfig() : createRemoteModuleFederationConfig(app));
5790
5384
  writeFile(targetDir, `${app.directory}/src/routes/layout.tsx`, createLayout(app.id));
5385
+ for (const [relativePath, content] of Object.entries(commerceAssetsForApp(app)))writeFile(targetDir, `${app.directory}/${relativePath}`, content);
5791
5386
  writeFile(targetDir, `${app.directory}/src/routes/[lang]/page.tsx`, 'shell' === app.kind ? createShellPage() : createRemotePage(app));
5792
5387
  for (const route of createRouteOwnedI18nPaths(app))if ('/' !== route.canonicalPath && 'shell' !== app.kind) writeFile(targetDir, createRoutePageFilePath(app, route.canonicalPath), createRouteAliasPage(route.canonicalPath));
5793
5388
  if ('shell' === app.kind) {
5794
- writeFile(targetDir, `${app.directory}/src/routes/remote-components.tsx`, createShellRemoteComponents());
5389
+ writeFile(targetDir, `${app.directory}/src/routes/remote-components.tsx`, createShellRemoteComponents(scope));
5390
+ writeFile(targetDir, `${app.directory}/src/routes/shell-frame.tsx`, createShellFrameComponent());
5795
5391
  writeFile(targetDir, `${app.directory}/src/routes/boundary-overlay.tsx`, createShellBoundaryOverlay());
5796
5392
  writeFile(targetDir, `${app.directory}/src/effect/recommendations-client.ts`, createShellEffectClient(scope));
5797
5393
  writeFile(targetDir, `${app.directory}/src/routes/[lang]/tractors/page.tsx`, createShellTractorsPage());
@@ -5805,7 +5401,7 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind) {
5805
5401
  }
5806
5402
  if ('vertical' === app.kind || 'horizontal-remote' === app.kind) {
5807
5403
  writeFile(targetDir, `${app.directory}/src/remote-entry.tsx`, createRemoteEntry(app));
5808
- if ('remote-decide' === app.id) writeFile(targetDir, `${app.directory}/src/components/remote-components.tsx`, createDecideRemoteComponents());
5404
+ if ('remote-decide' === app.id) writeFile(targetDir, `${app.directory}/src/components/remote-components.tsx`, createDecideRemoteComponents(scope));
5809
5405
  if ('remote-checkout' === app.id) writeFile(targetDir, `${app.directory}/src/cart-store.ts`, createCheckoutCartStore());
5810
5406
  for (const expose of Object.keys(app.exposes ?? {})){
5811
5407
  const outputPath = remoteComponentOutputPath(app, expose);
@@ -5824,7 +5420,13 @@ function writeEffectService(targetDir, scope, packageSource, enableTailwind, ser
5824
5420
  writeFile(targetDir, `${service.directory}/src/ultramodern-build.ts`, createUltramodernBuildModule(scope, service));
5825
5421
  writeFile(targetDir, `${service.directory}/src/routes/layout.tsx`, createLayout(service.id));
5826
5422
  writeFile(targetDir, `${service.directory}/src/routes/page.tsx`, `export default function ${toPascalCase(service.id)}Home() {
5827
- return <main>${service.id} Effect service</main>;
5423
+ return (
5424
+ <main className="min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8">
5425
+ <section className="rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10">
5426
+ <h1 className="text-3xl font-black">${service.id} Effect service</h1>
5427
+ </section>
5428
+ </main>
5429
+ );
5828
5430
  }
5829
5431
  `);
5830
5432
  writeFile(targetDir, `${service.directory}/src/routes/index.css`, createServiceStyles(enableTailwind, scope, service));