@vendure-platform/create 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +70 -0
- package/dist/assets/demo-data/branding/logo.svg +4 -0
- package/dist/assets/demo-data/images/absorbent-pad.webp +0 -0
- package/dist/assets/demo-data/images/adjustable-wrench.webp +0 -0
- package/dist/assets/demo-data/images/anchor-bolt.webp +0 -0
- package/dist/assets/demo-data/images/angle-grinder.webp +0 -0
- package/dist/assets/demo-data/images/barrier-tape.webp +0 -0
- package/dist/assets/demo-data/images/bench-grinder.webp +0 -0
- package/dist/assets/demo-data/images/bracket.webp +0 -0
- package/dist/assets/demo-data/images/broom.webp +0 -0
- package/dist/assets/demo-data/images/bucket.webp +0 -0
- package/dist/assets/demo-data/images/cable-gland.webp +0 -0
- package/dist/assets/demo-data/images/cable-tie.webp +0 -0
- package/dist/assets/demo-data/images/cable-tray.webp +0 -0
- package/dist/assets/demo-data/images/cable.webp +0 -0
- package/dist/assets/demo-data/images/chimney-base-kit.webp +0 -0
- package/dist/assets/demo-data/images/chimney-cowl-bird-guard.webp +0 -0
- package/dist/assets/demo-data/images/chimney-cowl-open.webp +0 -0
- package/dist/assets/demo-data/images/chimney-storm-collar.webp +0 -0
- package/dist/assets/demo-data/images/chimney-wall-bracket.webp +0 -0
- package/dist/assets/demo-data/images/circular-saw.webp +0 -0
- package/dist/assets/demo-data/images/cleaning-spray.webp +0 -0
- package/dist/assets/demo-data/images/conduit.webp +0 -0
- package/dist/assets/demo-data/images/cordless-drill.webp +0 -0
- package/dist/assets/demo-data/images/drill-bits.webp +0 -0
- package/dist/assets/demo-data/images/dust-mask.webp +0 -0
- package/dist/assets/demo-data/images/ear-defenders.webp +0 -0
- package/dist/assets/demo-data/images/ear-plugs.webp +0 -0
- package/dist/assets/demo-data/images/extension-lead.webp +0 -0
- package/dist/assets/demo-data/images/eye-wash-station.webp +0 -0
- package/dist/assets/demo-data/images/face-shield.webp +0 -0
- package/dist/assets/demo-data/images/file-set.webp +0 -0
- package/dist/assets/demo-data/images/first-aid-kit.webp +0 -0
- package/dist/assets/demo-data/images/floor-sign.webp +0 -0
- package/dist/assets/demo-data/images/flue-bend-45.webp +0 -0
- package/dist/assets/demo-data/images/flue-bend-90.webp +0 -0
- package/dist/assets/demo-data/images/flue-section-1000mm.webp +0 -0
- package/dist/assets/demo-data/images/flue-section-250mm.webp +0 -0
- package/dist/assets/demo-data/images/flue-section-500mm.webp +0 -0
- package/dist/assets/demo-data/images/fuse.webp +0 -0
- package/dist/assets/demo-data/images/glove-dispenser.webp +0 -0
- package/dist/assets/demo-data/images/grinding-disc.webp +0 -0
- package/dist/assets/demo-data/images/hacksaw.webp +0 -0
- package/dist/assets/demo-data/images/hammer.webp +0 -0
- package/dist/assets/demo-data/images/hand-sanitiser.webp +0 -0
- package/dist/assets/demo-data/images/head-torch.webp +0 -0
- package/dist/assets/demo-data/images/heat-gun.webp +0 -0
- package/dist/assets/demo-data/images/hex-bolt.webp +0 -0
- package/dist/assets/demo-data/images/hex-key-set.webp +0 -0
- package/dist/assets/demo-data/images/hex-nut.webp +0 -0
- package/dist/assets/demo-data/images/hi-vis-jacket.webp +0 -0
- package/dist/assets/demo-data/images/hi-vis-vest.webp +0 -0
- package/dist/assets/demo-data/images/hose-clamp.webp +0 -0
- package/dist/assets/demo-data/images/impact-driver.webp +0 -0
- package/dist/assets/demo-data/images/jigsaw.webp +0 -0
- package/dist/assets/demo-data/images/junction-box.webp +0 -0
- package/dist/assets/demo-data/images/knee-pads.webp +0 -0
- package/dist/assets/demo-data/images/machine-screw.webp +0 -0
- package/dist/assets/demo-data/images/made-to-order-configurable-chimney.webp +0 -0
- package/dist/assets/demo-data/images/mallet.webp +0 -0
- package/dist/assets/demo-data/images/mcb.webp +0 -0
- package/dist/assets/demo-data/images/mop.webp +0 -0
- package/dist/assets/demo-data/images/paper-towels.webp +0 -0
- package/dist/assets/demo-data/images/pipe-wrench.webp +0 -0
- package/dist/assets/demo-data/images/pliers-set.webp +0 -0
- package/dist/assets/demo-data/images/pry-bar.webp +0 -0
- package/dist/assets/demo-data/images/rcd.webp +0 -0
- package/dist/assets/demo-data/images/reciprocating-saw.webp +0 -0
- package/dist/assets/demo-data/images/rivet.webp +0 -0
- package/dist/assets/demo-data/images/roof-flashing-high-pitch.webp +0 -0
- package/dist/assets/demo-data/images/roof-flashing-low-pitch.webp +0 -0
- package/dist/assets/demo-data/images/safety-boots.webp +0 -0
- package/dist/assets/demo-data/images/safety-glasses.webp +0 -0
- package/dist/assets/demo-data/images/safety-harness.webp +0 -0
- package/dist/assets/demo-data/images/safety-helmet.webp +0 -0
- package/dist/assets/demo-data/images/safety-sign.webp +0 -0
- package/dist/assets/demo-data/images/sanding-disc.webp +0 -0
- package/dist/assets/demo-data/images/saw-blade.webp +0 -0
- package/dist/assets/demo-data/images/screwdriver-set.webp +0 -0
- package/dist/assets/demo-data/images/screwdriver.webp +0 -0
- package/dist/assets/demo-data/images/self-tapping-screw.webp +0 -0
- package/dist/assets/demo-data/images/socket-set.webp +0 -0
- package/dist/assets/demo-data/images/socket.webp +0 -0
- package/dist/assets/demo-data/images/spanner-set.webp +0 -0
- package/dist/assets/demo-data/images/spanner.webp +0 -0
- package/dist/assets/demo-data/images/spill-kit.webp +0 -0
- package/dist/assets/demo-data/images/spirit-level.webp +0 -0
- package/dist/assets/demo-data/images/switch.webp +0 -0
- package/dist/assets/demo-data/images/tape-measure.webp +0 -0
- package/dist/assets/demo-data/images/terminal-block.webp +0 -0
- package/dist/assets/demo-data/images/threaded-rod.webp +0 -0
- package/dist/assets/demo-data/images/torque-wrench.webp +0 -0
- package/dist/assets/demo-data/images/utility-knife.webp +0 -0
- package/dist/assets/demo-data/images/wall-pass-sleeve.webp +0 -0
- package/dist/assets/demo-data/images/wall-plug.webp +0 -0
- package/dist/assets/demo-data/images/washer.webp +0 -0
- package/dist/assets/demo-data/images/waste-bin.webp +0 -0
- package/dist/assets/demo-data/images/wire-connector.webp +0 -0
- package/dist/assets/demo-data/images/wire-cutters.webp +0 -0
- package/dist/assets/demo-data/images/wood-screw.webp +0 -0
- package/dist/assets/demo-data/images/work-gloves.webp +0 -0
- package/dist/assets/demo-data/images/work-light.webp +0 -0
- package/dist/assets/demo-data/initial-data.json +667 -0
- package/dist/assets/demo-data/products.csv +779 -0
- package/dist/assets/storefront/.env.example +14 -0
- package/dist/assets/storefront/.env.local +1 -0
- package/dist/assets/storefront/components.json +22 -0
- package/dist/assets/storefront/eslint.config.mjs +23 -0
- package/dist/assets/storefront/graphql.config.yml +2 -0
- package/dist/assets/storefront/messages/de.json +1196 -0
- package/dist/assets/storefront/messages/en.json +1196 -0
- package/dist/assets/storefront/next-env.d.ts +6 -0
- package/dist/assets/storefront/next.config.ts +73 -0
- package/dist/assets/storefront/package.json +77 -0
- package/dist/assets/storefront/postcss.config.mjs +5 -0
- package/dist/assets/storefront/public/next.svg +22 -0
- package/dist/assets/storefront/public/scenarios/b2b-wholesale/hero/hero-bg.webp +0 -0
- package/dist/assets/storefront/public/scenarios/b2b-wholesale/logo.svg +4 -0
- package/dist/assets/storefront/public/scenarios/default/logo.svg +4 -0
- package/dist/assets/storefront/public/scenarios/kaminpro/hero/hero-bg.webp +0 -0
- package/dist/assets/storefront/public/scenarios/kaminpro/logo.svg +7 -0
- package/dist/assets/storefront/public/vendure.svg +4 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/catalog/page.tsx +65 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/collection/[slug]/loading.tsx +24 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/collection/[slug]/page.tsx +194 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/layout.tsx +9 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/actions.ts +139 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/loading.tsx +46 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/product/[slug]/page.tsx +330 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/search/actions.ts +11 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/search/loading.tsx +20 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/search/page.tsx +97 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-analytics-tracker.tsx +46 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-results.tsx +53 -0
- package/dist/assets/storefront/src/app/[locale]/(catalog)/search/search-term.tsx +26 -0
- package/dist/assets/storefront/src/app/[locale]/(scenario)/[...path]/page.tsx +31 -0
- package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/accept-invitation-client.tsx +56 -0
- package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/actions.ts +32 -0
- package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/page.tsx +85 -0
- package/dist/assets/storefront/src/app/[locale]/accept-invitation/[token]/sign-out-and-retry.tsx +26 -0
- package/dist/assets/storefront/src/app/[locale]/account/addresses/actions.ts +125 -0
- package/dist/assets/storefront/src/app/[locale]/account/addresses/address-form.tsx +180 -0
- package/dist/assets/storefront/src/app/[locale]/account/addresses/addresses-client.tsx +292 -0
- package/dist/assets/storefront/src/app/[locale]/account/addresses/loading.tsx +48 -0
- package/dist/assets/storefront/src/app/[locale]/account/addresses/page.tsx +54 -0
- package/dist/assets/storefront/src/app/[locale]/account/approvals/actions.ts +28 -0
- package/dist/assets/storefront/src/app/[locale]/account/approvals/page.tsx +340 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/actions.ts +33 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/addresses/actions.ts +83 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/addresses/address-form.tsx +267 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/addresses/addresses-client.tsx +253 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/addresses/page.tsx +75 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/business-units/actions.ts +70 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/business-units/business-unit-form.tsx +153 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/business-units/business-units-client.tsx +210 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/business-units/page.tsx +66 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/business-units/types.ts +8 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/edit-company-form.tsx +57 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/page.tsx +89 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/payment-methods/page.tsx +65 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/payment-methods/payment-methods-client.tsx +55 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/roles/page.tsx +66 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/roles/roles-client.tsx +93 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/actions.ts +51 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/page.tsx +57 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/tax-ids/tax-ids-client.tsx +326 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/users/actions.ts +74 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/users/edit-user-form.tsx +157 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/users/invite-user-form.tsx +133 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/users/page.tsx +104 -0
- package/dist/assets/storefront/src/app/[locale]/account/company/users/users-client.tsx +266 -0
- package/dist/assets/storefront/src/app/[locale]/account/error.tsx +24 -0
- package/dist/assets/storefront/src/app/[locale]/account/layout.tsx +50 -0
- package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/page.tsx +463 -0
- package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/reorder-actions.ts +160 -0
- package/dist/assets/storefront/src/app/[locale]/account/orders/[code]/reorder-dialog.tsx +386 -0
- package/dist/assets/storefront/src/app/[locale]/account/orders/loading.tsx +45 -0
- package/dist/assets/storefront/src/app/[locale]/account/orders/page.tsx +309 -0
- package/dist/assets/storefront/src/app/[locale]/account/profile/actions.ts +106 -0
- package/dist/assets/storefront/src/app/[locale]/account/profile/change-password-form.tsx +82 -0
- package/dist/assets/storefront/src/app/[locale]/account/profile/edit-email-form.tsx +88 -0
- package/dist/assets/storefront/src/app/[locale]/account/profile/edit-profile-form.tsx +80 -0
- package/dist/assets/storefront/src/app/[locale]/account/profile/loading.tsx +54 -0
- package/dist/assets/storefront/src/app/[locale]/account/profile/page.tsx +44 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/actions.ts +103 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/file-upload-tab.tsx +148 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/manual-entry-tab.tsx +112 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/page.tsx +26 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/preview-table.tsx +170 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/quick-order-form.tsx +243 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/save-to-list-dialog.tsx +153 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/sku-autocomplete.tsx +118 -0
- package/dist/assets/storefront/src/app/[locale]/account/quick-order/text-input-tab.tsx +40 -0
- package/dist/assets/storefront/src/app/[locale]/account/quotes/[id]/page.tsx +260 -0
- package/dist/assets/storefront/src/app/[locale]/account/quotes/actions.ts +253 -0
- package/dist/assets/storefront/src/app/[locale]/account/quotes/new/new-quote-form.tsx +28 -0
- package/dist/assets/storefront/src/app/[locale]/account/quotes/new/page.tsx +51 -0
- package/dist/assets/storefront/src/app/[locale]/account/quotes/page.tsx +248 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/loading.tsx +44 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/page.tsx +51 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/[id]/shopping-list-detail-client.tsx +562 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/actions.ts +235 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/create-shopping-list-form.tsx +86 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/loading.tsx +48 -0
- package/dist/assets/storefront/src/app/[locale]/account/shopping-lists/page.tsx +176 -0
- package/dist/assets/storefront/src/app/[locale]/account/store-credits/actions.ts +31 -0
- package/dist/assets/storefront/src/app/[locale]/account/store-credits/claim-form.tsx +41 -0
- package/dist/assets/storefront/src/app/[locale]/account/store-credits/page.tsx +190 -0
- package/dist/assets/storefront/src/app/[locale]/account/store-credits/reveal-code.tsx +38 -0
- package/dist/assets/storefront/src/app/[locale]/account/verify-email/page.tsx +117 -0
- package/dist/assets/storefront/src/app/[locale]/cart/actions.ts +128 -0
- package/dist/assets/storefront/src/app/[locale]/cart/cart-items.tsx +228 -0
- package/dist/assets/storefront/src/app/[locale]/cart/cart-line-actions.tsx +55 -0
- package/dist/assets/storefront/src/app/[locale]/cart/cart-quantity-control.tsx +158 -0
- package/dist/assets/storefront/src/app/[locale]/cart/cart-remove-button.tsx +36 -0
- package/dist/assets/storefront/src/app/[locale]/cart/cart.tsx +151 -0
- package/dist/assets/storefront/src/app/[locale]/cart/code-input.tsx +49 -0
- package/dist/assets/storefront/src/app/[locale]/cart/loading.tsx +10 -0
- package/dist/assets/storefront/src/app/[locale]/cart/order-summary.tsx +178 -0
- package/dist/assets/storefront/src/app/[locale]/cart/page.tsx +33 -0
- package/dist/assets/storefront/src/app/[locale]/cart/promotion-code.tsx +142 -0
- package/dist/assets/storefront/src/app/[locale]/cart/reapproval-confirm.tsx +76 -0
- package/dist/assets/storefront/src/app/[locale]/cart/request-quote-button.tsx +80 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/actions.ts +192 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/cancel-quote-checkout-button.tsx +30 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/checkout-flow.tsx +214 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/checkout-provider.tsx +181 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/loading.tsx +90 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/order-summary.tsx +160 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/page.tsx +154 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/steps/delivery-step.tsx +107 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/steps/payment-step.tsx +110 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/steps/review-step.tsx +180 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/steps/shipping-address-step.tsx +518 -0
- package/dist/assets/storefront/src/app/[locale]/checkout/types.ts +7 -0
- package/dist/assets/storefront/src/app/[locale]/error.tsx +28 -0
- package/dist/assets/storefront/src/app/[locale]/forgot-password/actions.ts +28 -0
- package/dist/assets/storefront/src/app/[locale]/forgot-password/forgot-password-form.tsx +128 -0
- package/dist/assets/storefront/src/app/[locale]/forgot-password/page.tsx +24 -0
- package/dist/assets/storefront/src/app/[locale]/globals.css +72 -0
- package/dist/assets/storefront/src/app/[locale]/layout.tsx +202 -0
- package/dist/assets/storefront/src/app/[locale]/not-found.tsx +26 -0
- package/dist/assets/storefront/src/app/[locale]/order-confirmation/[code]/order-confirmation.tsx +296 -0
- package/dist/assets/storefront/src/app/[locale]/order-confirmation/[code]/page.tsx +18 -0
- package/dist/assets/storefront/src/app/[locale]/page.tsx +125 -0
- package/dist/assets/storefront/src/app/[locale]/register/actions.ts +50 -0
- package/dist/assets/storefront/src/app/[locale]/register/page.tsx +82 -0
- package/dist/assets/storefront/src/app/[locale]/register/registration-form.tsx +237 -0
- package/dist/assets/storefront/src/app/[locale]/register-company/actions.ts +40 -0
- package/dist/assets/storefront/src/app/[locale]/register-company/page.tsx +43 -0
- package/dist/assets/storefront/src/app/[locale]/register-company/registration-form.tsx +48 -0
- package/dist/assets/storefront/src/app/[locale]/reset-password/actions.ts +40 -0
- package/dist/assets/storefront/src/app/[locale]/reset-password/page.tsx +32 -0
- package/dist/assets/storefront/src/app/[locale]/reset-password/reset-password-form.tsx +96 -0
- package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/add-to-cart-button.tsx +31 -0
- package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/loading.tsx +29 -0
- package/dist/assets/storefront/src/app/[locale]/shopping-list/[code]/page.tsx +157 -0
- package/dist/assets/storefront/src/app/[locale]/sign-in/actions.ts +76 -0
- package/dist/assets/storefront/src/app/[locale]/sign-in/login-form.tsx +177 -0
- package/dist/assets/storefront/src/app/[locale]/sign-in/page.tsx +81 -0
- package/dist/assets/storefront/src/app/[locale]/verify/actions.ts +41 -0
- package/dist/assets/storefront/src/app/[locale]/verify/page.tsx +40 -0
- package/dist/assets/storefront/src/app/[locale]/verify/verify-content.tsx +127 -0
- package/dist/assets/storefront/src/app/[locale]/verify-pending/page.tsx +67 -0
- package/dist/assets/storefront/src/app/api/clear-company-context/route.ts +26 -0
- package/dist/assets/storefront/src/app/api/draft/disable/route.ts +12 -0
- package/dist/assets/storefront/src/app/api/draft/route.ts +17 -0
- package/dist/assets/storefront/src/app/api/revalidate/route.ts +110 -0
- package/dist/assets/storefront/src/app/api/search-analytics/route.ts +16 -0
- package/dist/assets/storefront/src/app/favicon.ico +0 -0
- package/dist/assets/storefront/src/components/commerce/account-nav-items.ts +56 -0
- package/dist/assets/storefront/src/components/commerce/account-sidebar.tsx +112 -0
- package/dist/assets/storefront/src/components/commerce/active-filters.tsx +107 -0
- package/dist/assets/storefront/src/components/commerce/approval-decision-form.tsx +70 -0
- package/dist/assets/storefront/src/components/commerce/approval-status-badge.tsx +37 -0
- package/dist/assets/storefront/src/components/commerce/business-unit-switcher.tsx +56 -0
- package/dist/assets/storefront/src/components/commerce/catalog-search-bar.tsx +83 -0
- package/dist/assets/storefront/src/components/commerce/category-product-section.tsx +69 -0
- package/dist/assets/storefront/src/components/commerce/category-sidebar.tsx +133 -0
- package/dist/assets/storefront/src/components/commerce/collection-hero-banner.tsx +36 -0
- package/dist/assets/storefront/src/components/commerce/company-state-badge.tsx +32 -0
- package/dist/assets/storefront/src/components/commerce/company-switcher.tsx +58 -0
- package/dist/assets/storefront/src/components/commerce/configurator-form.tsx +606 -0
- package/dist/assets/storefront/src/components/commerce/facet-filters.tsx +286 -0
- package/dist/assets/storefront/src/components/commerce/gift-card-pdp.tsx +43 -0
- package/dist/assets/storefront/src/components/commerce/gift-card-product-info.tsx +137 -0
- package/dist/assets/storefront/src/components/commerce/highlighted-text.tsx +30 -0
- package/dist/assets/storefront/src/components/commerce/instant-search-dropdown.tsx +377 -0
- package/dist/assets/storefront/src/components/commerce/order-status-badge.tsx +41 -0
- package/dist/assets/storefront/src/components/commerce/packaging-unit-selector.tsx +146 -0
- package/dist/assets/storefront/src/components/commerce/permission-gate.tsx +20 -0
- package/dist/assets/storefront/src/components/commerce/price-range-filter.tsx +111 -0
- package/dist/assets/storefront/src/components/commerce/price-tiers.tsx +98 -0
- package/dist/assets/storefront/src/components/commerce/price.tsx +29 -0
- package/dist/assets/storefront/src/components/commerce/product-card-list.tsx +121 -0
- package/dist/assets/storefront/src/components/commerce/product-card.tsx +89 -0
- package/dist/assets/storefront/src/components/commerce/product-carousel.tsx +42 -0
- package/dist/assets/storefront/src/components/commerce/product-grid.tsx +54 -0
- package/dist/assets/storefront/src/components/commerce/product-image-carousel.tsx +127 -0
- package/dist/assets/storefront/src/components/commerce/product-info.tsx +525 -0
- package/dist/assets/storefront/src/components/commerce/product-list-expansion.tsx +393 -0
- package/dist/assets/storefront/src/components/commerce/product-list-view.tsx +34 -0
- package/dist/assets/storefront/src/components/commerce/product-sidebar.tsx +175 -0
- package/dist/assets/storefront/src/components/commerce/product-view-switcher.tsx +107 -0
- package/dist/assets/storefront/src/components/commerce/quote-action-buttons.tsx +235 -0
- package/dist/assets/storefront/src/components/commerce/quote-activity-timeline.tsx +320 -0
- package/dist/assets/storefront/src/components/commerce/quote-comment-form.tsx +52 -0
- package/dist/assets/storefront/src/components/commerce/quote-csv-export-button.tsx +97 -0
- package/dist/assets/storefront/src/components/commerce/quote-product-search.tsx +139 -0
- package/dist/assets/storefront/src/components/commerce/quote-request-form.tsx +252 -0
- package/dist/assets/storefront/src/components/commerce/quote-status-badge.tsx +41 -0
- package/dist/assets/storefront/src/components/commerce/quote-validity-indicator.tsx +33 -0
- package/dist/assets/storefront/src/components/commerce/quote-version-comparison.tsx +88 -0
- package/dist/assets/storefront/src/components/commerce/related-products.tsx +56 -0
- package/dist/assets/storefront/src/components/commerce/shop-by-category.tsx +59 -0
- package/dist/assets/storefront/src/components/commerce/shopping-list-toggle.tsx +158 -0
- package/dist/assets/storefront/src/components/commerce/sort-dropdown.tsx +51 -0
- package/dist/assets/storefront/src/components/commerce/store-credit-summary.tsx +45 -0
- package/dist/assets/storefront/src/components/commerce/subcollection-tiles.tsx +56 -0
- package/dist/assets/storefront/src/components/layout/auth-page-shell.tsx +15 -0
- package/dist/assets/storefront/src/components/layout/draft-mode-action.ts +8 -0
- package/dist/assets/storefront/src/components/layout/draft-mode-indicator.tsx +54 -0
- package/dist/assets/storefront/src/components/layout/draft-mode-link.tsx +29 -0
- package/dist/assets/storefront/src/components/layout/footer.tsx +168 -0
- package/dist/assets/storefront/src/components/layout/navbar/actions.ts +33 -0
- package/dist/assets/storefront/src/components/layout/navbar/cart-icon.tsx +50 -0
- package/dist/assets/storefront/src/components/layout/navbar/channel-picker-wrapper.tsx +19 -0
- package/dist/assets/storefront/src/components/layout/navbar/channel-picker.tsx +53 -0
- package/dist/assets/storefront/src/components/layout/navbar/currency-picker-wrapper.tsx +21 -0
- package/dist/assets/storefront/src/components/layout/navbar/currency-picker.tsx +52 -0
- package/dist/assets/storefront/src/components/layout/navbar/language-picker.tsx +51 -0
- package/dist/assets/storefront/src/components/layout/navbar/login-button.tsx +34 -0
- package/dist/assets/storefront/src/components/layout/navbar/mobile-nav.tsx +74 -0
- package/dist/assets/storefront/src/components/layout/navbar/nav-menu-items.tsx +51 -0
- package/dist/assets/storefront/src/components/layout/navbar/navbar-cart.tsx +5 -0
- package/dist/assets/storefront/src/components/layout/navbar/navbar-collections.tsx +291 -0
- package/dist/assets/storefront/src/components/layout/navbar/navbar-link.tsx +28 -0
- package/dist/assets/storefront/src/components/layout/navbar/navbar-user.tsx +147 -0
- package/dist/assets/storefront/src/components/layout/navbar/theme-switcher.tsx +39 -0
- package/dist/assets/storefront/src/components/layout/navbar.tsx +117 -0
- package/dist/assets/storefront/src/components/layout/search-input.tsx +71 -0
- package/dist/assets/storefront/src/components/providers/awaiting-approval-banner.tsx +58 -0
- package/dist/assets/storefront/src/components/providers/cart-count-server.tsx +31 -0
- package/dist/assets/storefront/src/components/providers/company-context-guard.tsx +47 -0
- package/dist/assets/storefront/src/components/providers/company-permissions-server.tsx +14 -0
- package/dist/assets/storefront/src/components/providers/theme-provider.tsx +16 -0
- package/dist/assets/storefront/src/components/shared/breadcrumbs.tsx +39 -0
- package/dist/assets/storefront/src/components/shared/catalog-sidebar-skeleton.tsx +21 -0
- package/dist/assets/storefront/src/components/shared/country-select.tsx +83 -0
- package/dist/assets/storefront/src/components/shared/error-state.tsx +16 -0
- package/dist/assets/storefront/src/components/shared/pagination.tsx +119 -0
- package/dist/assets/storefront/src/components/shared/prefetch-link.tsx +36 -0
- package/dist/assets/storefront/src/components/shared/product-grid-skeleton.tsx +26 -0
- package/dist/assets/storefront/src/components/shared/scenario-paused.tsx +80 -0
- package/dist/assets/storefront/src/components/shared/skeletons/cart-skeleton.tsx +48 -0
- package/dist/assets/storefront/src/components/shared/skeletons/navbar-user-skeleton.tsx +9 -0
- package/dist/assets/storefront/src/components/shared/skeletons/search-input-skeleton.tsx +7 -0
- package/dist/assets/storefront/src/components/shared/skeletons/search-results-skeleton.tsx +17 -0
- package/dist/assets/storefront/src/components/ui/accordion.tsx +66 -0
- package/dist/assets/storefront/src/components/ui/alert-dialog.tsx +157 -0
- package/dist/assets/storefront/src/components/ui/alert.tsx +66 -0
- package/dist/assets/storefront/src/components/ui/aspect-ratio.tsx +11 -0
- package/dist/assets/storefront/src/components/ui/avatar.tsx +53 -0
- package/dist/assets/storefront/src/components/ui/badge.tsx +46 -0
- package/dist/assets/storefront/src/components/ui/breadcrumb.tsx +109 -0
- package/dist/assets/storefront/src/components/ui/button.tsx +58 -0
- package/dist/assets/storefront/src/components/ui/calendar.tsx +213 -0
- package/dist/assets/storefront/src/components/ui/card.tsx +92 -0
- package/dist/assets/storefront/src/components/ui/carousel.tsx +241 -0
- package/dist/assets/storefront/src/components/ui/chart.tsx +357 -0
- package/dist/assets/storefront/src/components/ui/checkbox.tsx +32 -0
- package/dist/assets/storefront/src/components/ui/collapsible.tsx +33 -0
- package/dist/assets/storefront/src/components/ui/command.tsx +184 -0
- package/dist/assets/storefront/src/components/ui/context-menu.tsx +252 -0
- package/dist/assets/storefront/src/components/ui/dialog.tsx +143 -0
- package/dist/assets/storefront/src/components/ui/drawer.tsx +135 -0
- package/dist/assets/storefront/src/components/ui/dropdown-menu.tsx +257 -0
- package/dist/assets/storefront/src/components/ui/empty-state.tsx +37 -0
- package/dist/assets/storefront/src/components/ui/field.tsx +244 -0
- package/dist/assets/storefront/src/components/ui/form.tsx +167 -0
- package/dist/assets/storefront/src/components/ui/hover-card.tsx +44 -0
- package/dist/assets/storefront/src/components/ui/input-otp.tsx +77 -0
- package/dist/assets/storefront/src/components/ui/input.tsx +21 -0
- package/dist/assets/storefront/src/components/ui/kbd-shortcut.tsx +20 -0
- package/dist/assets/storefront/src/components/ui/label.tsx +24 -0
- package/dist/assets/storefront/src/components/ui/menubar.tsx +276 -0
- package/dist/assets/storefront/src/components/ui/navigation-menu.tsx +168 -0
- package/dist/assets/storefront/src/components/ui/pagination.tsx +127 -0
- package/dist/assets/storefront/src/components/ui/popover.tsx +48 -0
- package/dist/assets/storefront/src/components/ui/progress.tsx +31 -0
- package/dist/assets/storefront/src/components/ui/radio-group.tsx +45 -0
- package/dist/assets/storefront/src/components/ui/resizable.tsx +56 -0
- package/dist/assets/storefront/src/components/ui/scroll-area.tsx +58 -0
- package/dist/assets/storefront/src/components/ui/select.tsx +185 -0
- package/dist/assets/storefront/src/components/ui/separator.tsx +28 -0
- package/dist/assets/storefront/src/components/ui/sheet.tsx +139 -0
- package/dist/assets/storefront/src/components/ui/sidebar.tsx +728 -0
- package/dist/assets/storefront/src/components/ui/skeleton.tsx +13 -0
- package/dist/assets/storefront/src/components/ui/slider.tsx +63 -0
- package/dist/assets/storefront/src/components/ui/sonner.tsx +25 -0
- package/dist/assets/storefront/src/components/ui/switch.tsx +31 -0
- package/dist/assets/storefront/src/components/ui/table.tsx +116 -0
- package/dist/assets/storefront/src/components/ui/tabs.tsx +66 -0
- package/dist/assets/storefront/src/components/ui/textarea.tsx +18 -0
- package/dist/assets/storefront/src/components/ui/toggle-group.tsx +73 -0
- package/dist/assets/storefront/src/components/ui/toggle.tsx +47 -0
- package/dist/assets/storefront/src/components/ui/tooltip.tsx +61 -0
- package/dist/assets/storefront/src/config/branding.ts +4 -0
- package/dist/assets/storefront/src/config/scenario-meta.ts +46 -0
- package/dist/assets/storefront/src/config/scenario.ts +313 -0
- package/dist/assets/storefront/src/contexts/auth-context.tsx +35 -0
- package/dist/assets/storefront/src/graphql.ts +14 -0
- package/dist/assets/storefront/src/hooks/use-mobile.ts +19 -0
- package/dist/assets/storefront/src/i18n/locale-utils.ts +33 -0
- package/dist/assets/storefront/src/i18n/locales.ts +18 -0
- package/dist/assets/storefront/src/i18n/navigation.ts +35 -0
- package/dist/assets/storefront/src/i18n/request.ts +19 -0
- package/dist/assets/storefront/src/i18n/routing.ts +19 -0
- package/dist/assets/storefront/src/i18n/server.ts +16 -0
- package/dist/assets/storefront/src/lib/actions/switch-channel.ts +32 -0
- package/dist/assets/storefront/src/lib/actions/switch-currency.ts +25 -0
- package/dist/assets/storefront/src/lib/auth.ts +18 -0
- package/dist/assets/storefront/src/lib/backend-health.ts +38 -0
- package/dist/assets/storefront/src/lib/cart-count-context.tsx +59 -0
- package/dist/assets/storefront/src/lib/cart-guard-utils.ts +10 -0
- package/dist/assets/storefront/src/lib/cart-guard.ts +104 -0
- package/dist/assets/storefront/src/lib/channel-server.ts +28 -0
- package/dist/assets/storefront/src/lib/channel.ts +2 -0
- package/dist/assets/storefront/src/lib/company-context.ts +35 -0
- package/dist/assets/storefront/src/lib/company-permissions-context.tsx +40 -0
- package/dist/assets/storefront/src/lib/currency-server.ts +20 -0
- package/dist/assets/storefront/src/lib/currency.ts +2 -0
- package/dist/assets/storefront/src/lib/format.ts +48 -0
- package/dist/assets/storefront/src/lib/metadata.ts +85 -0
- package/dist/assets/storefront/src/lib/quantity.test.js +20 -0
- package/dist/assets/storefront/src/lib/quantity.ts +20 -0
- package/dist/assets/storefront/src/lib/search-bar-context.tsx +45 -0
- package/dist/assets/storefront/src/lib/search-helpers.ts +69 -0
- package/dist/assets/storefront/src/lib/use-recent-searches.ts +55 -0
- package/dist/assets/storefront/src/lib/utils.ts +6 -0
- package/dist/assets/storefront/src/lib/vendure/actions.ts +96 -0
- package/dist/assets/storefront/src/lib/vendure/api.ts +164 -0
- package/dist/assets/storefront/src/lib/vendure/approval-utils.ts +21 -0
- package/dist/assets/storefront/src/lib/vendure/cached.ts +71 -0
- package/dist/assets/storefront/src/lib/vendure/fragments.ts +213 -0
- package/dist/assets/storefront/src/lib/vendure/instant-search-action.ts +104 -0
- package/dist/assets/storefront/src/lib/vendure/mutations.ts +1136 -0
- package/dist/assets/storefront/src/lib/vendure/queries.ts +1406 -0
- package/dist/assets/storefront/src/middleware.ts +11 -0
- package/dist/assets/storefront/src/scenarios/b2b-wholesale/branding.ts +180 -0
- package/dist/assets/storefront/src/scenarios/b2b-wholesale/hero.tsx +122 -0
- package/dist/assets/storefront/src/scenarios/b2b-wholesale/index.ts +21 -0
- package/dist/assets/storefront/src/scenarios/b2b-wholesale/meta.ts +3 -0
- package/dist/assets/storefront/src/scenarios/default/branding.ts +148 -0
- package/dist/assets/storefront/src/scenarios/default/hero.tsx +107 -0
- package/dist/assets/storefront/src/scenarios/default/index.ts +12 -0
- package/dist/assets/storefront/src/scenarios/default/meta.ts +3 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/auth-gate.tsx +36 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/branding.ts +238 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/cart-items.tsx +359 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/hero.tsx +123 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/index.ts +50 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/meta.ts +9 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/banners.tsx +21 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/bom-basket.tsx +221 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/btn.tsx +38 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/chip.tsx +35 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/config-header.tsx +72 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/field-row.tsx +126 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/info-dot.tsx +38 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/login-notice.tsx +81 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/module-panel.tsx +144 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/quote-dialog.tsx +110 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/schematic.tsx +674 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/components/why-panel.tsx +66 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/configurator-pdp.tsx +43 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/configurator-shell.tsx +320 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/lib/data.ts +150 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/lib/types.ts +30 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/pdp/styles.css +104 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/shop-by-system.tsx +97 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/system-finder/decision-tree.ts +261 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/system-finder/page.tsx +21 -0
- package/dist/assets/storefront/src/scenarios/kaminpro/system-finder/wizard.tsx +600 -0
- package/dist/assets/storefront/src/schema.graphql.placeholder +5 -0
- package/dist/assets/storefront/tsconfig.json +37 -0
- package/dist/assets/templates/CLAUDE.md.hbs +63 -0
- package/dist/assets/templates/README.md.hbs +53 -0
- package/dist/assets/templates/custom-populate.ts.hbs +28 -0
- package/dist/assets/templates/docker-compose.yml.hbs +29 -0
- package/dist/assets/templates/env.hbs +44 -0
- package/dist/assets/templates/environment.d.ts.hbs +32 -0
- package/dist/assets/templates/gitignore.hbs +7 -0
- package/dist/assets/templates/index.ts.hbs +16 -0
- package/dist/assets/templates/npmrc.hbs +1 -0
- package/dist/assets/templates/populate.ts.hbs +27 -0
- package/dist/assets/templates/root-package.json.hbs +17 -0
- package/dist/assets/templates/server-package.json.hbs +31 -0
- package/dist/assets/templates/tsconfig.dashboard.json.hbs +17 -0
- package/dist/assets/templates/tsconfig.root.json.hbs +16 -0
- package/dist/assets/templates/tsconfig.server.json.hbs +20 -0
- package/dist/assets/templates/vendure-config.ts.hbs +80 -0
- package/dist/assets/templates/vite.config.mts.hbs +27 -0
- package/dist/bin/run.d.ts +2 -0
- package/dist/bin/run.js +79 -0
- package/dist/bin/run.js.map +1 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +154 -0
- package/dist/cli.js.map +1 -0
- package/dist/git-init.d.ts +4 -0
- package/dist/git-init.js +60 -0
- package/dist/git-init.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/plugin-registry.d.ts +10 -0
- package/dist/plugin-registry.js +485 -0
- package/dist/plugin-registry.js.map +1 -0
- package/dist/scaffolder.d.ts +10 -0
- package/dist/scaffolder.js +218 -0
- package/dist/scaffolder.js.map +1 -0
- package/dist/storefront-copier.d.ts +6 -0
- package/dist/storefront-copier.js +68 -0
- package/dist/storefront-copier.js.map +1 -0
- package/dist/template-renderer.d.ts +30 -0
- package/dist/template-renderer.js +177 -0
- package/dist/template-renderer.js.map +1 -0
- package/dist/types.d.ts +60 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useCallback, useEffect, useRef, useState, type CSSProperties } from 'react';
|
|
4
|
+
import { getEvaluatedValue, getFieldDefinition, labelForOption } from '../lib/data';
|
|
5
|
+
import type { ConfigurationEvaluation, ConfiguratorSystem } from '../lib/types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Returns a set of field refs that have changed since the previous
|
|
9
|
+
* evaluation. Refs stay in the set for `durationMs` before being cleared,
|
|
10
|
+
* so the caller can apply a fading highlight animation to whichever
|
|
11
|
+
* schematic element depends on that field.
|
|
12
|
+
*
|
|
13
|
+
* IMPORTANT: `refs` must be a stable reference across renders (module-level
|
|
14
|
+
* constant or `useMemo`). An inline array literal would re-run the effect
|
|
15
|
+
* every render, clearing and re-setting `changed` on each pass — producing
|
|
16
|
+
* a continuous flash. Don't change that without changing the effect deps.
|
|
17
|
+
*
|
|
18
|
+
* Null-evaluation behaviour is deliberately one-way: when `evaluation` goes
|
|
19
|
+
* null (e.g. transient network error), we preserve the last-known value
|
|
20
|
+
* map so that on reconnect, fields whose values haven't actually changed
|
|
21
|
+
* don't spuriously re-flash.
|
|
22
|
+
*/
|
|
23
|
+
function useRecentFieldChanges(
|
|
24
|
+
evaluation: ConfigurationEvaluation | null,
|
|
25
|
+
refs: readonly string[],
|
|
26
|
+
durationMs = 1600,
|
|
27
|
+
): Set<string> {
|
|
28
|
+
const prev = useRef<Map<string, string>>(new Map());
|
|
29
|
+
const [changed, setChanged] = useState<Set<string>>(new Set());
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
if (!evaluation) return;
|
|
33
|
+
const newChanged = new Set<string>();
|
|
34
|
+
for (const ref of refs) {
|
|
35
|
+
const value = evaluation.fields.find(f => f.fieldRef === ref)?.value ?? '';
|
|
36
|
+
const before = prev.current.get(ref);
|
|
37
|
+
if (before !== undefined && before !== value) {
|
|
38
|
+
newChanged.add(ref);
|
|
39
|
+
}
|
|
40
|
+
prev.current.set(ref, value);
|
|
41
|
+
}
|
|
42
|
+
if (newChanged.size === 0) return;
|
|
43
|
+
setChanged(newChanged);
|
|
44
|
+
const t = setTimeout(() => setChanged(new Set()), durationMs);
|
|
45
|
+
return () => clearTimeout(t);
|
|
46
|
+
}, [evaluation, refs, durationMs]);
|
|
47
|
+
|
|
48
|
+
return changed;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Technical axonometric schematic of the assembled chimney stack.
|
|
53
|
+
*
|
|
54
|
+
* This is the one place in the PDP that hard-couples to specific backend
|
|
55
|
+
* field refs because the SVG geometry branches on their values. If any of
|
|
56
|
+
* these refs are renamed or removed, the schematic degrades to a safe
|
|
57
|
+
* neutral default — the rest of the PDP keeps working.
|
|
58
|
+
*
|
|
59
|
+
* Read field refs:
|
|
60
|
+
* - allgemein.brennstoff (title strip annotation)
|
|
61
|
+
* - allgemein.dn (DN callout)
|
|
62
|
+
* - allgemein.bauhoehe (stack length + callout, mm from backend)
|
|
63
|
+
* - allgemein.leistung (kW badge on Kessel)
|
|
64
|
+
* - montage.aussenmontage ('true' / 'false' — wall vs roof geometry)
|
|
65
|
+
* - tstueck.winkel ('45' / '87' / '90' — T-piece shape)
|
|
66
|
+
* - tstueck.reinigung ('unten' / 'seitlich' — Fußteil at base)
|
|
67
|
+
* - ueberdach.kaminabschluss ('regenhaube' / 'abstromkonus' / 'offen' — mouth)
|
|
68
|
+
* - ueberdach.hoeheUeberBefestigung (above-roof section, mm from backend)
|
|
69
|
+
* - dachdurchfuehrung.dachneigung (roof pitch angle, degrees)
|
|
70
|
+
* - zugbegrenzer.notwendig (draft-regulator valve toggle)
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
const REFS = {
|
|
74
|
+
brennstoff: 'allgemein.brennstoff',
|
|
75
|
+
dn: 'allgemein.dn',
|
|
76
|
+
bauhoehe: 'allgemein.bauhoehe',
|
|
77
|
+
leistung: 'allgemein.leistung',
|
|
78
|
+
aussenmontage: 'montage.aussenmontage',
|
|
79
|
+
tWinkel: 'tstueck.winkel',
|
|
80
|
+
reinigung: 'tstueck.reinigung',
|
|
81
|
+
kaminabschluss: 'ueberdach.kaminabschluss',
|
|
82
|
+
hoeheUeberBefestigung: 'ueberdach.hoeheUeberBefestigung',
|
|
83
|
+
dachneigung: 'dachdurchfuehrung.dachneigung',
|
|
84
|
+
zugbegrenzer: 'zugbegrenzer.notwendig',
|
|
85
|
+
} as const;
|
|
86
|
+
|
|
87
|
+
interface SchematicProps {
|
|
88
|
+
system: ConfiguratorSystem;
|
|
89
|
+
evaluation: ConfigurationEvaluation | null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const WATCHED_REFS = Object.values(REFS);
|
|
93
|
+
|
|
94
|
+
export function Schematic({ system, evaluation }: SchematicProps) {
|
|
95
|
+
const get = (ref: string, fallback = '') => getEvaluatedValue(evaluation, ref, fallback);
|
|
96
|
+
const recent = useRecentFieldChanges(evaluation, WATCHED_REFS);
|
|
97
|
+
// Returns the flash class name when the given ref (or any of the given
|
|
98
|
+
// refs) changed recently — applied to SVG groups so they pulse.
|
|
99
|
+
const flashClass = useCallback(
|
|
100
|
+
(...refs: string[]) => (refs.some(r => recent.has(r)) ? 'kp-schem-flash' : undefined),
|
|
101
|
+
[recent],
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const brennstoffValue = get(REFS.brennstoff);
|
|
105
|
+
const brennstoffField = getFieldDefinition(system, REFS.brennstoff);
|
|
106
|
+
const brennstoffLabel = brennstoffValue ? labelForOption(brennstoffField, brennstoffValue) : '—';
|
|
107
|
+
|
|
108
|
+
// Drawing label: strip the scenario prefix from the system code.
|
|
109
|
+
// `kaminpro-stahlline-dw` → `STAHLLINE-DW`, `kaminpro-polyflex-pp` → `POLYFLEX-PP`.
|
|
110
|
+
const dwgLabel = system.code.replace(/^kaminpro-/, '').toUpperCase();
|
|
111
|
+
|
|
112
|
+
const dnValue = get(REFS.dn);
|
|
113
|
+
|
|
114
|
+
const montageAussen = get(REFS.aussenmontage) === 'true';
|
|
115
|
+
// Empty string = field cleared by a constrain rule — render a neutral
|
|
116
|
+
// placeholder rather than falling back to the default shape (which
|
|
117
|
+
// looks like a silent failure).
|
|
118
|
+
const kaminabschlussRaw = get(REFS.kaminabschluss, '');
|
|
119
|
+
const kaminabschluss = kaminabschlussRaw || 'pending';
|
|
120
|
+
const isAbstrom = kaminabschluss === 'abstromkonus';
|
|
121
|
+
const isPending = kaminabschluss === 'pending';
|
|
122
|
+
const tWinkel = get(REFS.tWinkel, '87');
|
|
123
|
+
const reinigung = get(REFS.reinigung, 'unten');
|
|
124
|
+
|
|
125
|
+
// Pressure regime derived from brennstoff (since druck is not a
|
|
126
|
+
// user-facing field any more). Gas/Öl = Überdruck (pushed gases),
|
|
127
|
+
// solid fuels = Unterdruck (natural draft).
|
|
128
|
+
const isUeberdruck = brennstoffValue === 'gas' || brennstoffValue === 'oel';
|
|
129
|
+
|
|
130
|
+
// kW rating for the appliance badge on the Kessel.
|
|
131
|
+
const leistungKw = Number(get(REFS.leistung)) || 0;
|
|
132
|
+
// Guy-wire bracing: required above 3 m height-above-last-fixing per
|
|
133
|
+
// EN 1856. Draw 3 anchor wires fanning out from the above-roof pipe.
|
|
134
|
+
const bracingNeeded = Number(get(REFS.hoeheUeberBefestigung)) > 2999;
|
|
135
|
+
// Zugbegrenzer opt-in shows a small valve icon on the lower pipe.
|
|
136
|
+
const zugbegrenzerActive = get(REFS.zugbegrenzer) === 'true';
|
|
137
|
+
|
|
138
|
+
// Bauhöhe (mm) → m for display; stackRun px mapped 3–25m into 120–340px.
|
|
139
|
+
const bauhoeheMm = Number(get(REFS.bauhoehe)) || 5000;
|
|
140
|
+
const h = Math.max(3, Math.min(25, bauhoeheMm / 1000));
|
|
141
|
+
const stackRun = 120 + (h - 3) * 10;
|
|
142
|
+
|
|
143
|
+
// Höhe über letzter Befestigung (mm) → m for display; udRun px mapped
|
|
144
|
+
// 0.4–3m into 30–87px.
|
|
145
|
+
const hoeheMm = Number(get(REFS.hoeheUeberBefestigung)) || 1000;
|
|
146
|
+
const ueberdach = Math.max(0.4, Math.min(3, hoeheMm / 1000));
|
|
147
|
+
const udRun = 30 + (ueberdach - 0.4) * 22;
|
|
148
|
+
|
|
149
|
+
// Dachneigung (°) clamped 0–55 for viewport fit. Don't use `|| 35` —
|
|
150
|
+
// `0` (Flachdach) is a valid input and shouldn't fall back.
|
|
151
|
+
const dachneigungParsed = Number(get(REFS.dachneigung, '35'));
|
|
152
|
+
const dachneigung = Math.max(
|
|
153
|
+
0,
|
|
154
|
+
Math.min(55, Number.isFinite(dachneigungParsed) ? dachneigungParsed : 35),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
const stroke = '#d6d3d1';
|
|
158
|
+
const sub = '#78716c';
|
|
159
|
+
const accent = '#e7e5e4';
|
|
160
|
+
|
|
161
|
+
// Layout anchors — baseY grows with stack height so the schematic fills
|
|
162
|
+
// the container at any height instead of clumping at the bottom of a
|
|
163
|
+
// fixed-size canvas. `vbH` (viewBox height) tracks this so the SVG
|
|
164
|
+
// scales naturally.
|
|
165
|
+
const cx = 240;
|
|
166
|
+
// 120 px of head-room keeps the ABSCHLUSS callout clear of the title
|
|
167
|
+
// strip (which occupies y≤40).
|
|
168
|
+
const mouthY = 120;
|
|
169
|
+
const roofY = mouthY + udRun;
|
|
170
|
+
const baseY = roofY + stackRun;
|
|
171
|
+
const vbH = baseY + 80;
|
|
172
|
+
|
|
173
|
+
// Wall bracket count is read from the LIVE BOM so the drawing can
|
|
174
|
+
// never drift from the actual parts list. Falls back to a conservative
|
|
175
|
+
// estimate if the evaluation hasn't returned yet.
|
|
176
|
+
const wallBracketLine = evaluation?.lines.find(
|
|
177
|
+
l => l.productVariant.facetValues?.some(
|
|
178
|
+
fv => fv.facet?.code === 'classification' && fv.code === 'wallBracket',
|
|
179
|
+
),
|
|
180
|
+
);
|
|
181
|
+
const konsolenCount = Math.max(
|
|
182
|
+
1,
|
|
183
|
+
wallBracketLine?.quantity ?? Math.ceil(h / 4) + 1,
|
|
184
|
+
);
|
|
185
|
+
const konsolenTopY = roofY + 10;
|
|
186
|
+
const konsolenSpan = stackRun - 90;
|
|
187
|
+
|
|
188
|
+
const calloutText: CSSProperties = { fontFamily: "'JetBrains Mono', monospace", fontSize: '9px', letterSpacing: '0.04em' };
|
|
189
|
+
const calloutVal: CSSProperties = { fontFamily: "'JetBrains Mono', monospace", fontSize: '11px', fontWeight: 500 };
|
|
190
|
+
|
|
191
|
+
const abschlussLabel = isPending ? '—' : isAbstrom ? 'Abstromkonus' : 'Regenhaube';
|
|
192
|
+
const tWinkelLabel = tWinkel === '45-einlauf' ? '45° Einlauf' : `${tWinkel}°`;
|
|
193
|
+
|
|
194
|
+
return (
|
|
195
|
+
<svg
|
|
196
|
+
viewBox={`0 0 480 ${vbH}`}
|
|
197
|
+
preserveAspectRatio="xMidYMin meet"
|
|
198
|
+
className="w-full h-full"
|
|
199
|
+
style={{ fontFamily: "'JetBrains Mono', monospace" }}
|
|
200
|
+
>
|
|
201
|
+
<defs>
|
|
202
|
+
<pattern id="kp-hatch" patternUnits="userSpaceOnUse" width="6" height="6" patternTransform="rotate(45)">
|
|
203
|
+
<line x1="0" y1="0" x2="0" y2="6" stroke={sub} strokeWidth="0.7" />
|
|
204
|
+
</pattern>
|
|
205
|
+
<pattern id="kp-brick" patternUnits="userSpaceOnUse" width="16" height="8">
|
|
206
|
+
<rect width="16" height="8" fill="none" />
|
|
207
|
+
<path d="M0 4 H16 M8 0 V4 M0 8 V4 M16 8 V4" stroke={sub} strokeWidth="0.4" />
|
|
208
|
+
</pattern>
|
|
209
|
+
</defs>
|
|
210
|
+
|
|
211
|
+
{/* Title strip */}
|
|
212
|
+
<g>
|
|
213
|
+
<text x="18" y="24" fill={accent} fontSize="11" fontWeight="600">DWG · {dwgLabel} · AXO</text>
|
|
214
|
+
<text x="18" y="38" fill={sub} fontSize="9">REV 04 · 21.04.2026 · M 1:20</text>
|
|
215
|
+
<text x="462" y="24" fill={sub} fontSize="9" textAnchor="end">DN {dnValue || '—'}</text>
|
|
216
|
+
<text x="462" y="38" fill={sub} fontSize="9" textAnchor="end">{brennstoffLabel}</text>
|
|
217
|
+
</g>
|
|
218
|
+
|
|
219
|
+
{/* Corner tick marks */}
|
|
220
|
+
{([[12, 12], [468, 12], [12, vbH - 12], [468, vbH - 12]] as const).map(([x, y], i) => (
|
|
221
|
+
<g key={i} stroke={sub} strokeWidth="0.7" fill="none">
|
|
222
|
+
<line x1={x - 6} y1={y} x2={x + 6} y2={y} />
|
|
223
|
+
<line x1={x} y1={y - 6} x2={x} y2={y + 6} />
|
|
224
|
+
</g>
|
|
225
|
+
))}
|
|
226
|
+
|
|
227
|
+
{/* Ground */}
|
|
228
|
+
<g>
|
|
229
|
+
<line x1="18" y1={baseY} x2="462" y2={baseY} stroke={stroke} strokeWidth="1" />
|
|
230
|
+
{Array.from({ length: 28 }).map((_, i) => (
|
|
231
|
+
<line key={i} x1={20 + i * 16} y1={baseY} x2={12 + i * 16} y2={baseY + 10} stroke={sub} strokeWidth="0.7" />
|
|
232
|
+
))}
|
|
233
|
+
<text x="22" y={baseY + 24} fill={sub} fontSize="8">OKFB ±0,000</text>
|
|
234
|
+
</g>
|
|
235
|
+
|
|
236
|
+
{/* Building envelope —
|
|
237
|
+
Interior: chimney rises through a narrow masonry shaft
|
|
238
|
+
inside the house, with a pitched roof (angle driven by
|
|
239
|
+
`dachdurchfuehrung.dachneigung`). Shaft pierces the roof
|
|
240
|
+
with a flashing collar.
|
|
241
|
+
Exterior: single facade wall to the left of the pipe, no
|
|
242
|
+
roof drawn (the pipe runs up the outside of the building). */}
|
|
243
|
+
{/* Building envelope — shaft walls, roof band, flashing collar,
|
|
244
|
+
exterior facade. No flash: the envelope is structural context,
|
|
245
|
+
not a driven response to a field change. */}
|
|
246
|
+
<g>
|
|
247
|
+
{!montageAussen ? (
|
|
248
|
+
(() => {
|
|
249
|
+
const slope = Math.tan((dachneigung * Math.PI) / 180);
|
|
250
|
+
// Roof extends 110 px each side of shaft center.
|
|
251
|
+
const roofHalfW = 110;
|
|
252
|
+
const roofLX = cx - roofHalfW;
|
|
253
|
+
const roofRX = cx + roofHalfW;
|
|
254
|
+
const rise = slope * roofHalfW;
|
|
255
|
+
// Pitched up to the right (common convention); shaft
|
|
256
|
+
// pierces the midpoint of the roof at y=roofY.
|
|
257
|
+
const roofLY = roofY + rise; // lower (far-left eave)
|
|
258
|
+
const roofRY = roofY - rise; // upper (far-right ridge direction)
|
|
259
|
+
const roofThickness = 18;
|
|
260
|
+
// Shaft walls: two brick rects hugging the chimney with
|
|
261
|
+
// an ~15 px air gap each side. A masonry shaft terminates
|
|
262
|
+
// at the roof — only the insulated steel pipe continues
|
|
263
|
+
// above into the Über-Dach section. Top the walls a few
|
|
264
|
+
// pixels into the roof band for a clean pierce.
|
|
265
|
+
const shaftLX = cx - 35;
|
|
266
|
+
const shaftRX = cx + 15;
|
|
267
|
+
const shaftWallW = 20;
|
|
268
|
+
const shaftTopY = roofY + 2;
|
|
269
|
+
return (
|
|
270
|
+
<g>
|
|
271
|
+
{/* Left shaft wall */}
|
|
272
|
+
<rect
|
|
273
|
+
x={shaftLX} y={shaftTopY}
|
|
274
|
+
width={shaftWallW} height={baseY - shaftTopY}
|
|
275
|
+
fill="url(#kp-brick)" stroke={stroke} strokeWidth="0.8"
|
|
276
|
+
/>
|
|
277
|
+
{/* Right shaft wall */}
|
|
278
|
+
<rect
|
|
279
|
+
x={shaftRX} y={shaftTopY}
|
|
280
|
+
width={shaftWallW} height={baseY - shaftTopY}
|
|
281
|
+
fill="url(#kp-brick)" stroke={stroke} strokeWidth="0.8"
|
|
282
|
+
/>
|
|
283
|
+
{/* Pitched roof band */}
|
|
284
|
+
<path
|
|
285
|
+
d={`M ${roofLX} ${roofLY} L ${roofRX} ${roofRY} L ${roofRX} ${roofRY - roofThickness} L ${roofLX} ${roofLY - roofThickness} Z`}
|
|
286
|
+
fill="url(#kp-hatch)" stroke={stroke} strokeWidth="0.9"
|
|
287
|
+
/>
|
|
288
|
+
{/* Flashing collar at the shaft-roof intersection
|
|
289
|
+
(over the roof band, under the pipe). A little
|
|
290
|
+
trapezoid that sits perpendicular to the roof
|
|
291
|
+
slope at the shaft. */}
|
|
292
|
+
<rect
|
|
293
|
+
x={cx - 22}
|
|
294
|
+
y={roofY - 5}
|
|
295
|
+
width={44}
|
|
296
|
+
height={10}
|
|
297
|
+
fill="#2a2522" stroke={stroke} strokeWidth="1"
|
|
298
|
+
transform={`rotate(${-dachneigung} ${cx} ${roofY})`}
|
|
299
|
+
/>
|
|
300
|
+
</g>
|
|
301
|
+
);
|
|
302
|
+
})()
|
|
303
|
+
) : (
|
|
304
|
+
<g>
|
|
305
|
+
{/* External facade mount layout (left → right):
|
|
306
|
+
- Interior building volume (Kessel sits inside, drawn
|
|
307
|
+
by the stack group below)
|
|
308
|
+
- Exterior wall — thin vertical band between Kessel
|
|
309
|
+
and the pipe. The Kessel's short horizontal stub
|
|
310
|
+
passes THROUGH this wall (it's the only pipe that
|
|
311
|
+
crosses the building envelope).
|
|
312
|
+
- Eave overhang sloping up-right from the wall top
|
|
313
|
+
toward the pipe.
|
|
314
|
+
- Chimney pipe runs up the OUTSIDE of the wall with
|
|
315
|
+
brackets; terminates above the eave. */}
|
|
316
|
+
<rect
|
|
317
|
+
x={200}
|
|
318
|
+
y={roofY}
|
|
319
|
+
width={20}
|
|
320
|
+
height={baseY - roofY}
|
|
321
|
+
fill="url(#kp-brick)" stroke={stroke} strokeWidth="0.8"
|
|
322
|
+
/>
|
|
323
|
+
{/* Eave overhang — slopes up-right at ~22°, stops before
|
|
324
|
+
the pipe so the pipe visibly clears the eave. */}
|
|
325
|
+
<path
|
|
326
|
+
d={`M 220 ${roofY + 5} L 228 ${roofY - 11} L 228 ${roofY - 3} L 220 ${roofY + 13} Z`}
|
|
327
|
+
fill="url(#kp-hatch)" stroke={stroke} strokeWidth="0.9"
|
|
328
|
+
/>
|
|
329
|
+
{/* Dashed clearance line between eave tip and pipe. */}
|
|
330
|
+
<line x1={228} y1={roofY - 5} x2={cx - 10} y2={roofY - 5} stroke={sub} strokeWidth="0.5" strokeDasharray="2 2" />
|
|
331
|
+
</g>
|
|
332
|
+
)}
|
|
333
|
+
</g>
|
|
334
|
+
|
|
335
|
+
{/* Annotation overlay — rendered as a sibling of the envelope so
|
|
336
|
+
layout order places it above the roof without affecting the
|
|
337
|
+
envelope's own grouping. Text never goes in a flash wrapper
|
|
338
|
+
(drop-shadow outlines look awful on glyphs). */}
|
|
339
|
+
{!montageAussen ? (
|
|
340
|
+
(() => {
|
|
341
|
+
const slope = Math.tan((dachneigung * Math.PI) / 180);
|
|
342
|
+
const roofHalfW = 110;
|
|
343
|
+
const roofRX = cx + roofHalfW;
|
|
344
|
+
const roofRY = roofY - slope * roofHalfW;
|
|
345
|
+
return (
|
|
346
|
+
<text x={roofRX + 4} y={roofRY - 22} fill={sub} fontSize="8">
|
|
347
|
+
{dachneigung.toFixed(0)}°
|
|
348
|
+
</text>
|
|
349
|
+
);
|
|
350
|
+
})()
|
|
351
|
+
) : (
|
|
352
|
+
<>
|
|
353
|
+
<text x={100} y={roofY - 12} fill={sub} fontSize="9" style={{ letterSpacing: '0.08em' }}>INNEN</text>
|
|
354
|
+
<text x={260} y={roofY - 12} fill={sub} fontSize="9" style={{ letterSpacing: '0.08em' }}>AUSSEN</text>
|
|
355
|
+
</>
|
|
356
|
+
)}
|
|
357
|
+
|
|
358
|
+
{/* Stack */}
|
|
359
|
+
<g>
|
|
360
|
+
{/* Mouth / termination — flashes when kaminabschluss changes.
|
|
361
|
+
Text labels are rendered outside as non-flashing siblings. */}
|
|
362
|
+
<g className={flashClass(REFS.kaminabschluss)}>
|
|
363
|
+
{isPending ? (
|
|
364
|
+
<g>
|
|
365
|
+
{/* Dashed open-top placeholder — a constrain rule
|
|
366
|
+
cleared the terminal and is waiting for the user
|
|
367
|
+
to pick a new one. */}
|
|
368
|
+
<line x1={cx - 10} y1={mouthY} x2={cx - 10} y2={mouthY - 14} stroke={sub} strokeWidth="0.9" strokeDasharray="3 2" />
|
|
369
|
+
<line x1={cx + 10} y1={mouthY} x2={cx + 10} y2={mouthY - 14} stroke={sub} strokeWidth="0.9" strokeDasharray="3 2" />
|
|
370
|
+
</g>
|
|
371
|
+
) : isAbstrom ? (
|
|
372
|
+
<g>
|
|
373
|
+
<path
|
|
374
|
+
d={`M ${cx - 14} ${mouthY} L ${cx + 14} ${mouthY} L ${cx + 6} ${mouthY - 18} L ${cx - 6} ${mouthY - 18} Z`}
|
|
375
|
+
fill="#2a2522" stroke={stroke} strokeWidth="1"
|
|
376
|
+
/>
|
|
377
|
+
<path d={`M ${cx - 6} ${mouthY - 18} L ${cx + 6} ${mouthY - 18}`} stroke={stroke} strokeWidth="1" />
|
|
378
|
+
</g>
|
|
379
|
+
) : (
|
|
380
|
+
<g>
|
|
381
|
+
<rect x={cx - 20} y={mouthY - 10} width="40" height="4" fill="#2a2522" stroke={stroke} strokeWidth="1" />
|
|
382
|
+
<line x1={cx - 14} y1={mouthY - 6} x2={cx - 14} y2={mouthY} stroke={stroke} strokeWidth="1" />
|
|
383
|
+
<line x1={cx + 14} y1={mouthY - 6} x2={cx + 14} y2={mouthY} stroke={stroke} strokeWidth="1" />
|
|
384
|
+
<line x1={cx - 8} y1={mouthY - 6} x2={cx - 8} y2={mouthY} stroke={stroke} strokeWidth="0.8" />
|
|
385
|
+
<line x1={cx + 8} y1={mouthY - 6} x2={cx + 8} y2={mouthY} stroke={stroke} strokeWidth="0.8" />
|
|
386
|
+
</g>
|
|
387
|
+
)}
|
|
388
|
+
|
|
389
|
+
</g>
|
|
390
|
+
|
|
391
|
+
{/* ABSCHLUSS? placeholder text — non-flashing sibling, only
|
|
392
|
+
rendered when the terminal is pending. */}
|
|
393
|
+
{isPending && (
|
|
394
|
+
<text x={cx} y={mouthY - 22} fill={sub} fontSize="8" textAnchor="middle">ABSCHLUSS?</text>
|
|
395
|
+
)}
|
|
396
|
+
|
|
397
|
+
{/* Über-Dach section — flashes when hoeheUeberBefestigung changes. */}
|
|
398
|
+
<g className={flashClass(REFS.hoeheUeberBefestigung)}>
|
|
399
|
+
<rect x={cx - 10} y={mouthY} width="20" height={roofY - mouthY} fill="#1c1917" stroke={stroke} strokeWidth="1" />
|
|
400
|
+
<line x1={cx - 6} y1={mouthY + 2} x2={cx - 6} y2={roofY} stroke={sub} strokeWidth="0.6" />
|
|
401
|
+
<line x1={cx + 6} y1={mouthY + 2} x2={cx + 6} y2={roofY} stroke={sub} strokeWidth="0.6" />
|
|
402
|
+
</g>
|
|
403
|
+
|
|
404
|
+
{/* Main stack — flashes when bauhoehe changes. */}
|
|
405
|
+
<g className={flashClass(REFS.bauhoehe)}>
|
|
406
|
+
<rect x={cx - 10} y={roofY} width="20" height={stackRun - 60} fill="#1c1917" stroke={stroke} strokeWidth="1" />
|
|
407
|
+
<line x1={cx - 6} y1={roofY + 2} x2={cx - 6} y2={roofY + stackRun - 60} stroke={sub} strokeWidth="0.6" />
|
|
408
|
+
<line x1={cx + 6} y1={roofY + 2} x2={cx + 6} y2={roofY + stackRun - 60} stroke={sub} strokeWidth="0.6" />
|
|
409
|
+
</g>
|
|
410
|
+
|
|
411
|
+
{/* Wandkonsolen — ~ every 4 m. Attach from inner shaft
|
|
412
|
+
wall (interior) or from the exterior facade (exterior)
|
|
413
|
+
to the pipe left edge. Flashes when bauhoehe (count)
|
|
414
|
+
or aussenmontage (attachment face) changes. */}
|
|
415
|
+
<g className={flashClass(REFS.bauhoehe, REFS.aussenmontage)}>
|
|
416
|
+
{(() => {
|
|
417
|
+
const bracketLeftX = montageAussen ? 220 : cx - 15;
|
|
418
|
+
return Array.from({ length: konsolenCount }).map((_, i) => {
|
|
419
|
+
const y = konsolenTopY + (i + 1) * (konsolenSpan / (konsolenCount + 1));
|
|
420
|
+
return (
|
|
421
|
+
<g key={i}>
|
|
422
|
+
<line x1={bracketLeftX} y1={y} x2={cx - 10} y2={y} stroke={stroke} strokeWidth="0.9" />
|
|
423
|
+
<circle cx={cx - 10} cy={y} r="2" fill={stroke} />
|
|
424
|
+
<circle cx={bracketLeftX} cy={y} r="1.5" fill={stroke} />
|
|
425
|
+
</g>
|
|
426
|
+
);
|
|
427
|
+
});
|
|
428
|
+
})()}
|
|
429
|
+
</g>
|
|
430
|
+
|
|
431
|
+
{/* T-Stück — geometry by angle. 45°-Einlauf = standard
|
|
432
|
+
horizontal T-piece stub plus two 45° bends and a short
|
|
433
|
+
diagonal run into a lower-offset Kessel. 87° = industry-
|
|
434
|
+
standard nearly-horizontal inlet (slight upward slope).
|
|
435
|
+
90° = pure horizontal. */}
|
|
436
|
+
{(() => {
|
|
437
|
+
const tY = baseY - 60;
|
|
438
|
+
if (tWinkel === '45-einlauf') {
|
|
439
|
+
// Dog-leg at the same visual weight as the 87°/90°
|
|
440
|
+
// stub+Kessel but with a 45° drop between the T-piece
|
|
441
|
+
// and the Kessel. Mirrors when aussenmontage=true so
|
|
442
|
+
// the Kessel sits INSIDE the building (left of pipe).
|
|
443
|
+
const stubTop = tY + 8;
|
|
444
|
+
const pipeW = 22;
|
|
445
|
+
const stubDir = montageAussen ? -1 : 1;
|
|
446
|
+
const pipeEdgeX = cx + stubDir * 10; // vertical-pipe side wall
|
|
447
|
+
const stubEndX = cx + stubDir * 18; // end of horiz stub
|
|
448
|
+
const jogEndX = stubEndX + stubDir * pipeW; // after 45° drop
|
|
449
|
+
const lowerPipeY = stubTop + pipeW;
|
|
450
|
+
const kesselInnerX = cx + stubDir * 54; // pipe-side face of Kessel
|
|
451
|
+
const kesselOuterX = cx + stubDir * 90; // far side (36 px box)
|
|
452
|
+
const stubRectX = Math.min(pipeEdgeX, stubEndX);
|
|
453
|
+
const stubRectW = Math.abs(stubEndX - pipeEdgeX);
|
|
454
|
+
const lowerRectX = Math.min(jogEndX, kesselInnerX);
|
|
455
|
+
const lowerRectW = Math.abs(kesselInnerX - jogEndX);
|
|
456
|
+
const kesselRectX = Math.min(kesselInnerX, kesselOuterX);
|
|
457
|
+
const kesselCenterX = (kesselInnerX + kesselOuterX) / 2;
|
|
458
|
+
const labelAnchor = stubDir > 0 ? 'start' : 'end';
|
|
459
|
+
return (
|
|
460
|
+
<>
|
|
461
|
+
<g className={flashClass(REFS.tWinkel, REFS.aussenmontage)}>
|
|
462
|
+
{/* Vertical T-piece shaft (continuous with main stack). */}
|
|
463
|
+
<rect x={cx - 10} y={tY} width="20" height="56" fill="#1c1917" stroke={stroke} strokeWidth="1" />
|
|
464
|
+
<line x1={cx - 6} y1={tY + 2} x2={cx - 6} y2={tY + 54} stroke={sub} strokeWidth="0.6" />
|
|
465
|
+
<line x1={cx + 6} y1={tY + 2} x2={cx + 6} y2={tY + 54} stroke={sub} strokeWidth="0.6" />
|
|
466
|
+
|
|
467
|
+
{/* Horizontal stub out of T-piece (same thickness as 87°/90°) */}
|
|
468
|
+
<rect x={stubRectX} y={stubTop} width={stubRectW} height={pipeW} fill="#1c1917" stroke={stroke} strokeWidth="1" />
|
|
469
|
+
<line x1={pipeEdgeX} y1={stubTop + 6} x2={stubEndX} y2={stubTop + 6} stroke={sub} strokeWidth="0.6" />
|
|
470
|
+
<line x1={pipeEdgeX} y1={stubTop + 16} x2={stubEndX} y2={stubTop + 16} stroke={sub} strokeWidth="0.6" />
|
|
471
|
+
|
|
472
|
+
{/* 45° diagonal pipe (parallelogram, drops by pipeW) */}
|
|
473
|
+
<path
|
|
474
|
+
d={`M ${stubEndX} ${stubTop} L ${jogEndX} ${stubTop + pipeW} L ${jogEndX} ${stubTop + pipeW * 2} L ${stubEndX} ${stubTop + pipeW} Z`}
|
|
475
|
+
fill="#1c1917" stroke={stroke} strokeWidth="1"
|
|
476
|
+
/>
|
|
477
|
+
|
|
478
|
+
{/* Horizontal pipe into Kessel (at the lower jog level) */}
|
|
479
|
+
<rect x={lowerRectX} y={lowerPipeY} width={lowerRectW} height={pipeW} fill="#1c1917" stroke={stroke} strokeWidth="1" />
|
|
480
|
+
<line x1={jogEndX} y1={lowerPipeY + 6} x2={kesselInnerX} y2={lowerPipeY + 6} stroke={sub} strokeWidth="0.6" />
|
|
481
|
+
<line x1={jogEndX} y1={lowerPipeY + 16} x2={kesselInnerX} y2={lowerPipeY + 16} stroke={sub} strokeWidth="0.6" />
|
|
482
|
+
|
|
483
|
+
{/* Kessel (same 36×30 hatched box as 87°/90°, just dropped by pipeW) */}
|
|
484
|
+
<rect x={kesselRectX} y={lowerPipeY - 4} width="36" height="30" fill="url(#kp-hatch)" stroke={stroke} strokeWidth="0.8" />
|
|
485
|
+
</g>
|
|
486
|
+
{/* Non-flashing text siblings. */}
|
|
487
|
+
<text x={stubEndX + stubDir * 3} y={stubTop - 3} fill={sub} fontSize="8" textAnchor={labelAnchor}>45°</text>
|
|
488
|
+
<text x={jogEndX + stubDir * 3} y={lowerPipeY + pipeW + 9} fill={sub} fontSize="8" textAnchor={labelAnchor}>45°</text>
|
|
489
|
+
<text x={kesselCenterX} y={lowerPipeY + pipeW / 2} fill={sub} fontSize="8" textAnchor="middle">KESSEL</text>
|
|
490
|
+
{leistungKw > 0 && (
|
|
491
|
+
<text x={kesselCenterX} y={lowerPipeY + pipeW / 2 + 12} fill={accent} fontSize="7" textAnchor="middle" style={{ fontFamily: "'JetBrains Mono', monospace" }}>
|
|
492
|
+
{leistungKw} kW
|
|
493
|
+
</text>
|
|
494
|
+
)}
|
|
495
|
+
</>
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
// 87° slopes the inlet upward by 3 px (~3° offset from
|
|
499
|
+
// 90°). Geometrically subtle but visually distinct.
|
|
500
|
+
const slope = tWinkel === '87' ? 3 : 0;
|
|
501
|
+
// Exterior mount: Kessel is inside the building (LEFT
|
|
502
|
+
// of the wall), so the T-piece stub and Kessel box
|
|
503
|
+
// mirror to the left of the pipe. The stub crosses the
|
|
504
|
+
// exterior wall to reach the Kessel.
|
|
505
|
+
const stubDir = montageAussen ? -1 : 1;
|
|
506
|
+
const pipeEdgeX = cx + stubDir * 10;
|
|
507
|
+
const kesselInnerX = cx + stubDir * 48; // pipe-side face of Kessel
|
|
508
|
+
const kesselOuterX = cx + stubDir * 84; // far side of Kessel
|
|
509
|
+
const kesselRectX = Math.min(kesselInnerX, kesselOuterX);
|
|
510
|
+
const kesselCenterX = (kesselInnerX + kesselOuterX) / 2;
|
|
511
|
+
return (
|
|
512
|
+
<>
|
|
513
|
+
<g className={flashClass(REFS.tWinkel, REFS.aussenmontage)}>
|
|
514
|
+
<rect x={cx - 10} y={tY} width="20" height="56" fill="#1c1917" stroke={stroke} strokeWidth="1" />
|
|
515
|
+
<path
|
|
516
|
+
d={`M ${pipeEdgeX} ${tY + 8} L ${kesselInnerX} ${tY + 8 - slope} L ${kesselInnerX} ${tY + 30 - slope} L ${pipeEdgeX} ${tY + 30}`}
|
|
517
|
+
fill="#1c1917" stroke={stroke} strokeWidth="1"
|
|
518
|
+
/>
|
|
519
|
+
<line x1={pipeEdgeX} y1={tY + 14} x2={kesselInnerX} y2={tY + 14 - slope} stroke={sub} strokeWidth="0.6" />
|
|
520
|
+
<line x1={pipeEdgeX} y1={tY + 24} x2={kesselInnerX} y2={tY + 24 - slope} stroke={sub} strokeWidth="0.6" />
|
|
521
|
+
<rect x={kesselRectX} y={tY + 4 - slope} width="36" height="30" fill="url(#kp-hatch)" stroke={stroke} strokeWidth="0.8" />
|
|
522
|
+
</g>
|
|
523
|
+
{/* Non-flashing text siblings. */}
|
|
524
|
+
<text x={kesselCenterX} y={tY + 18 - slope} fill={sub} fontSize="8" textAnchor="middle">KESSEL</text>
|
|
525
|
+
{leistungKw > 0 && (
|
|
526
|
+
<text x={kesselCenterX} y={tY + 30 - slope} fill={accent} fontSize="7" textAnchor="middle" style={{ fontFamily: "'JetBrains Mono', monospace" }}>
|
|
527
|
+
{leistungKw} kW
|
|
528
|
+
</text>
|
|
529
|
+
)}
|
|
530
|
+
</>
|
|
531
|
+
);
|
|
532
|
+
})()}
|
|
533
|
+
|
|
534
|
+
{/* Fußteil — only if Reinigung unten. Cleaning door on
|
|
535
|
+
the left face (the access hatch a sweep uses). */}
|
|
536
|
+
{reinigung === 'unten' && (
|
|
537
|
+
<g className={flashClass(REFS.reinigung)}>
|
|
538
|
+
<rect x={cx - 14} y={baseY - 10} width="28" height="12" fill="#2a2522" stroke={stroke} strokeWidth="1" />
|
|
539
|
+
{/* Cleaning-door outline */}
|
|
540
|
+
<rect x={cx - 12} y={baseY - 8} width="6" height="8" fill="#1c1917" stroke={stroke} strokeWidth="0.6" />
|
|
541
|
+
{/* Door hinge marker on the left */}
|
|
542
|
+
<line x1={cx - 12} y1={baseY - 6} x2={cx - 11} y2={baseY - 6} stroke={stroke} strokeWidth="0.4" />
|
|
543
|
+
<line x1={cx - 12} y1={baseY - 3} x2={cx - 11} y2={baseY - 3} stroke={stroke} strokeWidth="0.4" />
|
|
544
|
+
{/* Door handle dot on the right edge */}
|
|
545
|
+
<circle cx={cx - 7} cy={baseY - 4} r="0.6" fill={stroke} />
|
|
546
|
+
{/* Condensate drain spigot on the bottom */}
|
|
547
|
+
<rect x={cx - 3} y={baseY + 2} width="6" height="3" fill="#1c1917" stroke={stroke} strokeWidth="0.5" />
|
|
548
|
+
</g>
|
|
549
|
+
)}
|
|
550
|
+
|
|
551
|
+
{/* Flow-direction arrows along the stack. Solid triangles
|
|
552
|
+
for Überdruck (pushed gases), hollow triangles for
|
|
553
|
+
Unterdruck (natural draft). 3 arrows spaced evenly. */}
|
|
554
|
+
<g className={flashClass(REFS.brennstoff)}>
|
|
555
|
+
{(() => {
|
|
556
|
+
const tStuckY = baseY - 60;
|
|
557
|
+
const arrowSpacing = (tStuckY - roofY) / 4;
|
|
558
|
+
return Array.from({ length: 3 }).map((_, i) => {
|
|
559
|
+
const y = roofY + arrowSpacing * (i + 1);
|
|
560
|
+
const x = cx + 18;
|
|
561
|
+
const shape = `M ${x} ${y} L ${x - 3} ${y + 5} L ${x + 3} ${y + 5} Z`;
|
|
562
|
+
return (
|
|
563
|
+
<path
|
|
564
|
+
key={`flow-${i}`}
|
|
565
|
+
d={shape}
|
|
566
|
+
fill={isUeberdruck ? stroke : 'none'}
|
|
567
|
+
stroke={stroke}
|
|
568
|
+
strokeWidth="0.7"
|
|
569
|
+
/>
|
|
570
|
+
);
|
|
571
|
+
});
|
|
572
|
+
})()}
|
|
573
|
+
</g>
|
|
574
|
+
|
|
575
|
+
{/* Guy-wire bracing — fans out from the above-roof pipe
|
|
576
|
+
when hoeheUeberBefestigung > 3 m per EN 1856. Three
|
|
577
|
+
wires anchored at the roof at 45°/90°/135° from the
|
|
578
|
+
pipe top. */}
|
|
579
|
+
{bracingNeeded && (
|
|
580
|
+
<>
|
|
581
|
+
<g className={flashClass(REFS.hoeheUeberBefestigung)} stroke={stroke} strokeWidth="0.6" strokeDasharray="3 2">
|
|
582
|
+
<line x1={cx} y1={mouthY + 20} x2={cx - 50} y2={roofY + 4} />
|
|
583
|
+
<line x1={cx} y1={mouthY + 20} x2={cx + 50} y2={roofY + 4} />
|
|
584
|
+
<line x1={cx} y1={mouthY + 20} x2={cx} y2={roofY + 4} />
|
|
585
|
+
{/* Anchor collar at the bracing point */}
|
|
586
|
+
<circle cx={cx} cy={mouthY + 20} r="2.5" fill="#2a2522" stroke={stroke} strokeWidth="0.6" />
|
|
587
|
+
</g>
|
|
588
|
+
{/* Non-flashing label sibling. */}
|
|
589
|
+
<text x={cx + 58} y={(mouthY + roofY) / 2 + 4} fill={sub} fontSize="7">3-Punkt-Abspannung</text>
|
|
590
|
+
</>
|
|
591
|
+
)}
|
|
592
|
+
|
|
593
|
+
{/* Zugbegrenzer — small valve icon on the lower pipe
|
|
594
|
+
below the T-piece when the installer opts in. */}
|
|
595
|
+
{zugbegrenzerActive && (
|
|
596
|
+
<>
|
|
597
|
+
<g className={flashClass(REFS.zugbegrenzer)} transform={`translate(${cx + 16} ${baseY - 28})`}>
|
|
598
|
+
<line x1={-6} y1={0} x2={0} y2={0} stroke={stroke} strokeWidth="0.8" />
|
|
599
|
+
<circle r="5" fill="#2a2522" stroke={stroke} strokeWidth="0.9" />
|
|
600
|
+
<line x1={-3.5} y1={0} x2={3.5} y2={0} stroke={stroke} strokeWidth="0.8" />
|
|
601
|
+
</g>
|
|
602
|
+
{/* Non-flashing label sibling — absolute-positioned equivalent
|
|
603
|
+
of x=10, y=3 inside the translated group. */}
|
|
604
|
+
<text x={cx + 26} y={baseY - 25} fill={sub} fontSize="7">Zugbegrenzer</text>
|
|
605
|
+
</>
|
|
606
|
+
)}
|
|
607
|
+
|
|
608
|
+
{/* Sicherheitsabstand — dashed "safety clearance" box around
|
|
609
|
+
the vertical stack, annotating the 100 mm clear-of-
|
|
610
|
+
combustibles requirement per ÖNORM B 8200. */}
|
|
611
|
+
<g stroke={sub} strokeWidth="0.5" strokeDasharray="3 2" fill="none">
|
|
612
|
+
<rect x={cx - 18} y={mouthY - 4} width="36" height={baseY - mouthY + 2} />
|
|
613
|
+
</g>
|
|
614
|
+
<text x={cx - 22} y={(mouthY + baseY) / 2 + 28} fill={sub} fontSize="7" textAnchor="end" style={{ letterSpacing: '0.04em' }}>
|
|
615
|
+
100 mm Abstand zu
|
|
616
|
+
</text>
|
|
617
|
+
<text x={cx - 22} y={(mouthY + baseY) / 2 + 38} fill={sub} fontSize="7" textAnchor="end" style={{ letterSpacing: '0.04em' }}>
|
|
618
|
+
brennbarem Material
|
|
619
|
+
</text>
|
|
620
|
+
</g>
|
|
621
|
+
|
|
622
|
+
{/* Callouts */}
|
|
623
|
+
<g fill={sub}>
|
|
624
|
+
{/* Mündung über First */}
|
|
625
|
+
<line x1={cx + 30} y1={mouthY - 4} x2={410} y2={mouthY - 4} stroke={sub} strokeWidth="0.5" strokeDasharray="2 2" />
|
|
626
|
+
<line x1={cx + 30} y1={roofY - 4} x2={410} y2={roofY - 4} stroke={sub} strokeWidth="0.5" strokeDasharray="2 2" />
|
|
627
|
+
<line x1={410} y1={mouthY - 4} x2={410} y2={roofY - 4} stroke={sub} strokeWidth="0.6" />
|
|
628
|
+
<text x="416" y={(mouthY + roofY) / 2 - 8} style={calloutText}>ÜBER DACH</text>
|
|
629
|
+
<text x="416" y={(mouthY + roofY) / 2 + 4} style={calloutVal} fill={accent}>{ueberdach.toFixed(1)} m</text>
|
|
630
|
+
|
|
631
|
+
{/* Bauhöhe gesamt */}
|
|
632
|
+
<line x1={cx - 20} y1={roofY + 10} x2={70} y2={roofY + 10} stroke={sub} strokeWidth="0.5" strokeDasharray="2 2" />
|
|
633
|
+
<line x1={cx - 20} y1={baseY - 10} x2={70} y2={baseY - 10} stroke={sub} strokeWidth="0.5" strokeDasharray="2 2" />
|
|
634
|
+
<line x1={70} y1={roofY + 10} x2={70} y2={baseY - 10} stroke={sub} strokeWidth="0.6" />
|
|
635
|
+
<text x="22" y={(roofY + baseY) / 2 - 4} style={calloutText}>BAUHÖHE</text>
|
|
636
|
+
<text x="22" y={(roofY + baseY) / 2 + 10} style={calloutVal} fill={accent}>{h.toFixed(1)} m</text>
|
|
637
|
+
|
|
638
|
+
{/* DN */}
|
|
639
|
+
<line x1={cx + 10} y1={roofY + 40} x2={cx + 78} y2={roofY + 40} stroke={sub} strokeWidth="0.5" strokeDasharray="2 2" />
|
|
640
|
+
<text x={cx + 82} y={roofY + 38} style={calloutText}>DN</text>
|
|
641
|
+
<text x={cx + 82} y={roofY + 50} style={calloutVal} fill={accent}>{dnValue ? `${dnValue} mm` : '—'}</text>
|
|
642
|
+
|
|
643
|
+
{/* T-Stück Winkel — right-anchored at the outer margin so
|
|
644
|
+
the text stays inside the viewBox at every width. */}
|
|
645
|
+
<line
|
|
646
|
+
x1={cx + 20}
|
|
647
|
+
y1={baseY - 44}
|
|
648
|
+
x2={414}
|
|
649
|
+
y2={baseY - 44}
|
|
650
|
+
stroke={sub}
|
|
651
|
+
strokeWidth="0.5"
|
|
652
|
+
strokeDasharray="2 2"
|
|
653
|
+
/>
|
|
654
|
+
<text x={460} y={baseY - 46} style={calloutText} textAnchor="end">T-STÜCK</text>
|
|
655
|
+
<text x={460} y={baseY - 34} style={calloutVal} textAnchor="end" fill={accent}>{tWinkelLabel}</text>
|
|
656
|
+
|
|
657
|
+
{/* Montageart */}
|
|
658
|
+
<text x="22" y={baseY + 40} style={calloutText}>MONTAGE</text>
|
|
659
|
+
<text x="22" y={baseY + 54} style={calloutVal} fill={accent}>{montageAussen ? 'Außen' : 'Innen'}</text>
|
|
660
|
+
|
|
661
|
+
{/* Mündung type — hidden when pending (the dashed placeholder
|
|
662
|
+
above the mouth already communicates what's missing). */}
|
|
663
|
+
{!isPending && (
|
|
664
|
+
<>
|
|
665
|
+
<text x={cx - 44} y={mouthY - 26} style={calloutText} textAnchor="end">ABSCHLUSS</text>
|
|
666
|
+
<text x={cx - 44} y={mouthY - 14} style={calloutVal} textAnchor="end" fill={accent}>
|
|
667
|
+
{abschlussLabel}
|
|
668
|
+
</text>
|
|
669
|
+
</>
|
|
670
|
+
)}
|
|
671
|
+
</g>
|
|
672
|
+
</svg>
|
|
673
|
+
);
|
|
674
|
+
}
|