@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.
- package/dist/index.js +453 -858
- 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
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
2760
|
-
import
|
|
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
|
-
<
|
|
2352
|
+
<ShellFrame>
|
|
2804
2353
|
<LocalizedHead />
|
|
2805
|
-
<
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
|
|
2810
|
-
|
|
2811
|
-
|
|
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
|
-
|
|
2830
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
</
|
|
2375
|
+
</ShellFrame>
|
|
2841
2376
|
);
|
|
2842
2377
|
}
|
|
2843
2378
|
`;
|
|
2844
2379
|
}
|
|
2845
2380
|
function createShellTractorsPage() {
|
|
2846
|
-
return `import {
|
|
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
|
|
2850
|
-
import
|
|
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
|
-
<
|
|
2390
|
+
<ShellFrame>
|
|
2893
2391
|
<LocalizedHead />
|
|
2894
|
-
<
|
|
2895
|
-
|
|
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 {
|
|
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
|
|
2922
|
-
import
|
|
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
|
-
<
|
|
2408
|
+
<ShellFrame>
|
|
2967
2409
|
<LocalizedHead />
|
|
2968
|
-
<
|
|
2969
|
-
|
|
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 {
|
|
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
|
|
2996
|
-
import
|
|
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
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
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
|
|
3008
|
-
|
|
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
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
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
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
}, []);
|
|
2491
|
+
if (!match) {
|
|
2492
|
+
return undefined;
|
|
2493
|
+
}
|
|
3022
2494
|
|
|
3023
|
-
return
|
|
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
|
-
|
|
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="
|
|
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
|
-
|
|
3040
|
-
|
|
3041
|
-
<
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
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
|
-
{
|
|
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="
|
|
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="
|
|
2740
|
+
<div aria-hidden="true" className="pointer-events-none fixed inset-0 z-[70]">
|
|
3193
2741
|
{boxes.map(box => (
|
|
3194
2742
|
<div
|
|
3195
|
-
className="
|
|
2743
|
+
className="fixed rounded-lg border"
|
|
3196
2744
|
data-label-placement={box.labelPlacement}
|
|
3197
2745
|
key={box.id}
|
|
3198
2746
|
style={
|
|
3199
2747
|
{
|
|
3200
|
-
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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="
|
|
3404
|
-
<a className="
|
|
3405
|
-
<nav aria-label={t('explore.header.navigation')} className="
|
|
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="
|
|
3428
|
-
<h2 className="
|
|
3429
|
-
<div className="
|
|
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="
|
|
3432
|
-
<
|
|
3433
|
-
<
|
|
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="
|
|
3449
|
-
<h2 className="
|
|
3450
|
-
<div className="
|
|
3451
|
-
<article className="
|
|
3452
|
-
<
|
|
3453
|
-
<
|
|
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="
|
|
3456
|
-
<
|
|
3457
|
-
<
|
|
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="
|
|
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="
|
|
3480
|
-
<
|
|
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="
|
|
3483
|
-
<h1 className="
|
|
3484
|
-
<p className="
|
|
3485
|
-
<div className="
|
|
3486
|
-
<article className="
|
|
3487
|
-
<article className="
|
|
3488
|
-
<article className="
|
|
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="
|
|
3508
|
-
<button className="
|
|
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="
|
|
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="
|
|
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="
|
|
3544
|
-
<h1 className="
|
|
3545
|
-
<div className="
|
|
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="
|
|
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="
|
|
3557
|
-
<button className="
|
|
3558
|
-
<span>{line.quantity}</span>
|
|
3559
|
-
<button className="
|
|
3560
|
-
<button className="
|
|
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:
|
|
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:
|
|
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 `
|
|
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 `@
|
|
3880
|
-
:
|
|
3881
|
-
--um-
|
|
3882
|
-
--um-
|
|
3883
|
-
--um-
|
|
3884
|
-
--um-
|
|
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
|
|
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));
|