@bleedingdev/modern-js-create 3.2.0-ultramodern.32 → 3.2.0-ultramodern.33
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 +36 -534
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1445,21 +1445,10 @@ const zephyrRspackPlugin = () => ({
|
|
|
1445
1445
|
const appId = '${app.id}';
|
|
1446
1446
|
const cloudflareWorkerName = '${createCloudflareWorkerName(scope, app)}';
|
|
1447
1447
|
const port = Number(process.env['${app.portEnv}'] ?? ${app.port});
|
|
1448
|
-
const
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
process.env['NODE_ENV'] === 'production' || process.argv.includes('build');
|
|
1453
|
-
|
|
1454
|
-
if (isProductionBuild && !hasConfiguredSiteUrl) {
|
|
1455
|
-
throw new Error(
|
|
1456
|
-
'MODERN_PUBLIC_SITE_URL must be set for production builds so canonical and hreflang URLs use the deployed origin.',
|
|
1457
|
-
);
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
const siteUrl = hasConfiguredSiteUrl
|
|
1461
|
-
? configuredSiteUrl
|
|
1462
|
-
: \`http://localhost:\${port}\`;
|
|
1448
|
+
const siteUrl =
|
|
1449
|
+
process.env['MODERN_PUBLIC_SITE_URL'] ??
|
|
1450
|
+
process.env['${createCloudflarePublicUrlEnv(app)}'] ??
|
|
1451
|
+
\`http://localhost:\${port}\`;
|
|
1463
1452
|
|
|
1464
1453
|
export default defineConfig(
|
|
1465
1454
|
presetUltramodern(
|
|
@@ -2620,7 +2609,6 @@ export default function ShellHome() {
|
|
|
2620
2609
|
`;
|
|
2621
2610
|
}
|
|
2622
2611
|
function createRemotePage(app) {
|
|
2623
|
-
if ('remote-commerce' === app.id) return createCommerceRemotePage(app);
|
|
2624
2612
|
const effectBffImport = appHasEffectApi(app) ? `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
2625
2613
|
import { Helmet } from '@modern-js/runtime/head';
|
|
2626
2614
|
import { useLocation } from '@modern-js/plugin-tanstack/runtime';
|
|
@@ -2685,404 +2673,6 @@ ${effectBffMarkup} </main>
|
|
|
2685
2673
|
}
|
|
2686
2674
|
`;
|
|
2687
2675
|
}
|
|
2688
|
-
function createCommerceRemotePage(app) {
|
|
2689
|
-
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
2690
|
-
import { Helmet } from '@modern-js/runtime/head';
|
|
2691
|
-
import { useLocation } from '@modern-js/plugin-tanstack/runtime';
|
|
2692
|
-
import { useEffect, useState, type CSSProperties } from 'react';
|
|
2693
|
-
import { ultramodernLocalisedUrls } from '../ultramodern-route-metadata';
|
|
2694
|
-
import { ultramodernUiMarker } from '../../ultramodern-build';
|
|
2695
|
-
|
|
2696
|
-
const languageCodes = ['en', 'cs'] as const;
|
|
2697
|
-
|
|
2698
|
-
const boundaryDefinitions = [
|
|
2699
|
-
{
|
|
2700
|
-
color: '#ff5a57',
|
|
2701
|
-
id: 'explore',
|
|
2702
|
-
labelKey: 'commerce.boundaries.explore',
|
|
2703
|
-
},
|
|
2704
|
-
{
|
|
2705
|
-
color: '#24d671',
|
|
2706
|
-
id: 'decide',
|
|
2707
|
-
labelKey: 'commerce.boundaries.decide',
|
|
2708
|
-
},
|
|
2709
|
-
{
|
|
2710
|
-
color: '#f4d044',
|
|
2711
|
-
id: 'checkout',
|
|
2712
|
-
labelKey: 'commerce.boundaries.checkout',
|
|
2713
|
-
},
|
|
2714
|
-
] as const;
|
|
2715
|
-
|
|
2716
|
-
type BoundaryId = (typeof boundaryDefinitions)[number]['id'];
|
|
2717
|
-
type BoundaryDefinition = (typeof boundaryDefinitions)[number];
|
|
2718
|
-
|
|
2719
|
-
const boundaryMetadata: Record<BoundaryId, BoundaryDefinition> = {
|
|
2720
|
-
checkout: boundaryDefinitions[2],
|
|
2721
|
-
decide: boundaryDefinitions[1],
|
|
2722
|
-
explore: boundaryDefinitions[0],
|
|
2723
|
-
};
|
|
2724
|
-
|
|
2725
|
-
const products = [
|
|
2726
|
-
{
|
|
2727
|
-
id: 'field-loader-112',
|
|
2728
|
-
titleKey: 'commerce.products.fieldLoader.title',
|
|
2729
|
-
descriptionKey: 'commerce.products.fieldLoader.description',
|
|
2730
|
-
priceKey: 'commerce.products.fieldLoader.price',
|
|
2731
|
-
powerKey: 'commerce.products.fieldLoader.power',
|
|
2732
|
-
availabilityKey: 'commerce.products.fieldLoader.availability',
|
|
2733
|
-
},
|
|
2734
|
-
{
|
|
2735
|
-
id: 'orchard-tractor',
|
|
2736
|
-
titleKey: 'commerce.products.orchard.title',
|
|
2737
|
-
badgeKey: 'commerce.products.orchard.badge',
|
|
2738
|
-
},
|
|
2739
|
-
{
|
|
2740
|
-
id: 'autonomy-kit',
|
|
2741
|
-
titleKey: 'commerce.products.autonomy.title',
|
|
2742
|
-
badgeKey: 'commerce.products.autonomy.badge',
|
|
2743
|
-
},
|
|
2744
|
-
] as const;
|
|
2745
|
-
|
|
2746
|
-
type ProductId = (typeof products)[number]['id'];
|
|
2747
|
-
type CartState = Partial<Record<ProductId, number>>;
|
|
2748
|
-
|
|
2749
|
-
type BoundaryLabels = Record<BoundaryId, string>;
|
|
2750
|
-
type BoundaryBox = {
|
|
2751
|
-
color: string;
|
|
2752
|
-
height: number;
|
|
2753
|
-
id: BoundaryId;
|
|
2754
|
-
label: string;
|
|
2755
|
-
labelPlacement: 'above' | 'inside';
|
|
2756
|
-
left: number;
|
|
2757
|
-
top: number;
|
|
2758
|
-
width: number;
|
|
2759
|
-
};
|
|
2760
|
-
|
|
2761
|
-
const featuredProduct = products[0];
|
|
2762
|
-
const recommendations = [products[1], products[2]] as const;
|
|
2763
|
-
|
|
2764
|
-
${createLocalizedHeadComponent()}
|
|
2765
|
-
const isBoundaryId = (value: string): value is BoundaryId =>
|
|
2766
|
-
Object.prototype.hasOwnProperty.call(boundaryMetadata, value);
|
|
2767
|
-
|
|
2768
|
-
function collectBoundaryBoxes(labels: BoundaryLabels): BoundaryBox[] {
|
|
2769
|
-
return Array.from(
|
|
2770
|
-
document.querySelectorAll<HTMLElement>('[data-boundary], [data-boundary-page]'),
|
|
2771
|
-
)
|
|
2772
|
-
.map(element => {
|
|
2773
|
-
const id = element.dataset.boundary ?? element.dataset.boundaryPage;
|
|
2774
|
-
|
|
2775
|
-
if (id === undefined || !isBoundaryId(id)) {
|
|
2776
|
-
return undefined;
|
|
2777
|
-
}
|
|
2778
|
-
|
|
2779
|
-
const rect = element.getBoundingClientRect();
|
|
2780
|
-
|
|
2781
|
-
if (rect.width <= 0 || rect.height <= 0) {
|
|
2782
|
-
return undefined;
|
|
2783
|
-
}
|
|
2784
|
-
|
|
2785
|
-
return {
|
|
2786
|
-
color: boundaryMetadata[id].color,
|
|
2787
|
-
height: rect.height,
|
|
2788
|
-
id,
|
|
2789
|
-
label: labels[id],
|
|
2790
|
-
labelPlacement: rect.top > 28 ? 'above' : 'inside',
|
|
2791
|
-
left: rect.left,
|
|
2792
|
-
top: rect.top,
|
|
2793
|
-
width: rect.width,
|
|
2794
|
-
};
|
|
2795
|
-
})
|
|
2796
|
-
.filter((box): box is BoundaryBox => box !== undefined);
|
|
2797
|
-
}
|
|
2798
|
-
|
|
2799
|
-
function BoundaryOverlay({
|
|
2800
|
-
labels,
|
|
2801
|
-
visible,
|
|
2802
|
-
}: {
|
|
2803
|
-
labels: BoundaryLabels;
|
|
2804
|
-
visible: boolean;
|
|
2805
|
-
}) {
|
|
2806
|
-
const [boxes, setBoxes] = useState<BoundaryBox[]>([]);
|
|
2807
|
-
|
|
2808
|
-
useEffect(() => {
|
|
2809
|
-
if (!visible) {
|
|
2810
|
-
setBoxes([]);
|
|
2811
|
-
return;
|
|
2812
|
-
}
|
|
2813
|
-
|
|
2814
|
-
let animationFrame = 0;
|
|
2815
|
-
const update = () => {
|
|
2816
|
-
cancelAnimationFrame(animationFrame);
|
|
2817
|
-
animationFrame = requestAnimationFrame(() => {
|
|
2818
|
-
setBoxes(collectBoundaryBoxes(labels));
|
|
2819
|
-
});
|
|
2820
|
-
};
|
|
2821
|
-
const observer = new ResizeObserver(update);
|
|
2822
|
-
|
|
2823
|
-
observer.observe(document.body);
|
|
2824
|
-
update();
|
|
2825
|
-
window.addEventListener('resize', update);
|
|
2826
|
-
window.addEventListener('scroll', update, true);
|
|
2827
|
-
|
|
2828
|
-
return () => {
|
|
2829
|
-
cancelAnimationFrame(animationFrame);
|
|
2830
|
-
observer.disconnect();
|
|
2831
|
-
window.removeEventListener('resize', update);
|
|
2832
|
-
window.removeEventListener('scroll', update, true);
|
|
2833
|
-
};
|
|
2834
|
-
}, [labels, visible]);
|
|
2835
|
-
|
|
2836
|
-
if (!visible) {
|
|
2837
|
-
return null;
|
|
2838
|
-
}
|
|
2839
|
-
|
|
2840
|
-
return (
|
|
2841
|
-
<div aria-hidden="true" className="boundary-overlay">
|
|
2842
|
-
{boxes.map((box, index) => (
|
|
2843
|
-
<div
|
|
2844
|
-
className="boundary-overlay__box"
|
|
2845
|
-
data-boundary-id={box.id}
|
|
2846
|
-
data-label-placement={box.labelPlacement}
|
|
2847
|
-
key={\`\${box.id}-\${index}\`}
|
|
2848
|
-
style={{
|
|
2849
|
-
'--boundary-color': box.color,
|
|
2850
|
-
height: box.height,
|
|
2851
|
-
left: box.left,
|
|
2852
|
-
top: box.top,
|
|
2853
|
-
width: box.width,
|
|
2854
|
-
} as CSSProperties}
|
|
2855
|
-
>
|
|
2856
|
-
<span className="boundary-overlay__label">{box.label}</span>
|
|
2857
|
-
</div>
|
|
2858
|
-
))}
|
|
2859
|
-
</div>
|
|
2860
|
-
);
|
|
2861
|
-
}
|
|
2862
|
-
|
|
2863
|
-
export default function ${toPascalCase(app.id)}Home() {
|
|
2864
|
-
const { i18nInstance, language } = useModernI18n();
|
|
2865
|
-
const t = i18nInstance.t.bind(i18nInstance);
|
|
2866
|
-
const location = useLocation();
|
|
2867
|
-
const suffix = locationSuffix(location);
|
|
2868
|
-
const [cart, setCart] = useState<CartState>({});
|
|
2869
|
-
const [showBoundaries, setShowBoundaries] = useState(false);
|
|
2870
|
-
const [effectApiStatus, setEffectApiStatus] = useState('pending');
|
|
2871
|
-
const boundaryLabels = {
|
|
2872
|
-
checkout: t('commerce.boundaries.checkout'),
|
|
2873
|
-
decide: t('commerce.boundaries.decide'),
|
|
2874
|
-
explore: t('commerce.boundaries.explore'),
|
|
2875
|
-
} satisfies BoundaryLabels;
|
|
2876
|
-
const cartLines = products
|
|
2877
|
-
.map(product => ({
|
|
2878
|
-
product,
|
|
2879
|
-
quantity: cart[product.id] ?? 0,
|
|
2880
|
-
}))
|
|
2881
|
-
.filter(line => line.quantity > 0);
|
|
2882
|
-
const cartCount = cartLines.reduce((total, line) => total + line.quantity, 0);
|
|
2883
|
-
|
|
2884
|
-
useEffect(() => {
|
|
2885
|
-
void fetch('${effectApiPrefix(app)}/effect/${effectApiStem(app)}?limit=1', {
|
|
2886
|
-
headers: {
|
|
2887
|
-
accept: 'application/json',
|
|
2888
|
-
},
|
|
2889
|
-
})
|
|
2890
|
-
.then(response => {
|
|
2891
|
-
if (!response.ok) {
|
|
2892
|
-
throw new Error(\`Effect BFF request failed: \${response.status}\`);
|
|
2893
|
-
}
|
|
2894
|
-
|
|
2895
|
-
return response.json() as Promise<{ items?: Array<{ title?: string }> }>;
|
|
2896
|
-
})
|
|
2897
|
-
.then(data => {
|
|
2898
|
-
setEffectApiStatus(data.items[0]?.title ?? 'empty');
|
|
2899
|
-
})
|
|
2900
|
-
.catch(() => {
|
|
2901
|
-
setEffectApiStatus('unavailable');
|
|
2902
|
-
});
|
|
2903
|
-
}, []);
|
|
2904
|
-
|
|
2905
|
-
const addToCart = (id: ProductId) => {
|
|
2906
|
-
setCart(current => ({
|
|
2907
|
-
...current,
|
|
2908
|
-
[id]: (current[id] ?? 0) + 1,
|
|
2909
|
-
}));
|
|
2910
|
-
};
|
|
2911
|
-
|
|
2912
|
-
const reduceQuantity = (id: ProductId) => {
|
|
2913
|
-
setCart(current => {
|
|
2914
|
-
const quantity = current[id] ?? 0;
|
|
2915
|
-
const next = { ...current };
|
|
2916
|
-
|
|
2917
|
-
if (quantity <= 1) {
|
|
2918
|
-
delete next[id];
|
|
2919
|
-
} else {
|
|
2920
|
-
next[id] = quantity - 1;
|
|
2921
|
-
}
|
|
2922
|
-
|
|
2923
|
-
return next;
|
|
2924
|
-
});
|
|
2925
|
-
};
|
|
2926
|
-
|
|
2927
|
-
const removeFromCart = (id: ProductId) => {
|
|
2928
|
-
setCart(current => {
|
|
2929
|
-
const next = { ...current };
|
|
2930
|
-
|
|
2931
|
-
delete next[id];
|
|
2932
|
-
return next;
|
|
2933
|
-
});
|
|
2934
|
-
};
|
|
2935
|
-
|
|
2936
|
-
return (
|
|
2937
|
-
<main className="commerce-shell">
|
|
2938
|
-
<LocalizedHead />
|
|
2939
|
-
<BoundaryOverlay labels={boundaryLabels} visible={showBoundaries} />
|
|
2940
|
-
<header className="commerce-header" data-boundary="explore">
|
|
2941
|
-
<strong className="commerce-logo">{t('commerce.brand')}</strong>
|
|
2942
|
-
<nav aria-label={t('commerce.navigation.primary')} className="commerce-nav">
|
|
2943
|
-
<a className="commerce-pill" href="#machines">
|
|
2944
|
-
{t('commerce.navigation.machines')}
|
|
2945
|
-
</a>
|
|
2946
|
-
<a className="commerce-pill" href="#checkout">
|
|
2947
|
-
{t('commerce.navigation.checkout')}
|
|
2948
|
-
</a>
|
|
2949
|
-
</nav>
|
|
2950
|
-
<div className="commerce-actions">
|
|
2951
|
-
<a className="commerce-cart-button" data-boundary="checkout" href="#cart">
|
|
2952
|
-
{t('commerce.cart.button', { count: cartCount })}
|
|
2953
|
-
</a>
|
|
2954
|
-
<nav aria-label={t('commerce.language.switcher')} className="commerce-language">
|
|
2955
|
-
{languageCodes.map(code => (
|
|
2956
|
-
<a
|
|
2957
|
-
aria-current={language === code ? 'page' : undefined}
|
|
2958
|
-
className="commerce-pill"
|
|
2959
|
-
href={\`\${localizedPath(location.pathname, code)}\${suffix}\`}
|
|
2960
|
-
key={code}
|
|
2961
|
-
>
|
|
2962
|
-
{t(\`commerce.language.\${code}\`)}
|
|
2963
|
-
</a>
|
|
2964
|
-
))}
|
|
2965
|
-
</nav>
|
|
2966
|
-
</div>
|
|
2967
|
-
</header>
|
|
2968
|
-
|
|
2969
|
-
<div className="commerce-page">
|
|
2970
|
-
<section className="commerce-product" data-boundary-page="decide" id="machines">
|
|
2971
|
-
<div
|
|
2972
|
-
aria-label={t('commerce.products.fieldLoader.imageAlt')}
|
|
2973
|
-
className="commerce-product-media"
|
|
2974
|
-
role="img"
|
|
2975
|
-
/>
|
|
2976
|
-
<div>
|
|
2977
|
-
<p className="commerce-eyebrow">{t('commerce.detail.eyebrow')}</p>
|
|
2978
|
-
<h1 className="commerce-title">{t(featuredProduct.titleKey)}</h1>
|
|
2979
|
-
<p className="commerce-lede">{t(featuredProduct.descriptionKey)}</p>
|
|
2980
|
-
<div className="commerce-facts">
|
|
2981
|
-
<div className="commerce-fact">
|
|
2982
|
-
<span>{t('commerce.detail.price')}</span>
|
|
2983
|
-
<strong>{t(featuredProduct.priceKey)}</strong>
|
|
2984
|
-
</div>
|
|
2985
|
-
<div className="commerce-fact">
|
|
2986
|
-
<span>{t('commerce.detail.power')}</span>
|
|
2987
|
-
<strong>{t(featuredProduct.powerKey)}</strong>
|
|
2988
|
-
</div>
|
|
2989
|
-
<div className="commerce-fact">
|
|
2990
|
-
<span>{t('commerce.detail.availability')}</span>
|
|
2991
|
-
<strong>{t(featuredProduct.availabilityKey)}</strong>
|
|
2992
|
-
</div>
|
|
2993
|
-
</div>
|
|
2994
|
-
<div className="commerce-checkout" data-boundary="checkout" id="checkout">
|
|
2995
|
-
<button
|
|
2996
|
-
className="commerce-button"
|
|
2997
|
-
onClick={() => addToCart(featuredProduct.id)}
|
|
2998
|
-
type="button"
|
|
2999
|
-
>
|
|
3000
|
-
{t('commerce.cart.add')}
|
|
3001
|
-
</button>
|
|
3002
|
-
<a className="commerce-link-button" href="#cart">
|
|
3003
|
-
{t('commerce.cart.view')}
|
|
3004
|
-
</a>
|
|
3005
|
-
</div>
|
|
3006
|
-
</div>
|
|
3007
|
-
</section>
|
|
3008
|
-
|
|
3009
|
-
<section data-boundary="explore">
|
|
3010
|
-
<h2 className="commerce-section-title">{t('commerce.recommendations.title')}</h2>
|
|
3011
|
-
<div className="commerce-grid">
|
|
3012
|
-
{recommendations.map(product => (
|
|
3013
|
-
<article className="commerce-card" key={product.id}>
|
|
3014
|
-
<span>{t(product.badgeKey)}</span>
|
|
3015
|
-
<strong>{t(product.titleKey)}</strong>
|
|
3016
|
-
</article>
|
|
3017
|
-
))}
|
|
3018
|
-
</div>
|
|
3019
|
-
</section>
|
|
3020
|
-
|
|
3021
|
-
<section className="commerce-cart-panel" data-boundary="checkout" id="cart">
|
|
3022
|
-
<h2>{t('commerce.cart.title')}</h2>
|
|
3023
|
-
{cartLines.length === 0 ? (
|
|
3024
|
-
<p>{t('commerce.cart.empty')}</p>
|
|
3025
|
-
) : (
|
|
3026
|
-
cartLines.map(line => (
|
|
3027
|
-
<div className="commerce-cart-line" key={line.product.id}>
|
|
3028
|
-
<strong>{t(line.product.titleKey)}</strong>
|
|
3029
|
-
<div className="commerce-quantity">
|
|
3030
|
-
<button
|
|
3031
|
-
aria-label={t('commerce.cart.decrease', {
|
|
3032
|
-
name: t(line.product.titleKey),
|
|
3033
|
-
})}
|
|
3034
|
-
className="commerce-quantity-button"
|
|
3035
|
-
onClick={() => reduceQuantity(line.product.id)}
|
|
3036
|
-
type="button"
|
|
3037
|
-
>
|
|
3038
|
-
-
|
|
3039
|
-
</button>
|
|
3040
|
-
<span>{line.quantity}</span>
|
|
3041
|
-
<button
|
|
3042
|
-
aria-label={t('commerce.cart.increase', {
|
|
3043
|
-
name: t(line.product.titleKey),
|
|
3044
|
-
})}
|
|
3045
|
-
className="commerce-quantity-button"
|
|
3046
|
-
onClick={() => addToCart(line.product.id)}
|
|
3047
|
-
type="button"
|
|
3048
|
-
>
|
|
3049
|
-
+
|
|
3050
|
-
</button>
|
|
3051
|
-
<button
|
|
3052
|
-
className="commerce-link-button"
|
|
3053
|
-
onClick={() => removeFromCart(line.product.id)}
|
|
3054
|
-
type="button"
|
|
3055
|
-
>
|
|
3056
|
-
{t('commerce.cart.remove')}
|
|
3057
|
-
</button>
|
|
3058
|
-
</div>
|
|
3059
|
-
</div>
|
|
3060
|
-
))
|
|
3061
|
-
)}
|
|
3062
|
-
</section>
|
|
3063
|
-
</div>
|
|
3064
|
-
|
|
3065
|
-
<footer className="commerce-footer" data-boundary="explore">
|
|
3066
|
-
<span>{t('commerce.footer.stack')}</span>
|
|
3067
|
-
<span data-testid="effect-bff-status">{effectApiStatus}</span>
|
|
3068
|
-
<span data-build-marker={ultramodernUiMarker.build} data-testid="ultramodern-ui-marker">
|
|
3069
|
-
{ultramodernUiMarker.appId}:{ultramodernUiMarker.version}
|
|
3070
|
-
</span>
|
|
3071
|
-
</footer>
|
|
3072
|
-
|
|
3073
|
-
<label className="commerce-boundary-toggle">
|
|
3074
|
-
<input
|
|
3075
|
-
checked={showBoundaries}
|
|
3076
|
-
onChange={event => setShowBoundaries(event.currentTarget.checked)}
|
|
3077
|
-
type="checkbox"
|
|
3078
|
-
/>
|
|
3079
|
-
{t('commerce.boundaries.toggle')}
|
|
3080
|
-
</label>
|
|
3081
|
-
</main>
|
|
3082
|
-
);
|
|
3083
|
-
}
|
|
3084
|
-
`;
|
|
3085
|
-
}
|
|
3086
2676
|
function createLayout(appId) {
|
|
3087
2677
|
return `import { Outlet } from '@modern-js/plugin-tanstack/runtime';
|
|
3088
2678
|
import './index.css';
|
|
@@ -3203,69 +2793,6 @@ function createAppLocaleMessages(app, language) {
|
|
|
3203
2793
|
role: domain,
|
|
3204
2794
|
title: `${app.displayName} CZ`
|
|
3205
2795
|
};
|
|
3206
|
-
if ('commerce' === domain) return {
|
|
3207
|
-
commerce: {
|
|
3208
|
-
boundaries: {
|
|
3209
|
-
checkout: 'en' === language ? 'checkout' : 'pokladna',
|
|
3210
|
-
decide: 'en' === language ? 'decide' : 'rozhodování',
|
|
3211
|
-
explore: 'en' === language ? 'explore' : 'procházení',
|
|
3212
|
-
toggle: 'en' === language ? 'show team boundaries' : 'zobrazit hranice týmů'
|
|
3213
|
-
},
|
|
3214
|
-
brand: 'Acre & Iron',
|
|
3215
|
-
cart: {
|
|
3216
|
-
add: 'en' === language ? 'Add to cart' : 'Přidat do košíku',
|
|
3217
|
-
button: 'en' === language ? 'Your cart ({{count}})' : 'Košík ({{count}})',
|
|
3218
|
-
decrease: 'en' === language ? 'Decrease {{name}} quantity' : 'Snížit množství položky {{name}}',
|
|
3219
|
-
empty: 'en' === language ? 'Your cart is empty.' : 'Košík je prázdný.',
|
|
3220
|
-
increase: 'en' === language ? 'Increase {{name}} quantity' : 'Zvýšit množství položky {{name}}',
|
|
3221
|
-
remove: 'en' === language ? 'Remove' : 'Odebrat',
|
|
3222
|
-
title: 'en' === language ? 'Cart' : 'Košík',
|
|
3223
|
-
view: 'en' === language ? 'View cart' : 'Zobrazit košík'
|
|
3224
|
-
},
|
|
3225
|
-
detail: {
|
|
3226
|
-
availability: 'en' === language ? 'Availability' : 'Dostupnost',
|
|
3227
|
-
eyebrow: 'en' === language ? 'Machine detail' : 'Detail stroje',
|
|
3228
|
-
power: 'en' === language ? 'Power' : 'Výkon',
|
|
3229
|
-
price: 'en' === language ? 'Price' : 'Cena'
|
|
3230
|
-
},
|
|
3231
|
-
footer: {
|
|
3232
|
-
stack: 'en' === language ? 'SPA, SSR-ready Module Federation, React, Effect BFF' : 'SPA, SSR-ready Module Federation, React, Effect BFF'
|
|
3233
|
-
},
|
|
3234
|
-
language: {
|
|
3235
|
-
cs: 'en' === language ? 'Czech' : 'Čeština',
|
|
3236
|
-
en: 'en' === language ? 'English' : 'Angličtina',
|
|
3237
|
-
switcher: 'en' === language ? 'Language' : 'Jazyk'
|
|
3238
|
-
},
|
|
3239
|
-
navigation: {
|
|
3240
|
-
checkout: 'en' === language ? 'Checkout' : 'Pokladna',
|
|
3241
|
-
machines: 'en' === language ? 'Machines' : 'Stroje',
|
|
3242
|
-
primary: 'en' === language ? 'Primary commerce navigation' : 'Hlavní navigace obchodu'
|
|
3243
|
-
},
|
|
3244
|
-
products: {
|
|
3245
|
-
autonomy: {
|
|
3246
|
-
badge: 'en' === language ? 'AI-first option' : 'AI varianta',
|
|
3247
|
-
title: 'en' === language ? 'Autonomy Retrofit Kit' : 'Sada pro autonomní řízení'
|
|
3248
|
-
},
|
|
3249
|
-
fieldLoader: {
|
|
3250
|
-
availability: 'en' === language ? 'In stock' : 'Skladem',
|
|
3251
|
-
description: 'en' === language ? 'A loader-ready tractor for feed, hay, gravel, and winter road work.' : 'Traktor připravený na nakladač pro krmivo, seno, štěrk i zimní údržbu cest.',
|
|
3252
|
-
imageAlt: 'en' === language ? 'Field Loader 112 tractor working on a bright farm lane' : 'Traktor Field Loader 112 pracuje na světlé polní cestě',
|
|
3253
|
-
power: '112 hp',
|
|
3254
|
-
price: 'EUR 42,500',
|
|
3255
|
-
title: 'Field Loader 112'
|
|
3256
|
-
},
|
|
3257
|
-
orchard: {
|
|
3258
|
-
badge: 'en' === language ? 'Best for tight rows' : 'Nejlepší do úzkých řádků',
|
|
3259
|
-
title: 'en' === language ? 'Narrow Orchard Tractor' : 'Úzký sadový traktor'
|
|
3260
|
-
}
|
|
3261
|
-
},
|
|
3262
|
-
recommendations: {
|
|
3263
|
-
title: 'en' === language ? 'Compare alternatives' : 'Porovnat alternativy'
|
|
3264
|
-
},
|
|
3265
|
-
role: 'en' === language ? 'commerce' : 'obchod',
|
|
3266
|
-
title: 'en' === language ? app.displayName : czechLabel.title
|
|
3267
|
-
}
|
|
3268
|
-
};
|
|
3269
2796
|
return {
|
|
3270
2797
|
[domain]: {
|
|
3271
2798
|
language: {
|
|
@@ -4343,48 +3870,6 @@ function createAppGeneratedContract(scope, app, apps, enableTailwind) {
|
|
|
4343
3870
|
apiSurface: 'effect-bff'
|
|
4344
3871
|
} : {}
|
|
4345
3872
|
},
|
|
4346
|
-
...'commerce' === app.domain ? {
|
|
4347
|
-
boundaryVisualization: {
|
|
4348
|
-
mode: 'overlay',
|
|
4349
|
-
layoutAffecting: false,
|
|
4350
|
-
toggle: 'user-controlled',
|
|
4351
|
-
boundaries: [
|
|
4352
|
-
{
|
|
4353
|
-
id: 'explore',
|
|
4354
|
-
labelKey: 'commerce.boundaries.explore',
|
|
4355
|
-
owner: 'team-explore',
|
|
4356
|
-
color: '#ff5a57',
|
|
4357
|
-
owns: [
|
|
4358
|
-
'header',
|
|
4359
|
-
'footer',
|
|
4360
|
-
'recommendations',
|
|
4361
|
-
'catalog'
|
|
4362
|
-
]
|
|
4363
|
-
},
|
|
4364
|
-
{
|
|
4365
|
-
id: 'decide',
|
|
4366
|
-
labelKey: 'commerce.boundaries.decide',
|
|
4367
|
-
owner: 'team-decide',
|
|
4368
|
-
color: '#24d671',
|
|
4369
|
-
owns: [
|
|
4370
|
-
'product-detail',
|
|
4371
|
-
'variant-selection'
|
|
4372
|
-
]
|
|
4373
|
-
},
|
|
4374
|
-
{
|
|
4375
|
-
id: 'checkout',
|
|
4376
|
-
labelKey: 'commerce.boundaries.checkout',
|
|
4377
|
-
owner: 'team-checkout',
|
|
4378
|
-
color: '#f4d044',
|
|
4379
|
-
owns: [
|
|
4380
|
-
'add-to-cart',
|
|
4381
|
-
'cart-link',
|
|
4382
|
-
'cart-lines'
|
|
4383
|
-
]
|
|
4384
|
-
}
|
|
4385
|
-
]
|
|
4386
|
-
}
|
|
4387
|
-
} : {},
|
|
4388
3873
|
...appHasEffectApi(app) ? {
|
|
4389
3874
|
effect: {
|
|
4390
3875
|
runtime: 'effect',
|
|
@@ -4553,6 +4038,13 @@ function createAssertMfTypesScript(remotes = remoteApps) {
|
|
|
4553
4038
|
import path from 'node:path';
|
|
4554
4039
|
|
|
4555
4040
|
const root = process.cwd();
|
|
4041
|
+
const generatedContractPath = path.join(
|
|
4042
|
+
root,
|
|
4043
|
+
'.modernjs/ultramodern-generated-contract.json',
|
|
4044
|
+
);
|
|
4045
|
+
const generatedContract = fs.existsSync(generatedContractPath)
|
|
4046
|
+
? JSON.parse(fs.readFileSync(generatedContractPath, 'utf-8'))
|
|
4047
|
+
: undefined;
|
|
4556
4048
|
const defaultAppDirs = ${JSON.stringify(remotes.map((remote)=>remote.directory), null, 2)};
|
|
4557
4049
|
|
|
4558
4050
|
const candidateDirs = process.argv.slice(2);
|
|
@@ -4570,20 +4062,20 @@ for (const appDir of appDirs) {
|
|
|
4570
4062
|
);
|
|
4571
4063
|
}
|
|
4572
4064
|
|
|
4573
|
-
const
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4065
|
+
const contractEntry = generatedContract?.apps?.find(
|
|
4066
|
+
app => app.path === appDir.replace(/\\\\/g, '/'),
|
|
4067
|
+
);
|
|
4068
|
+
if (
|
|
4069
|
+
contractEntry &&
|
|
4070
|
+
contractEntry.moduleFederation?.dts?.compilerInstance !==
|
|
4071
|
+
'--package typescript -- tsc'
|
|
4072
|
+
) {
|
|
4581
4073
|
throw new Error(
|
|
4582
|
-
\`Module Federation DTS must use the workspace TypeScript compiler: \${
|
|
4074
|
+
\`Module Federation DTS must use the workspace TypeScript compiler: \${appDir}\`,
|
|
4583
4075
|
);
|
|
4584
4076
|
}
|
|
4585
4077
|
|
|
4586
|
-
if (
|
|
4078
|
+
if (contractEntry && contractEntry.moduleFederation?.exposes?.length === 0) {
|
|
4587
4079
|
continue;
|
|
4588
4080
|
}
|
|
4589
4081
|
|
|
@@ -4909,13 +4401,23 @@ function createCloudflareVersionProofScript() {
|
|
|
4909
4401
|
return `#!/usr/bin/env node
|
|
4910
4402
|
import fs from 'node:fs';
|
|
4911
4403
|
import path from 'node:path';
|
|
4404
|
+
import { fileURLToPath } from 'node:url';
|
|
4912
4405
|
|
|
4913
|
-
const
|
|
4914
|
-
|
|
4915
|
-
'
|
|
4406
|
+
const workspaceRoot = path.resolve(
|
|
4407
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
4408
|
+
'..',
|
|
4409
|
+
);
|
|
4410
|
+
const contractPath = path.join(
|
|
4411
|
+
workspaceRoot,
|
|
4412
|
+
'.modernjs/ultramodern-generated-contract.json',
|
|
4413
|
+
);
|
|
4414
|
+
const defaultOut = path.join(
|
|
4415
|
+
workspaceRoot,
|
|
4416
|
+
'.codex/reports/cloudflare-version-proof/public-url-proof.json',
|
|
4417
|
+
);
|
|
4916
4418
|
|
|
4917
|
-
function readJson(
|
|
4918
|
-
return JSON.parse(fs.readFileSync(
|
|
4419
|
+
function readJson(filePath) {
|
|
4420
|
+
return JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
4919
4421
|
}
|
|
4920
4422
|
|
|
4921
4423
|
function parseArgs(argv) {
|