{"id":56744,"date":"2025-03-21T14:31:47","date_gmt":"2025-03-21T13:31:47","guid":{"rendered":"https:\/\/dev.diamantrad.com\/?page_id=56744"},"modified":"2026-01-08T11:43:34","modified_gmt":"2026-01-08T10:43:34","slug":"lowstep","status":"publish","type":"page","link":"https:\/\/www.diamantrad.com\/pl-PL\/bikes\/lowstep\/","title":{"rendered":"Lowstep"},"content":{"rendered":"\n<div class=\"wp-block-cover\"><img data-dominant-color=\"64807f\" data-has-transparency=\"false\" loading=\"lazy\" decoding=\"async\" width=\"2250\" height=\"1500\" sizes=\"auto, (max-width: 2250px) 100vw, 2250px\" class=\"wp-block-cover__image-background wp-image-56709 size-full not-transparent\" alt=\"Di 24 zing trip lifestyle 67i0504 300dpitiefeinsteiger\" src=\"https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-png.avif\" style=\"--dominant-color: #64807f; object-position:59% 73%\" data-object-fit=\"cover\" data-object-position=\"59% 73%\" srcset=\"https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-png.avif 2250w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-300x200.avif 300w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-1024x683.avif 1024w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-768x512.avif 768w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-1536x1024.avif 1536w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_24_Zing_Trip_Lifestyle_67I0504_300dpitiefeinsteiger-2048x1365.avif 2048w\" \/><span aria-hidden=\"true\" class=\"wp-block-cover__background has-background-dim-0 has-background-dim\"><\/span><div class=\"wp-block-cover__inner-container is-layout-constrained wp-block-cover-is-layout-constrained\">\n<p class=\"has-text-align-center has-large-font-size\"><\/p>\n\n\n<div class=\"lazyblock-cover-text-2gU7ad wp-block-lazyblock-cover-text\"><div class=\"covertext container py-5 d-flex flex-column colorscheme-light justify-content-center\" id=\"covertext-2gU7ad\">\r\n  <div class=\"lazyblock-inner-blocks\">\n\n<h2 class=\"wp-block-heading\">Rowery z niskim przekrokiem&nbsp;<\/h2>\n\n\n\n<h4 class=\"wp-block-heading\">\u2026 oferuj\u0105 komfort i prostot\u0119 dla ka\u017cdego<\/h4>\n\n<\/div>\r\n<\/div><\/div><\/div><\/div>\n\n\n<div class=\"lazyblock-nncontainer-1vQnkR wp-block-lazyblock-nncontainer\"><div class=\"section-standard\">\r\n  <div class=\"container\" id=\"container-1vQnkR\">\r\n    <div class=\"row\">\r\n      <div class=\"col py-4 py-lg-5\">\r\n        <div class=\"lazyblock-inner-blocks\">\n\n<p>Rowery z ram\u0105 o niskim przekroku, zwane r\u00f3wnie\u017c rowerami z niskim przekrokiem, to nowoczesny wyb\u00f3r dla os\u00f3b ceni\u0105cych wygod\u0119 i \u0142atwo\u015b\u0107 u\u017cytkowania. Niezale\u017cnie od tego, czy chodzi o miejskie dojazdy, relaksuj\u0105ce przeja\u017cd\u017cki rekreacyjne czy codzienny transport, ta konstrukcja ramy sprawdza si\u0119 w ka\u017cdej sytuacji, a przy tym jest wyj\u0105tkowo przyjazna dla u\u017cytkownika.<\/p>\n\n<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div><\/div>\n\n<div class=\"lazyblock-nncontainer-2lvUhR wp-block-lazyblock-nncontainer\"><div class=\"section-light\">\r\n  <div class=\"container\" id=\"container-2lvUhR\">\r\n    <div class=\"row\">\r\n      <div class=\"col py-4 py-lg-5\">\r\n        <div class=\"lazyblock-inner-blocks\">\n<div class=\"lazyblock-bikefinder-Z4XcvP wp-block-lazyblock-bikefinder\"><template id=\"bikeTeaserComponent\">\n  <template x-if=\"frames.value.length\">\n    <div class=\"bikefinder-tile px-3 py-4 px-lg-4\" :class=\"classNames\">\n      <div class=\"bikefinder-tile-content\">\n        <a :href=\"selectedFrame.value.link\" class=\"bikefinder-title\">\n          <h4\n            class=\"mb-0\"\n            x-text=\"extractOrCleanString(selectedFrame.value.title)\"\n          ><\/h4>\n        <\/a>\n\n        <p\n          class=\"bikefinder-subtitle\"\n          x-text=\"$store.utils.t($store.utils.translations.frames[extractOrCleanString(selectedFrame.value.title, true)])\"\n        ><\/p>\n\n        <div\n          class=\"bikefinder-preis\"\n          x-text=\"getAbText() + ' ' + formatNumber(selectedFrame.value.price_lowest) + ' ' + getCurrency()\"\n        ><\/div>\n        <a :href=\"selectedFrame.value.link\" class=\"color-images mx-auto mb-4\"\n          ><picture>\n            <img\n              :src=\"selectedFrameImage.value\"\n              class=\"img-fluid lazy\"\n              :alt=\"selectedFrame.value.title\"\n          \/><\/picture>\n        <\/a>\n\n        <div class=\"bikefinder-controls mb-3\">\n          <div class=\"color-switch\">\n            <template x-for=\"(color, index) in selectedFrame.value.colors\">\n              <span\n                @click=\"onColorClicked(color)\"\n                :class=\"'bike-color-' + color.value.toLowerCase()\"\n                data-bs-toggle=\"tooltip\"\n                data-bs-placement=\"top\"\n                :title=\"color.description\"\n              ><\/span>\n            <\/template>\n          <\/div>\n\n          <div class=\"bikefinder-rahmen\">\n            <ul\n              class=\"nav nav-tabs\"\n              x-data=\"{ frames: framesAsGenerations ? selectedFrameByGeneration: frames }\"\n            >\n              <template x-for=\"(frame, index) in frames.value\">\n                <li\n                  class=\"nav-item\"\n                  @click=\"onFrameClicked(frame)\"\n                  x-show=\"!framesAsGenerations || isFrameInFiltered(frame)\"\n                >\n                  <span\n                    class=\"nav-link\"\n                    :class=\"selectedFrame.value.id == frame.id ? 'active' : ''\"\n                    x-data=\"{ meta: getFrameMeta(frame.frameType) }\"\n                  >\n                    <img\n                      width=\"48\"\n                      height=\"28\"\n                      :src=\"meta.icon\"\n                      data-bs-toggle=\"tooltip\"\n                      data-bs-placement=\"top\"\n                      :title=\"$store.utils.t(meta.text)\"\n                    \/>\n                  <\/span>\n                <\/li>\n              <\/template>\n            <\/ul>\n          <\/div>\n        <\/div>\n      <\/div>\n      <template x-if=\"framesAsGenerations\">\n        <div\n          x-data=\"generation({ generations: frames, generationClickedCallback: generationsCallback })\"\n        ><\/div>\n      <\/template>\n    <\/div>\n  <\/template>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\n      \"biketeaser\",\n      ({ frames, framesAsGenerations, framesMeta }) => ({\n        template: null,\n        frames: { value: frames },\n        selectedFrameByGeneration: { value: [] },\n        selectedFrame: { value: null },\n        framesMeta: framesMeta,\n        selectedFrameImage: {},\n        framesAsGenerations: framesAsGenerations,\n        generationsCallback: null,\n        classNames: \"\",\n        currentVariant: null,\n        init() {\n          this.setup();\n          this.$nextTick(() => {\n            this.mounted();\n            this.render();\n          });\n        },\n        setup() {\n          this.template = document.getElementById(\"bikeTeaserComponent\");\n        },\n        mounted() {\n          if (this.frames.value.length) {\n            if (this.framesAsGenerations) {\n              this.selectedFrameByGeneration.value = this.frames.value[0];\n              this.selectedFrame.value = this.frames.value[0];\n            } else {\n              this.selectedFrame.value = this.frames.value;\n            }\n\n            const frame = this.getFrameWithSpecialRecommendedRetailpriceOrFirst(\n              this.selectedFrame.value,\n            );\n\n            let variant = this.getVariantsWithKey(\n              frame,\n              \"special_recommended_retailprice\",\n            )[0];\n            if (!variant) {\n              variant = frame.variants[0];\n            }\n\n            const uniqueFrameImageOfVariant = this.getImageByVariant(\n              frame,\n              variant,\n            );\n\n            this.selectedFrame.value = frame;\n            this.selectedFrameImage = uniqueFrameImageOfVariant;\n\n            this.setClassNames(variant.id);\n          }\n          this.generationsCallback = this.onGenerationClicked.bind(this);\n        },\n        render() {\n          this.$el.innerHTML = this.template.innerHTML;\n        },\n        getFrameWithSpecialRecommendedRetailpriceOrFirst(frames) {\n          const frame = frames.find((frame) => {\n            return frame.hasOwnProperty(\"special_recommended_retailprice\");\n          });\n          return frame ? frame : frames[0];\n        },\n        getVariantsWithKey(frame, key, value = \"\") {\n          if (\n            frame.commonValues.hasOwnProperty(key) &&\n            (value ? frame.commonValues[key] === value : true)\n          ) {\n            return frame.variants;\n          }\n\n          return frame.variants.filter((variant) => {\n            return variant[key] && (value ? variant[key] === value : true);\n          });\n        },\n        getRecomendedRetailpriceVariantColor(color) {\n          const variantsWithPrice = this.getVariantsWithKey(\n            this.selectedFrame.value,\n            \"special_recommended_retailprice\",\n          );\n\n          const variantsWithColor = this.getVariantsWithKey(\n            this.selectedFrame.value,\n            \"primary_basecolour\",\n            color.value,\n          );\n\n          const variantsWithPriceIds = variantsWithPrice.map(\n            (variant) => variant.id,\n          );\n          let variant = variantsWithPrice.find((variant) =>\n            variantsWithPriceIds.includes(variant.id),\n          );\n          if (!variant) {\n            variant = variantsWithColor.length ? variantsWithColor[0] : this.selectedFrame.value.variants[0];\n          }\n\n          return {\n            value: variant ? variant.value : \"\",\n            variantId: variant ? variant.id : null,\n          };\n        },\n        getImageByVariant(frame, variant) {\n          if (!variant) {\n            return { value: frame?.commonValues?.pos_image, variantId: null };\n          }\n          const uniqueImage = frame.images?.find((image) => {\n            return image.value == variant[image.propertyPath];\n          });\n\n          return uniqueImage\n            ? { value: uniqueImage.value, variantId: variant.id }\n            : { value: frame.commonValues?.pos_image, variantId: variant.id };\n        },\n        isFrameInFiltered(frame) {\n          return frame.hasVariants.length ? true : false;\n        },\n        extractTextInBrackets(text) {\n          const match = text.match(\/\\((.*?)\\)\/);\n          return match ? match[1] : \"\";\n        },\n        onFrameClicked(frame) {\n          this.selectedFrame.value = frame;\n          const variantsWithPrice = this.getVariantsWithKey(\n            frame,\n            \"special_recommended_retailprice\",\n          );\n\n          const variantsWithPosImage = this.getVariantsWithKey(\n            frame,\n            \"pos_image\",\n          );\n\n          const variantsWithPriceIds = variantsWithPrice.map(\n            (variant) => variant.id,\n          );\n\n          let variant = variantsWithPrice.find((variant) =>\n            variantsWithPriceIds.includes(variant.id),\n          );\n          if (!variant) {\n            variant = frame.variants[0];\n          }\n\n          const uniqueFrameImageOfVariant = this.getImageByVariant(\n            frame,\n            variant,\n          );\n\n          this.selectedFrameImage = uniqueFrameImageOfVariant;\n          this.setClassNames(variant.id);\n        },\n        onGenerationClicked(generation) {\n          this.selectedFrameByGeneration.value = generation;\n          this.selectedFrame.value = this.selectedFrameByGeneration.value[0];\n          this.selectedFrameImage = this.selectedFrame.value.images[0];\n          this.setClassNames(this.selectedFrame.value.images[0].variantId);\n        },\n        onColorClicked(color) {\n          this.selectedFrameImage = this.selectedFrame.value.images.find(\n            (image) => image.variantId == color.variantId,\n          );\n\n          const colorRetailprice =\n            this.getRecomendedRetailpriceVariantColor(color);\n          this.setClassNames(colorRetailprice.variantId);\n        },\n        setClassNames(variantId) {\n          \/\/ Maybe many?\n          this.currentVariant = this.selectedFrame.value.variants.find(\n            (variant) => {\n              return variant.id === variantId;\n            },\n          );\n\n          let names = [];\n          if (this.isReducedPrice(this.currentVariant) && this.isLastChance()) {\n            names.push(\"sale\");\n            names.push(\"lastchance\");\n          } else if (this.isReducedPrice(this.currentVariant)) {\n            names.push(\"sale\");\n          } else if (this.isLastChance()) {\n            names.push(\"lastchance\");\n          }\n\n          if (this.isNewBike()) {\n            names.push(\"newbike\");\n          }\n          this.classNames = names.join(\" \");\n        },\n        getPriceText(price) {\n          return \"Ab \" + price + \" EUR\";\n        },\n        formatNumber(number) {\n          if (this.$store.utils.country === \"CH\") {\n            return number.toString().replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, \"'\");\n          } else {\n            return number.toString().replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, \".\");\n          }\n        },\n        getAbText() {\n          const lang = this.$store.utils.lang;\n          return (\n            {\n              da: \"Fra\",\n              de: \"Ab\",\n              en: \"From\",\n              fi: \"Alkaen\",\n              fr: \"\u00c0 partir de\",\n              nl: \"Vanaf\",\n              pl: \"Od\",\n              sv: \"Fr\u00e5n\",\n            }[lang] || \"Ab\"\n          );\n        },\n        getCurrency() {\n          const currencyMap = {\n            CH: \"CHF\",\n            DK: \"DKK\",\n            GB: \"GBP\",\n            PL: \"PLN\",\n            SE: \"SEK\",\n          };\n          const country = this.$store.utils.country;\n          return currencyMap[country] || \"EUR\";\n        },\n        isReducedPrice(variant) {\n          if (variant && variant.special_recommended_retailprice) {\n            return variant.special_recommended_retailprice;\n          }\n          return this.selectedFrame.value.specialRecommendedRetailprice.find(\n            (price) => price.variantId === this.selectedFrame.value.id,\n          );\n        },\n        isLastChance() {\n          return this.selectedFrame.value.lastchance;\n        },\n        isNewBike() {\n          return this.selectedFrame.value.newbike;\n        },\n        removeAllBrackets(str) {\n          const regex = \/\\[.*?\\]|\\(.*?\\)|\\{.*?\\}\/g;\n          return str.replace(regex, \"\");\n        },\n        extractBrackets(str) {\n          const regex = \/\\[.*?\\]|\\(.*?\\)|\\{.*?\\}\/g;\n\n          const matches = str.match(regex);\n\n          return matches || [];\n        },\n        getFrameMeta(frameType) {\n          return this.framesMeta[frameType] || { icon: '', text: '' };\n        },\n        extractOrCleanString(str, returnExtracted = false) {\n          if (!str) return \"\";\n          const pattern =\n            \/\\(?\\b(HCH|MIT|Lowstep|SCH|TIE|Midstep|Stepover|HER|TRA)\\b\\)?\/i;\n          const match = str.match(pattern);\n\n          if (match) {\n            return returnExtracted\n              ? match[1]\n              : str.replace(pattern, \"\").replace(\/\\s+\/g, \" \").trim();\n          }\n\n          return returnExtracted ? null : str.trim();\n        },\n      }),\n    );\n  });\n<\/script>\n<template id=\"generationComponent\">\n  <template x-if=\"getGenerationWithoutActive().length\">\n    <div class=\"dropdown bikefinder-generations\">\n      <button\n        class=\"btn btn-secondary dropdown-toggle p-0\"\n        type=\"button\"\n        :id=\"'dropdownGenerations-' + selectedGeneration.id\"\n        data-bs-toggle=\"dropdown\"\n        aria-expanded=\"false\"\n        x-text=\"$store.utils.t($store.utils.translations.futureGenerations)\"\n      ><\/button>\n      <div\n        class=\"dropdown-menu dropdown-generations\"\n        :aria-labelledby=\"'dropdownGenerations-' + selectedGeneration.id\"\n      >\n        <template\n          x-for=\"(generation, index) in getGenerationWithoutActive(generations)\"\n          :key=\"'genNav-' + index\"\n        >\n          <a\n            @click=\"onGenerationClicked(generation)\"\n            class=\"dropdown-item\"\n            x-text=\"mainTitle(generation)\"\n          ><\/a>\n        <\/template>\n      <\/div>\n    <\/div>\n  <\/template>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\"generation\", ({ generations, generationClickedCallback }) => ({\n      template: null,\n      generations: generations,\n      selectedGeneration: {},\n      selectedFrameImage: {},\n      generationClickedCallback: generationClickedCallback,\n      init() {\n        this.setup();\n        this.$nextTick(() => {\n          this.mounted();\n          this.render();\n        });\n      },\n      setup() {\n        this.template = document.getElementById(\"generationComponent\");\n      },\n      mounted() {\n        if (this.generations.value.length) {\n          this.selectedGeneration = this.generations.value[0];\n        }\n      },\n      render() {\n        this.$el.innerHTML = this.template.innerHTML;\n      },\n      onGenerationClicked(generation) {\n        this.generationClickedCallback(generation);\n        this.selectedGeneration = generation;\n      },\n      active(generation, selectedGeneration) {\n        return generation === selectedGeneration;\n      },\n      getGenerationWithoutActive() {\n        return this.generations.value.filter(\n          (generation) => generation != this.selectedGeneration\n        );\n      },\n      getGenerationFrame(generation) {\n        return generation[0];\n      },\n      extractOrCleanString(str, returnExtracted = false) {\n        const pattern =\n          \/\\(?\\b(HCH|MIT|Lowstep|SCH|TIE|Midstep|Stepover|HER|TRA)\\b\\)?\/i;\n        const match = str.match(pattern);\n\n        if (match) {\n          return returnExtracted\n            ? match[1]\n            : str.replace(pattern, \"\").replace(\/\\s+\/g, \" \").trim();\n        }\n\n        return returnExtracted ? null : str.trim();\n      },\n      mainTitle(generation) {\n        let frame = this.getGenerationFrame(generation);\n        let title = this.extractOrCleanString(frame.title);\n        return (\n          title +\n          \" \" +\n          this.addModelYear(frame) +\n          \" - \" +\n          this.formatNumber(frame.price_lowest) +\n          \" \" +\n          this.getCurrency()\n        );\n      },\n      addModelYear(frame) {\n        if (frame.modelYear) {\n          return \" (\" + frame.modelYear + \")\";\n        }\n        return \"\";\n      },\n      getCurrency() {\n        const currencyMap = {\n          CH: \"CHF\",\n          DK: \"DKK\",\n          GB: \"GBP\",\n          PL: \"PLN\",\n          SE: \"SEK\",\n        };\n        const country = this.$store.utils.country;\n        return currencyMap[country] || \"EUR\";\n      },\n      formatNumber(number) {\n        if (this.$store.utils.country === \"CH\") {\n          return number.toString().replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, \"'\");\n        } else {\n          return number.toString().replace(\/\\B(?=(\\d{3})+(?!\\d))\/g, \".\");\n        }\n      },\n    }));\n  });\n<\/script>\n<template id=\"filterComponent\">\n  <template x-if=\"showReset\">\n    <div id=\"filter\" class=\"bikefinder-filter mb-5 text-start\">\n      <h5 class=\"text-uppercase h-underline mt-4 position-relative\">\n        Filter\n        <div x-show=\"isFilterActive()\" class=\"small reset-filters\">\n          <span\n            @click=\"resetFilter()\"\n            class=\"btn-reset-filters\"\n            x-text=\"$store.utils.t($store.utils.translations.resetFilter)\"\n          >\n          <\/span>\n        <\/div>\n      <\/h5>\n      <div class=\"bike-counter mb-4\">\n        <span id=\"bikeCount\" x-text=\"countOfFilteredBikes.value\"><\/span> Bikes\n      <\/div>\n\n      <!-- Biketyp -->\n      <h5\n        class=\"mb-1\"\n        x-text=\"$store.utils.t($store.utils.translations.bikeType)\"\n      ><\/h5>\n      <div\n        class=\"small text-grey mb-2\"\n        x-text=\"$store.utils.t($store.utils.translations.bikeTypeSpeed)\"\n      ><\/div>\n      <div\n        x-key=\"'typeLineSelection'\"\n        x-data=\"lineselection(\n        { \n            items: typeFilterProps.sort((a, b) => a.context.order < b.context.order ? -1 : 1),\n            onSelected: onTypeSelected,\n            selectedFilter: selectedFilter,\n        }\n      )\"\n      ><\/div>\n\n      <template x-if=\"!hideBattery\">\n        <div class=\"bikefinder-filter-akku\">\n          <!-- Akku -->\n          <h5\n            class=\"mb-1\"\n            x-text=\"$store.utils.t($store.utils.translations.battery)\"\n          ><\/h5>\n          <div\n            class=\"small text-grey mb-2\"\n            x-text=\"$store.utils.t($store.utils.translations.unitBattery)\"\n          ><\/div>\n          <div\n            x-show=\"showReset\"\n            x-data=\"sliderselection(\n            { \n                items: batteryFilterProps,\n                onSelected: onBatterySelected,\n                id: 'battery-slider',\n                domLoaded: domLoaded,\n                options: { step: 100, values: true }\n            }\n          )\"\n          ><\/div>\n        <\/div>\n      <\/template>\n\n      <!-- Rahmenformen -->\n      <h5 x-text=\"$store.utils.t($store.utils.translations.frameShape)\"><\/h5>\n\n      <div\n        x-key=\"'frameLineSelection'\"\n        x-data=\"lineselection(\n        { \n            items: frameFilterProps.sort((a, b) => a.context.order < b.context.order ? -1 : 1),\n            onSelected: onFrameSelected,\n            selectedFilter: selectedFilter,\n        }\n      )\"\n      ><\/div>\n\n      <!-- Schaltung -->\n      <h5 x-text=\"$store.utils.t($store.utils.translations.gear)\"><\/h5>\n      <div\n        x-data=\"choiceselection(\n        { \n            items: gearFilterProps,\n            onSelected: onGearSelected \n        }\n      )\"\n      ><\/div>\n\n      <!-- Preis -->\n      <h5\n        class=\"mb-1\"\n        x-text=\"$store.utils.t($store.utils.translations.price)\"\n      ><\/h5>\n      <div\n        class=\"small text-grey mb-2\"\n        x-text=\"$store.utils.t($store.utils.translations.inCurrency)\"\n      ><\/div>\n      <div\n        x-data=\"sliderselection(\n        { \n            items: priceFilterProps,\n            onSelected: onPriceSelected,\n            id: 'price-slider',\n            domLoaded: domLoaded,\n            options: { step: 100 }\n        }\n      )\"\n      ><\/div>\n\n      <!-- Sale -->\n      <h5 x-text=\"$store.utils.t($store.utils.translations.sale)\"><\/h5>\n      <div\n        x-data=\"multiplechoiceselection(\n        { \n            items: saleFilterProps.concat(lastchanceFilterProps),\n            onSelected: onSaleOrLastchanceSelected \n        }\n      )\"\n      ><\/div>\n\n      <!-- Farben -->\n      <h5 x-text=\"$store.utils.t($store.utils.translations.color)\"><\/h5>\n      <div\n        x-data=\"colorselection(\n        { \n            items: colorFilterProps,\n            onSelected: onColorSelected \n        }\n      )\"\n      ><\/div>\n\n      <!-- Gewicht -->\n      <h5\n        class=\"mb-1\"\n        x-text=\"$store.utils.t($store.utils.translations.weight)\"\n      ><\/h5>\n      <div\n        class=\"small text-grey mb-2\"\n        x-text=\"$store.utils.t($store.utils.translations.unitWeight)\"\n      ><\/div>\n      <div\n        class=\"rslider\"\n        x-data=\"sliderselection(\n        { \n            items: weightFilterProps,\n            onSelected: onWeightSelected,\n            id: 'weight-slider',\n            domLoaded: domLoaded\n        }\n      )\"\n      ><\/div>\n    <\/div>\n  <\/template>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\n      \"filter\",\n      ({\n        frameFilterProps,\n        typeFilterProps,\n        batteryFilterProps,\n        gearFilterProps,\n        priceFilterProps,\n        weightFilterProps,\n        saleFilterProps,\n        lastchanceFilterProps,\n        newbikeFilterProps,\n        countOfFilteredBikes,\n        maxBikesCount,\n        colorFilterProps,\n        selectedFilter,\n        controller,\n      }) => ({\n        template: null,\n        frameFilterProps: frameFilterProps,\n        typeFilterProps: typeFilterProps,\n        batteryFilterProps: batteryFilterProps,\n        gearFilterProps: gearFilterProps,\n        priceFilterProps: priceFilterProps,\n        weightFilterProps: weightFilterProps,\n        saleFilterProps: saleFilterProps,\n        lastchanceFilterProps: lastchanceFilterProps,\n        newbikeFilterProps: newbikeFilterProps,\n        countOfFilteredBikes: countOfFilteredBikes,\n        maxBikesCount: maxBikesCount,\n        colorFilterProps: colorFilterProps,\n        selectedFrame: {},\n        selectedFrameImage: {},\n        controller: controller,\n        showReset: true,\n        domLoaded: false,\n        domUpdate: { value: 0 },\n        selectedFilter: selectedFilter,\n        hideBattery: false,\n        init() {\n          this.setup();\n          this.$nextTick(() => {\n            this.mounted();\n            this.render();\n          });\n        },\n        setup() {\n          this.template = document.getElementById(\"filterComponent\");\n        },\n        mounted() {},\n        render() {\n          this.$el.innerHTML = this.template.innerHTML;\n\n          document.addEventListener(\"DOMContentLoaded\", () => {\n            this.domLoaded = true;\n          });\n\n          this.$watch(\"selectedFilter\", (filter) => {\n            this.hideFilterSections(filter);\n          });\n        },\n        hideFilterSections(filter) {\n          \/\/ Hide Battery\n          const hideBattery = [\"Bike\", \"S-Pedelec\"].includes(\n            filter.properties?.category?.value\n          );\n\n          if (hideBattery) {\n            this.hideBattery = true;\n          } else {\n            this.hideBattery = false;\n          }\n        },\n        onFrameSelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, initial);\n        },\n        onTypeSelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, initial);\n        },\n        onBatterySelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, initial);\n        },\n        onGearSelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, initial);\n        },\n        onPriceSelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, initial);\n        },\n        onWeightSelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, initial);\n        },\n        onSaleOrLastchanceSelected(property, checked, initial = true) {\n          if (checked) {\n            this.controller.filterAddPropertyAction(property, initial);\n          } else {\n            this.controller.filterRemovePropertyAction(property);\n          }\n        },\n        onColorSelected(property, initial = true) {\n          this.controller.filterAddPropertyAction(property, true);\n        },\n        resetFilter() {\n          this.showReset = false;\n          this.controller.resetFilterAction();\n\n          this.$nextTick(() => {\n            this.showReset = true;\n          });\n        },\n        isFilterActive() {\n          return !this.selectedFilter.initial;\n        },\n      })\n    );\n  });\n<\/script>\n<template id=\"lineSelectionComponent\">\n  <div class=\"bikefilter-biketyp mb-4\">\n    <ul class=\"nav nav-tabs\">\n      <template x-for=\"(item, index) in items\">\n        <li class=\"nav-item\">\n          <button\n            @click=\"selected(item, index)\"\n            class=\"nav-link\"\n            :class=\"activeItem &#038;&#038; activeItem.value === item.value ? 'active' : ''\"\n            style=\"outline: none\"\n            data-bs-toggle=\"tooltip\"\n            data-placement=\"top\"\n            :title=\"$store.utils.t(item.context.text)\"\n          >\n            <template x-if=\"item.context &#038;&#038; item.context.type == 'icon'\">\n              <img :src=\"item.context.icon\" style=\"width: 48px; height: 28px\" \/>\n            <\/template>\n            <template x-if=\"item.context &#038;&#038; item.context.type == 'text'\">\n              <span\n                style=\"width: 48px; height: 28px\"\n                x-text=\"$store.utils.t(item.context.text)\"\n              ><\/span>\n            <\/template>\n          <\/button>\n        <\/li>\n      <\/template>\n    <\/ul>\n  <\/div>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\"lineselection\", ({ items, onSelected, selectedFilter }) => ({\n      template: null,\n      items: items,\n      onSelected: onSelected,\n      selectedFilter: selectedFilter,\n      selectedIndex: -1,\n      activeItem: null,\n      init() {\n        this.setup();\n        this.$nextTick(() => {\n          this.mounted();\n          this.render();\n        });\n      },\n      setup() {\n        this.template = document.getElementById(\"lineSelectionComponent\");\n      },\n      mounted() {\n        this.$watch(\"selectedFilter\", (filter) => {\n          this.activeItem = this.findActiveItem(filter);\n        });\n      },\n      render() {\n        this.$el.innerHTML = this.template.innerHTML;\n      },\n      selected(item, index) {\n        this.selectedIndex = index;\n        this.onSelected(item, false);\n      },\n      findActiveItem(filter) {\n        if (this.items[0].propertyPath in filter.properties) {\n          let found = this.items.find((item) => {\n            return (\n              item.value === filter.properties[this.items[0].propertyPath].value\n            );\n          });\n          return found;\n        }\n      },\n    }));\n  });\n<\/script>\n<template id=\"sliderSelectionComponent\">\n\t<div :style=\"!sliderReady ? 'opacity: 0' : ''\" class=\"bikefilter-rahmenform mb-4 mt-3\">\n\t\t<div :style=\"!domLoaded &#038;&#038; !slider ? 'opacity: 0' : ''\">\n\t\t\t<input :id=\"id\" type=\"range\" \/>\n\t\t<\/div>\n\t<\/div>\n<\/template>\n\n<script>\n\tdocument.addEventListener(\"alpine:init\", () => {\n\t\tAlpine.data(\"sliderselection\", ({ items, onSelected, id, domLoaded, options = {} }) => ({\n\t\t\ttemplate: null,\n\t\t\titems: [],\n\t\t\tonSelected: onSelected,\n\t\t\tid: id,\n\t\t\tvalue: 0,\n\t\t\tslider: items,\n\t\t\tdomLoaded: domLoaded,\n\t\t\tmin: 0,\n\t\t\tmax: 0,\n\t\t\toptions: options,\n\t\t\tinitial: true,\n\t\t\tsliderReady: false,\n\t\t\tinit() {\n\t\t\t\tthis.setup();\n\t\t\t\tthis.$nextTick(() => {\n\t\t\t\t\tthis.mounted();\n\t\t\t\t\tthis.render();\n\t\t\t\t});\n\t\t\t},\n\t\t\tsetup() {\n\t\t\t\tthis.template = document.getElementById(\"sliderSelectionComponent\");\n\t\t\t},\n\t\t\tmounted() {\n\t\t\t\tif (items.length) {\n\t\t\t\t\tthis.items = items.sort((a, b) => (Number(a.value) > Number(b.value) ? 1 : -1));\n\n\t\t\t\t\tthis.min = this.items[0].value;\n\t\t\t\t\tthis.max = this.items.slice(-1)[0].value;\n\t\t\t\t\tthis.value = this.max;\n\t\t\t\t}\n\t\t\t},\n\t\t\trender() {\n\t\t\t\tthis.$el.innerHTML = this.template.innerHTML;\n\n\t\t\t\tdocument.addEventListener(\"DOMContentLoaded\", () => {\n\t\t\t\t\tthis.domLoaded = true;\n\t\t\t\t\tthis.initRangeSlider();\n\t\t\t\t});\n\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tif (!this.domLoaded) {\n\t\t\t\t\t\tthis.initRangeSlider();\n\t\t\t\t\t}\n\t\t\t\t}, 400);\n\t\t\t},\n\t\t\tinitRangeSlider() {\n\t\t\t\tthis.domLoaded = true;\n\t\t\t\tthis.initial = true;\n\n\t\t\t\tconst min = this.roundMin(parseInt(this.min, 10));\n\t\t\t\tconst max = this.roundMax(parseInt(this.max, 10));\n\n\t\t\t\tthis.slider = new rSlider({\n\t\t\t\t\ttarget: \"#\" + this.id,\n\t\t\t\t\tvalues: options.values && options.values == true ? this.getAllValues() : { min: min, max: max },\n\t\t\t\t\trange: true,\n\t\t\t\t\ttooltip: true,\n\t\t\t\t\tstep: options.step ? options.step : 1,\n\t\t\t\t\tscale: false,\n\t\t\t\t\tlabels: true,\n\t\t\t\t\tvariableWidth: true,\n\t\t\t\t\tunit: \"kg\",\n\t\t\t\t\tset: [this.min, this.max],\n\t\t\t\t\tonChange: (vals) => {\n\t\t\t\t\t\t\/\/ vals is not correct so get from index\n\t\t\t\t\t\tlet min = Number(this.slider.conf.values[this.slider.values.start]);\n\t\t\t\t\t\tlet max = Number(this.slider.conf.values[this.slider.values.end]);\n\t\t\t\t\t\tthis.setValue(min, max);\n\t\t\t\t\t},\n\t\t\t\t});\n\n\t\t\t\tconst sliderElements = document.querySelectorAll(\".rs-container\");\n\t\t\t\tsliderElements.forEach((element) => {\n\t\t\t\t\telement.addEventListener(\"mousedown\", () => {\n\t\t\t\t\t\tthis.initial = false;\n\t\t\t\t\t});\n\t\t\t\t\telement.addEventListener(\"touchstart\", () => {\n\t\t\t\t\t\tthis.initial = false;\n\t\t\t\t\t});\n\t\t\t\t});\n\n\t\t\t\tthis.sliderReady = true;\n\t\t\t},\n\t\t\tsetValue(min, max) {\n\t\t\t\tlet range = this.items.filter((item) => {\n\t\t\t\t\tconst itemValue = Number(item.value);\n\t\t\t\t\treturn itemValue >= min && itemValue <= max;\n\t\t\t\t});\n\t\t\t\tif (range.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tlet maxOfRange = range.reduce((max, obj) => {\n\t\t\t\t\treturn Number(obj.value) > Number(max.value) ? obj : max;\n\t\t\t\t}, range[0]);\n\n\t\t\t\tlet minOfRange = range.reduce((min, obj) => {\n\t\t\t\t\treturn Number(obj.value) < Number(min.value) ? obj : min;\n\t\t\t\t}, range[0]);\n\n\t\t\t\tif (maxOfRange) {\n\t\t\t\t\tif (minOfRange) {\n\t\t\t\t\t\tmaxOfRange[\"min\"] = minOfRange.value;\n\t\t\t\t\t\tthis.select(maxOfRange, false);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\tselect(property) {\n\t\t\t\tthis.onSelected(property, this.initial);\n\t\t\t},\n\t\t\tgetAllValues() {\n\t\t\t\treturn this.items.map((item) => Number(item.value));\n\t\t\t},\n\t\t\troundMin(num) {\n\t\t\t\tif (num > 100) {\n\t\t\t\t\treturn Math.floor(num \/ 50) * 50;\n\t\t\t\t} else {\n\t\t\t\t\treturn Math.floor(num \/ 10) * 10;\n\t\t\t\t}\n\t\t\t},\n\t\t\troundMax(num) {\n\t\t\t\tif (num > 100) {\n\t\t\t\t\treturn Math.ceil(num \/ 50) * 50;\n\t\t\t\t} else {\n\t\t\t\t\treturn Math.ceil(num \/ 10) * 10;\n\t\t\t\t}\n\t\t\t},\n\t\t}));\n\t});\n<\/script>\n<template id=\"choiceSelectionComponent\">\n  <div class=\"bikefilter-schaltung mb-4\">\n    <fieldset>\n      <template x-for=\"(item, index) in items\">\n        <div class=\"form-check\">\n          <input\n            type=\"radio\"\n            :id=\"item.propertyPath + index\"\n            name=\"drone\"\n            value=\"huey\"\n            x-on:input.change=\"onSelected(item, false)\"\n            class=\"form-check-input\"\n          \/>\n          <label\n            :for=\"item.propertyPath + index\"\n            x-text=\"$store.utils.t(item.context.text)\"\n            class=\"form-check-label\"\n          ><\/label>\n        <\/div>\n      <\/template>\n    <\/fieldset>\n  <\/div>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\"choiceselection\", ({ items, onSelected }) => ({\n      template: null,\n      items: items,\n      onSelected: onSelected,\n      value: 0,\n      init() {\n        this.setup();\n        this.$nextTick(() => {\n          this.mounted();\n          this.render();\n        });\n      },\n      setup() {\n        this.template = document.getElementById(\"choiceSelectionComponent\");\n      },\n      mounted() {},\n      render() {\n        this.$el.innerHTML = this.template.innerHTML;\n      },\n    }));\n  });\n<\/script>\n<template id=\"multipleChoiceSelectionComponent\">\n  <div class=\"bikefilter-schaltung mb-4\">\n    <fieldset>\n      <template x-for=\"(item, index) in items\">\n        <div class=\"form-check\">\n          <input\n            type=\"checkbox\"\n            :id=\"item.propertyPath + index\"\n            name=\"drone\"\n            value=\"huey\"\n            x-on:input.change=\"onSelected(item, $event.target.checked, false)\"\n            class=\"form-check-input\"\n          \/>\n          <label\n            :for=\"item.propertyPath + index\"\n            x-text=\"$store.utils.t(item.context.text)\"\n            class=\"form-check-label\"\n          ><\/label>\n        <\/div>\n      <\/template>\n    <\/fieldset>\n  <\/div>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\"multiplechoiceselection\", ({ items, onSelected }) => ({\n      template: null,\n      items: items,\n      onSelected: onSelected,\n      value: 0,\n      init() {\n        this.setup();\n        this.$nextTick(() => {\n          this.mounted();\n          this.render();\n        });\n      },\n      setup() {\n        this.template = document.getElementById(\n          \"multipleChoiceSelectionComponent\"\n        );\n      },\n      mounted() {},\n      render() {\n        this.$el.innerHTML = this.template.innerHTML;\n      },\n    }));\n  });\n<\/script>\n<template id=\"colorSelectionComponent\">\n  <div class=\"color-options mb-4\">\n    <ul class=\"ps-0\">\n      <template x-for=\"(item, index) in items\">\n        <li>\n          <button\n            @click=\"selected(item, index, false)\"\n            :class=\"'btn filter-color-' + item.value.toLowerCase() + ' ' + ((selectedIndex == index) ? 'active' : '')\"\n            data-bs-toggle=\"tooltip\"\n            data-placement=\"top\"\n            :title=\"item.description\"\n          ><\/button>\n        <\/li>\n      <\/template>\n    <\/ul>\n  <\/div>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\"colorselection\", ({ items, onSelected }) => ({\n      template: null,\n      items: items,\n      onSelected: onSelected,\n      selectedIndex: -1,\n      init() {\n        this.setup();\n        this.$nextTick(() => {\n          this.mounted();\n          this.render();\n        });\n      },\n      setup() {\n        this.template = document.getElementById(\"colorSelectionComponent\");\n      },\n      mounted() {},\n      render() {\n        this.$el.innerHTML = this.template.innerHTML;\n      },\n      selected(item, index, initial) {\n        this.selectedIndex = index;\n        this.onSelected(item, initial);\n      },\n    }));\n  });\n<\/script>\n<template id=\"bikefinderComponent\">\n  <div class=\"bikefinder\">\n    <div class=\"row\">\n      <div class=\"col-md-4 col-lg-3 bikefinder-filter-col\">\n        <button\n          class=\"btn btn-primary filter-toggle d-md-none mb-3\"\n          data-show=\"Filter anzeigen\"\n          data-hide=\"Filter ausblenden\"\n          x-text=\"$store.utils.t($store.utils.translations.showFilter)\"\n        ><\/button>\n\n        <div\n          class=\"bikefinder-filter-content\"\n          x-data=\"filter({ \n            frameFilterProps: uniquePropFrames(), \n            typeFilterProps: model.uniquePropTypes(), \n            batteryFilterProps: uniquePropBatteries(), \n            gearFilterProps: uniquePropGears(),\n            priceFilterProps: uniquePropPrices(),\n            weightFilterProps: uniquePropWeights(),\n            saleFilterProps: model.uniquePropSales(),\n            lastchanceFilterProps: model.uniquePropLastchance(),\n            newbikeFilterProps: model.uniquePropNewbike(),\n            countOfFilteredBikes: state.countOfFilteredBikes,\n            maxBikesCount: state.maxBikesCount,\n            colorFilterProps: uniquePropColors(),\n            selectedFilter: state.selectedFilter,\n            controller: controller\n          })\"\n        ><\/div>\n      <\/div>\n      <div class=\"col-md-8 col-lg-9\">\n        <div class=\"dropdown text-end dropdown-underline\">\n          <button\n            class=\"btn btn-secondary dropdown-toggle p-0 pb-1 me-3 me-md-4\"\n            type=\"button\"\n            id=\"dropdownSort\"\n            data-bs-toggle=\"dropdown\"\n            aria-haspopup=\"true\"\n            aria-expanded=\"false\"\n            x-text=\"$store.utils.t($store.utils.translations.sortBy)\"\n          ><\/button>\n\n          <div\n            class=\"dropdown-menu dropdown-menu-end dropdown-sort\"\n            aria-labelledby=\"dropdownSort\"\n          >\n            <a\n              @click=\"controller.sortNewestAlphaAction()\"\n              class=\"dropdown-item\"\n              :class=\"state.currentSort == 'newestalpha' ? 'active' : ''\"\n              id=\"sort-newest-alpha\"\n              x-text=\"$store.utils.t($store.utils.translations.sortByNewestAlpha)\"\n            ><\/a>\n            <a\n              @click=\"controller.sortAlphaAction()\"\n              class=\"dropdown-item\"\n              :class=\"state.currentSort == 'alpha' ? 'active' : ''\"\n              id=\"sort-alpha\"\n              x-text=\"$store.utils.t($store.utils.translations.sortByAlpha)\"\n            ><\/a>\n            <a\n              @click=\"controller.sortPriceAction()\"\n              class=\"dropdown-item\"\n              :class=\"state.currentSort == 'priceASC' ? 'active' : 'peter'\"\n              id=\"sort-price-asc\"\n              x-text=\"$store.utils.t($store.utils.translations.sortByAsc)\"\n            ><\/a>\n            <a\n              @click=\"controller.sortPriceAction(true)\"\n              class=\"dropdown-item\"\n              :class=\"state.currentSort == 'priceDESC' ? 'active' : 'peter'\"\n              id=\"sort-price-desc\"\n              x-text=\"$store.utils.t($store.utils.translations.sortByDesc)\"\n            ><\/a>\n          <\/div>\n        <\/div>\n        <template x-if=\"showBikeSort &#038;&#038; initialReady\">\n          <div\n            x-data=\"{ bikesByGenerations: state.filteredBikesGroupedByGenerations  }\"\n            class=\"bikefinder-bikes p-md-3 p-lg-4\"\n          >\n            <div\n              x-show=\"state.countOfFilteredBikes.value == 0\"\n              class=\"no-results\"\n            >\n              <span\n                x-text=\"$store.utils.t($store.utils.translations.noResults)\"\n              ><\/span>\n            <\/div>\n            <div class=\"bikefinder-grid\">\n              <template x-for=\"(value, index) in bikesByGenerations\">\n                <div\n                  x-data=\"biketeaser({ frames: bikesByGenerations[index], framesAsGenerations: true, framesMeta: model.frameFilterModel })\"\n                ><\/div>\n              <\/template>\n            <\/div>\n          <\/div>\n        <\/template>\n      <\/div>\n    <\/div>\n  <\/div>\n<\/template>\n\n<script>\n  document.addEventListener(\"alpine:init\", () => {\n    Alpine.data(\n      \"bikefinder\",\n      ({\n        blockId,\n        model,\n        store,\n        state,\n        utils,\n        controller,\n        filterParamsResolver,\n      }) => ({\n        blockId: blockId,\n        model: model,\n        store: store,\n        state: state,\n        utils: utils,\n        controller: controller,\n        filterParamsResolver: filterParamsResolver,\n        showBikeSort: false,\n        initialReady: false,\n        init() {\n          this.setup();\n          this.$nextTick(() => {\n            this.mounted();\n            this.render();\n          });\n        },\n        setup() {\n          this.template = document.getElementById(\"bikefinderComponent\");\n        },\n        mounted() {\n          this.model.variantsToUniqueFramesAndFlattedVariants(\n            this.model.modules[this.blockId].bikes,\n            this.blockId\n          );\n\n          this.$watch(\"state.selectedFilter\", (value) => {\n            this.filter(value);\n          });\n\n          this.$watch(\"state.filteredBikesGroupedByGenerations\", (grouped) => {\n            this.reactiveBikeSort();\n          });\n\n          setTimeout(() => {\n            const { filters } = this.filterParamsResolver.defaultParams;\n            Object.keys(filters).forEach((key) => {\n              this.filterByParams(key, filters[key], true);\n            });\n            \/\/ wait to set all default filter properties - for resetFilterAction() -- to prevent watch updates on state.selectedFilter\n            this.state.defaultFilterProperties = JSON.stringify(\n              this.state.selectedFilter.properties\n            );\n\n            this.initialReady = true;\n          }, 1500);\n        },\n        render() {\n          this.$el.innerHTML = this.template.innerHTML;\n        },\n        filterByParams(key, value, initial) {\n          const propsMap = {\n            category: {\n              getProps: () => this.model.uniquePropTypes(),\n              keyName: \"value\",\n            },\n            primary_basecolour: {\n              getProps: () => this.uniquePropColors(),\n              keyName: \"value\",\n            },\n            frame_type: {\n              getProps: () => this.uniquePropFrames(),\n              keyName: \"value\",\n            },\n            \"bike_specifics.gear.gear_type\": {\n              getProps: () => this.uniquePropGears(),\n              keyName: \"value\",\n            },\n            \"ebike_specifics.battery_range.battery_capacity\": {\n              getProps: () => this.uniquePropBatteries(),\n              keyName: \"value\",\n            },\n          };\n\n          if (key in propsMap) {\n            const mapResult = propsMap[key];\n            const prop = mapResult\n              .getProps()\n              .find((prop) => prop[mapResult[\"keyName\"]] == value);\n            if (prop) {\n              this.controller.filterAddPropertyAction(prop, initial);\n            }\n\n            this.state.selectedFilter.initial = false;\n          }\n        },\n\n        filter(value) {\n          this.model.groupedFrames[this.blockId].forEach((group) => {\n            group.forEach((frame) => {\n              frame.filter(value);\n            });\n          });\n\n          this.state.filteredBikes =\n            this.controller.getOnlyBikesWhereFramesWithVariants(\n              this.model.groupedFrames[this.blockId]\n            );\n\n          const generations = this.controller.getGenerations(\n            this.state.filteredBikes\n          );\n          this.state.filteredBikesGroupedByGenerations = generations;\n\n          const countOfBikes = this.controller.calculateCountOfFilteredBikes(\n            this.blockId\n          );\n          if (this.state.selectedFilter.initial) {\n            this.state.maxBikesCount.value = countOfBikes;\n          }\n\n          this.state.countOfFilteredBikes.value = countOfBikes;\n          this.controller.sortNewestAlphaAction();\n\n          \/\/ Sync Filter\n          this.filterParamsResolver.setFiltersParams(\n            this.filterParamsResolver.getActiveFilters()\n          );\n        },\n        reactiveBikeSort() {\n          this.showBikeSort = false;\n          this.$nextTick(() => {\n            this.showBikeSort = true;\n          });\n        },\n        uniquePropFrames() {\n          return this.model.uniquePropFrames(this.blockId);\n        },\n        uniquePropBatteries() {\n          return this.model.uniquePropBatteries(this.blockId);\n        },\n        uniquePropGears() {\n          return this.model.uniquePropGears(this.blockId);\n        },\n        uniquePropPrices() {\n          return this.model.uniquePropPrices(this.blockId);\n        },\n        uniquePropWeights() {\n          return this.model.uniquePropWeights(this.blockId);\n        },\n        uniquePropColors() {\n          return this.model.uniquePropColors(this.blockId);\n        },\n      })\n    );\n  });\n<\/script>\n\n<style type=\"text\/css\">\n  body.modal-open {\n    padding-right: 0px !important;\n    overflow: auto !important;\n  }\n\n  body {\n    padding-right: 0 !important;\n  }\n\n  body.modal-open header,\n  body.modal-open .content {\n    padding-right: 0 !important;\n  }\n<\/style>\n<div x-data='bikefinder({ \n    blockId: \"Z4XcvP\", \n    model: $store.bikefinderModel, \n    store: $store.bikefinderStore, \n    state: $store.bikefinderState, \n    utils: $store.utils, \n    controller: $store.bikefinderController,\n    filterParamsResolver: $store.bikefinderFilterParamsResolver })'>\n<\/div>\n<\/div>\n<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div><\/div>\n\n<div class=\"lazyblock-nncontainer-1JYotJ wp-block-lazyblock-nncontainer\"><div class=\"section-standard\">\r\n  <div class=\"container\" id=\"container-1JYotJ\">\r\n    <div class=\"row\">\r\n      <div class=\"col py-4 py-lg-5\">\r\n        <div class=\"lazyblock-inner-blocks\">\n\n<h3 class=\"wp-block-heading\">Jakie s\u0105 zalety rower\u00f3w z niskim przekrokiem?<\/h3>\n\n\n\n<p>Rowery z niskim przekrokiem charakteryzuj\u0105 si\u0119 wyj\u0105tkowo nisk\u0105 wysoko\u015bci\u0105 przekroku, dzi\u0119ki czemu \u0142atwo si\u0119 na nie wsiada i z nich zsiada. Konstrukcja ta jest szczeg\u00f3lnie popularna w rowerach elektrycznych, w\u015br\u00f3d kt\u00f3rych dominuj\u0105 modele z niskim przekrokiem. Najwa\u017cniejsze zalety to:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>\u0141atwe wsiadanie i zsiadanie<\/strong>: Idealne dla os\u00f3b o ograniczonej sprawno\u015bci ruchowej, starszych rowerzyst\u00f3w i ka\u017cdego, kto ceni wygod\u0119.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Du\u017ca stabilno\u015b\u0107<\/strong>: Nasze nowoczesne rowery z niskim przekrokiem wykonane s\u0105 z materia\u0142\u00f3w najwy\u017cszej jako\u015bci i s\u0105 r\u00f3wnie stabilne jak inne modele ram.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Wszechstronno\u015b\u0107:<\/strong> Niezale\u017cnie od tego, czy jest to rower Trekking\u00ae, miejski, czy elektryczny, opcja z niskim przekrokiem jest dost\u0119pna w r\u00f3\u017cnych kategoriach.&nbsp;<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Dla kogo s\u0105 rowery z niskim przekrokiem?<\/h3>\n\n\n\n<p>Rowery z niskim przekrokiem s\u0105 idealne dla os\u00f3b szukaj\u0105cych komfortowej i bezpiecznej jazdy. Skorzystaj\u0105 z nich szczeg\u00f3lnie:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Doje\u017cd\u017caj\u0105cy<\/strong>: Niski przekrok sprawia, \u017ce rowery te nadaj\u0105 si\u0119 do codziennej jazdy w garniturze lub sp\u00f3dnicy.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Seniorzy<\/strong>: Komfort i bezpiecze\u0144stwo to priorytety podczas ruszania i zatrzymywania si\u0119.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Rodziny<\/strong>: Nawet maj\u0105c fotelik dzieci\u0119cy lub obci\u0105\u017cony baga\u017cnik, rodzice mog\u0105 z \u0142atwo\u015bci\u0105 wsi\u0105\u015b\u0107 na rower i bezpiecznie uruchomi\u0107 go i zatrzyma\u0107.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Rowerzy\u015bci o ograniczonej sprawno\u015bci ruchowej<\/strong>: Szeroka rama z przekrokiem (bez udziwnie\u0144) u\u0142atwia wsiadanie na rower.&nbsp;<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\">Specjalne cechy nowoczesnych rower\u00f3w z niskim przekrokiem<\/h3>\n\n\n\n<p>Dzisiejsze rowery z niskim przekrokiem s\u0105 wyposa\u017cane w szereg rozwi\u0105za\u0144 skupionych na wsp\u00f3\u0142czesnych potrzebach:&nbsp;<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Ergonomia<\/strong>: Regulowana kierownica, siode\u0142ko i pozycja peda\u0142\u00f3w gwarantuj\u0105 idealne dopasowanie do wymiar\u00f3w cia\u0142a.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Stabilno\u015b\u0107<\/strong>: Materia\u0142y najwy\u017cszej jako\u015bci i przemy\u015blana konstrukcja ramy sprawiaj\u0105, \u017ce rowery te s\u0105 solidne i trwa\u0142e.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>R\u00f3\u017cnorodno\u015b\u0107<\/strong>: Niezale\u017cnie od tego, czy s\u0105 to rowery sportowe czy rekreacyjne, z silnikiem czy bez, rowery z niskim przekrokiem spe\u0142niaj\u0105 wszystkie potrzeby.&nbsp;<\/li>\n<\/ul>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Konstrukcja<\/strong>: Nowoczesne rowery z niskim przekrokiem \u0142\u0105cz\u0105 w sobie funkcjonalno\u015b\u0107, stylowy design i \u017cywe kolory.&nbsp;<\/li>\n<\/ul>\n\n<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div><\/div>\n\n\n<div class=\"wp-block-cover is-light\"><img data-dominant-color=\"917183\" data-has-transparency=\"false\" loading=\"lazy\" decoding=\"async\" width=\"2560\" height=\"1707\" sizes=\"auto, (max-width: 2560px) 100vw, 2560px\" class=\"wp-block-cover__image-background wp-image-56679 size-full not-transparent\" alt=\"Di 25 suvea lifestyle\" src=\"https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-scaled.avif\" style=\"--dominant-color: #917183; object-position:59% 32%\" data-object-fit=\"cover\" data-object-position=\"59% 32%\" srcset=\"https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-scaled.avif 2560w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-300x200.avif 300w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-1024x683.avif 1024w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-768x512.avif 768w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-1536x1024.avif 1536w, https:\/\/www.diamantrad.com\/wp-content\/uploads\/2025\/03\/DI_25_Suvea_Lifestyle_67I4568_300dpi-2048x1365.avif 2048w\" \/><span aria-hidden=\"true\" class=\"wp-block-cover__background has-background-dim-0 has-background-dim\"><\/span><div class=\"wp-block-cover__inner-container is-layout-constrained wp-block-cover-is-layout-constrained\">\n<p class=\"has-text-align-center has-large-font-size\"><\/p>\n<\/div><\/div>\n\n\n<div class=\"lazyblock-nncontainer-Z5mR1n wp-block-lazyblock-nncontainer\"><div class=\"section-light\">\r\n  <div class=\"container\" id=\"container-Z5mR1n\">\r\n    <div class=\"row\">\r\n      <div class=\"col py-4 py-lg-5\">\r\n        <div class=\"lazyblock-inner-blocks\">\n\n<h3 class=\"wp-block-heading\">Cz\u0119sto zadawane pytania dotycz\u0105ce rower\u00f3w z niskim przekrokiem&nbsp;<\/h3>\n\n\n\n<p><strong>Czy rowery z niskim przekrokiem s\u0105 mniej stabilne ni\u017c inne?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Nie, nowoczesne rowery z niskim przekrokiem s\u0105 tak samo stabilne jak modele z ramami o wysokim lub \u015brednim przekroku. Dzi\u0119ki zaawansowanym materia\u0142om i innowacyjnej konstrukcji spe\u0142niaj\u0105 one wszystkie wymagania. Niekt\u00f3re modele z niskim przekrokiem s\u0105 nawet przeznaczone do jazdy po szlakach.&nbsp;<\/p>\n\n\n\n<p><strong>Czy istniej\u0105 rowery elektryczne z niskim przekrokiem?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Oczywi\u015bcie! Wiele rower\u00f3w elektrycznych ma niski przekrok. U\u0142atwia to wsiadanie i jest szczeg\u00f3lnie praktyczne w codziennym u\u017cytkowaniu. W Diamant uwa\u017camy obecnie ram\u0119 z niskim przekrokiem za podstawow\u0105 wersj\u0119 do tworzenia wariant\u00f3w wszelkich nowych platform.&nbsp;<\/p>\n\n\n\n<p><strong>Czy rowery z niskim przekrokiem s\u0105 tylko dla kobiet?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Sk\u0105d\u017ce! Rowery z niskim przekrokiem s\u0105 przeznaczone dla obu p\u0142ci, zapewniaj\u0105c wygod\u0119 i funkcjonalno\u015b\u0107 ka\u017cdemu.&nbsp;<\/p>\n\n\n\n<p><strong>Czy mog\u0119 przerobi\u0107 rower m\u0119ski na rower z niskim przekrokiem?<\/strong>&nbsp;<\/p>\n\n\n\n<p>Raczej nie. Usuni\u0119cie rury g\u00f3rnej z ramy bez przekroku narusza integralno\u015b\u0107 strukturaln\u0105 roweru. Jednak Diamant oferuje wyj\u0105tkowe rozwi\u0105zanie: Diamant Suvea, rower elektryczny z niskim przekrokiem, kt\u00f3ry mo\u017cna wyposa\u017cy\u0107 w opcjonalny wspornik na akcesoria. Wspornik ten pe\u0142ni funkcj\u0119 modu\u0142owej rury g\u00f3rnej, a profesjonalny mechanik zamontuje go w zaledwie pi\u0119\u0107 minut. Aby w pe\u0142ni wykorzysta\u0107 niski przekrok, wystarczy zdemontowa\u0107 wspornik na akcesoria.&nbsp;<\/p>\n\n<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div><\/div>\n\n<div class=\"lazyblock-nncontainer-Zxyg0T wp-block-lazyblock-nncontainer\"><div class=\"section-standard\">\r\n  <div class=\"container\" id=\"container-Zxyg0T\">\r\n    <div class=\"row\">\r\n      <div class=\"col py-4 py-lg-5\">\r\n        <div class=\"lazyblock-inner-blocks\">\n\n<h3 class=\"wp-block-heading\">Kup rower z niskim przekrokiem<\/h3>\n\n\n\n<p>Rowery z niskim przekrokiem zapewniaj\u0105 wygod\u0119, bezpiecze\u0144stwo i uniwersalno\u015b\u0107. S\u0105 idealnym wyborem dla rowerzyst\u00f3w ceni\u0105cych \u0142atwo\u015b\u0107 u\u017cytkowania bez po\u015bwi\u0119cania stylu i dzia\u0142ania. Niezale\u017cnie od tego, czy potrzebujesz roweru typu Trekking\u00ae, miejskiego czy elektrycznego, rowery z niskim przekrokiem s\u0105 nowoczesn\u0105 odpowiedzi\u0105 na dzisiejsze potrzeby rowerzyst\u00f3w. Najciekawsz\u0105 propozycj\u0105 pod wzgl\u0119dem stosunku jako\u015bci do ceny s\u0105 modele takie jak Diamant Suvea, kt\u00f3re mo\u017cna stosowa\u0107 zar\u00f3wno z niskim przekrokiem, jak i bez przekroku.&nbsp;<\/p>\n\n\n\n<p>Odkryj nasz\u0105 ofert\u0119 rower\u00f3w z niskim przekrokiem i znajd\u017a idealny rower odpowiadaj\u0105cy Twoim potrzebom!&nbsp;<\/p>\n\n<\/div>\r\n      <\/div>\r\n    <\/div>\r\n  <\/div>\r\n<\/div><\/div>","protected":false},"excerpt":{"rendered":"<p>Odkryj wszystkie komfortowe rowery od Diamant \u2713 Trekking \u2713 E-bike \u2713 Eleganckie kolory.<\/p>\n","protected":false},"author":8,"featured_media":56718,"parent":38323,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"slim_seo":{"title":"Rowery z niskim przekrokiem dla kobiet i m\u0119\u017cczyzn","description":"Odkryj wszystkie komfortowe rowery od Diamant \u2713 Trekking \u2713 E-bike \u2713 Eleganckie kolory."},"footnotes":""},"class_list":["post-56744","page","type-page","status-publish","has-post-thumbnail","hentry"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/pages\/56744","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/users\/8"}],"replies":[{"embeddable":true,"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/comments?post=56744"}],"version-history":[{"count":3,"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/pages\/56744\/revisions"}],"predecessor-version":[{"id":72154,"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/pages\/56744\/revisions\/72154"}],"up":[{"embeddable":true,"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/pages\/38323"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/media\/56718"}],"wp:attachment":[{"href":"https:\/\/www.diamantrad.com\/en-GB\/wp-json\/wp\/v2\/media?parent=56744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}