@shopware/cms-base-layer 1.5.0 → 2.0.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 +328 -13
- package/app/app.config.ts +7 -0
- package/app/assets/icons/check-circle.svg +3 -0
- package/app/assets/icons/checkmark.svg +3 -0
- package/app/assets/icons/chevron.svg +3 -0
- package/app/assets/icons/exclamation-circle.svg +3 -0
- package/app/assets/icons/star-empty.svg +3 -0
- package/app/assets/icons/star-filled.svg +3 -0
- package/app/assets/icons/user.svg +1 -0
- package/app/components/SwCategoryNavigation.vue +76 -0
- package/app/components/SwCategoryNavigationLink.vue +128 -0
- package/{components → app/components}/SwContactForm.vue +27 -27
- package/app/components/SwFilterChips.vue +144 -0
- package/app/components/SwListingProductPrice.vue +89 -0
- package/{components → app/components}/SwNewsletterForm.vue +45 -34
- package/{components → app/components}/SwPagination.vue +3 -5
- package/{components → app/components}/SwProductAddToCart.vue +22 -27
- package/app/components/SwProductCard.vue +170 -0
- package/app/components/SwProductCardDetails.vue +57 -0
- package/app/components/SwProductCardImage.vue +87 -0
- package/app/components/SwProductCardSkeleton.vue +33 -0
- package/app/components/SwProductListingFilter.vue +64 -0
- package/app/components/SwProductListingFilters.vue +308 -0
- package/{components → app/components}/SwProductReviews.vue +28 -13
- package/app/components/SwProductReviewsForm.vue +292 -0
- package/app/components/SwQuantitySelect.vue +106 -0
- package/{components → app/components}/SwSlider.vue +4 -4
- package/app/components/SwSortDropdown.vue +83 -0
- package/app/components/SwStockInfo.vue +44 -0
- package/{components → app/components}/SwVariantConfigurator.vue +1 -1
- package/app/components/listing-filters/SwFilterPrice.vue +214 -0
- package/app/components/listing-filters/SwFilterProperties.vue +113 -0
- package/app/components/listing-filters/SwFilterRating.vue +90 -0
- package/app/components/listing-filters/SwFilterShippingFree.vue +107 -0
- package/{components → app/components}/public/cms/CmsPage.vue +19 -4
- package/{components → app/components}/public/cms/block/CmsBlockGalleryBuybox.vue +5 -5
- package/{components → app/components}/public/cms/block/CmsBlockImageBubbleRow.vue +5 -5
- package/app/components/public/cms/block/CmsBlockImageFourColumn.vue +41 -0
- package/app/components/public/cms/block/CmsBlockImageGalleryBig.vue +42 -0
- package/app/components/public/cms/block/CmsBlockImageHighlightRow.vue +37 -0
- package/{components → app/components}/public/cms/block/CmsBlockImageSimpleGrid.vue +11 -5
- package/{components → app/components}/public/cms/block/CmsBlockImageText.vue +7 -3
- package/{components → app/components}/public/cms/block/CmsBlockImageTextBubble.vue +13 -16
- package/{components → app/components}/public/cms/block/CmsBlockImageTextCover.vue +7 -9
- package/app/components/public/cms/block/CmsBlockImageTextGallery.vue +88 -0
- package/app/components/public/cms/block/CmsBlockImageTextRow.vue +53 -0
- package/{components → app/components}/public/cms/block/CmsBlockImageThreeColumn.vue +10 -4
- package/app/components/public/cms/block/CmsBlockImageThreeCover.vue +37 -0
- package/app/components/public/cms/block/CmsBlockImageTwoColumn.vue +37 -0
- package/{components → app/components}/public/cms/block/CmsBlockProductHeading.vue +1 -1
- package/{components → app/components}/public/cms/block/CmsBlockProductThreeColumn.vue +10 -4
- package/{components → app/components}/public/cms/block/CmsBlockSidebarFilter.vue +3 -1
- package/app/components/public/cms/block/CmsBlockTextOnImage.vue +30 -0
- package/{components → app/components}/public/cms/block/CmsBlockTextTeaserSection.vue +4 -4
- package/{components → app/components}/public/cms/block/CmsBlockTextTwoColumn.vue +3 -5
- package/app/components/public/cms/element/CmsElementBuyBox.vue +145 -0
- package/app/components/public/cms/element/CmsElementCategoryNavigation.vue +53 -0
- package/{components → app/components}/public/cms/element/CmsElementCrossSelling.vue +3 -3
- package/{components → app/components}/public/cms/element/CmsElementImage.vue +52 -13
- package/app/components/public/cms/element/CmsElementImageGallery.vue +158 -0
- package/{components → app/components}/public/cms/element/CmsElementImageSlider.vue +2 -2
- package/{components → app/components}/public/cms/element/CmsElementProductBox.vue +2 -1
- package/app/components/public/cms/element/CmsElementProductDescriptionReviews.vue +217 -0
- package/{components → app/components}/public/cms/element/CmsElementProductListing.vue +23 -94
- package/app/components/public/cms/element/CmsElementProductName.vue +11 -0
- package/{components → app/components}/public/cms/element/CmsElementProductSlider.vue +4 -4
- package/{components → app/components}/public/cms/element/CmsElementText.vue +8 -2
- package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.vue +8 -2
- package/app/components/public/cms/element/SwProductListingPagination.vue +70 -0
- package/{components → app/components}/public/cms/section/CmsSectionDefault.vue +1 -1
- package/app/components/public/cms/section/CmsSectionSidebar.vue +36 -0
- package/app/components/public/cms/skeleton/ProductCardSkeleton.vue +28 -0
- package/app/components/ui/BaseButton.vue +99 -0
- package/app/components/ui/BaseIcon.vue +15 -0
- package/app/components/ui/Checkbox.vue +49 -0
- package/app/components/ui/CheckmarkIcon.vue +23 -0
- package/app/components/ui/ChevronIcon.vue +37 -0
- package/app/components/ui/ExclamationIcon.vue +11 -0
- package/app/components/ui/IconButton.vue +32 -0
- package/app/components/ui/RadioButton.vue +26 -0
- package/app/components/ui/StarIcon.vue +18 -0
- package/app/components/ui/SwitchButton.vue +100 -0
- package/app/components/ui/UserIcon.vue +11 -0
- package/app/components/ui/WishlistIcon.vue +20 -0
- package/app/composables/useImagePlaceholder.ts +27 -0
- package/{helpers → app/helpers}/clientOnly.ts +5 -0
- package/app/providers/shopware.test.ts +213 -0
- package/app/providers/shopware.ts +107 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.mjs +2 -2
- package/index.d.ts +12 -0
- package/nuxt.config.ts +80 -6
- package/package.json +29 -21
- package/uno.config.ts +83 -0
- package/components/SwCategoryNavigation.vue +0 -44
- package/components/SwCategoryNavigationLink.vue +0 -57
- package/components/SwListingProductPrice.vue +0 -89
- package/components/SwProductCard.vue +0 -286
- package/components/SwProductListingFilter.vue +0 -42
- package/components/SwProductListingFilters.vue +0 -292
- package/components/listing-filters/SwFilterPrice.vue +0 -160
- package/components/listing-filters/SwFilterProperties.vue +0 -123
- package/components/listing-filters/SwFilterRating.vue +0 -101
- package/components/listing-filters/SwFilterShippingFree.vue +0 -104
- package/components/public/cms/block/CmsBlockImageFourColumn.vue +0 -29
- package/components/public/cms/block/CmsBlockImageHighlightRow.vue +0 -27
- package/components/public/cms/block/CmsBlockImageTextGallery.vue +0 -85
- package/components/public/cms/block/CmsBlockImageTextRow.vue +0 -43
- package/components/public/cms/block/CmsBlockImageThreeCover.vue +0 -27
- package/components/public/cms/block/CmsBlockImageTwoColumn.vue +0 -25
- package/components/public/cms/block/CmsBlockTextOnImage.vue +0 -20
- package/components/public/cms/element/CmsBlockHtml.md +0 -1
- package/components/public/cms/element/CmsElementBuyBox.vue +0 -190
- package/components/public/cms/element/CmsElementCategoryNavigation.vue +0 -167
- package/components/public/cms/element/CmsElementImageGallery.vue +0 -249
- package/components/public/cms/element/CmsElementProductDescriptionReviews.vue +0 -123
- package/components/public/cms/element/CmsElementProductName.vue +0 -10
- package/components/public/cms/section/CmsSectionSidebar.vue +0 -49
- package/components/public/cms/skeleton/ProductCardSkeleton.vue +0 -44
- /package/{components → app/components}/SwMedia3D.vue +0 -0
- /package/{components → app/components}/SwProductGallery.vue +0 -0
- /package/{components → app/components}/SwProductPrice.vue +0 -0
- /package/{components → app/components}/SwProductUnits.vue +0 -0
- /package/{components → app/components}/SwSharedPrice.vue +0 -0
- /package/{components → app/components}/public/cms/CmsGenericBlock.md +0 -0
- /package/{components → app/components}/public/cms/CmsGenericBlock.vue +0 -0
- /package/{components → app/components}/public/cms/CmsGenericElement.md +0 -0
- /package/{components → app/components}/public/cms/CmsGenericElement.vue +0 -0
- /package/{components → app/components}/public/cms/CmsNoComponent.vue +0 -0
- /package/{components → app/components}/public/cms/CmsPage.md +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCategoryNavigation.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCenterText.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCrossSelling.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockCustomForm.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockDefault.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockForm.vue +0 -0
- /package/{components/public/cms/element → app/components/public/cms/block}/CmsBlockHtml.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImage.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImageCover.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImageGallery.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockImageSlider.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockProductDescriptionReviews.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockProductListing.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockProductSlider.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockText.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockTextHero.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockTextTeaser.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockTextThreeColumn.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockVimeoVideo.vue +0 -0
- /package/{components → app/components}/public/cms/block/CmsBlockYoutubeVideo.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementBuyBox.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCategoryNavigation.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCrossSelling.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCustomForm.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementCustomForm.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementForm.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementForm.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementHtml.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImage.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImageGallery.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImageGallery3dPlaceholder.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementImageSlider.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementManufacturerLogo.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductBox.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductDescriptionReviews.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductListing.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductName.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementProductSlider.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementSidebarFilter.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementText.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.md +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementVimeoVideo.vue +0 -0
- /package/{components → app/components}/public/cms/element/CmsElementYoutubeVideo.md +0 -0
- /package/{components → app/components}/public/cms/section/CmsSectionDefault.md +0 -0
- /package/{components → app/components}/public/cms/section/CmsSectionSidebar.md +0 -0
- /package/{helpers → app/helpers}/html-to-vue/ast.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.test.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/getOptionsFromNode.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/renderToHtml.ts +0 -0
- /package/{helpers → app/helpers}/html-to-vue/renderer.ts +0 -0
- /package/{helpers → app/helpers}/media/isSpatial.ts +0 -0
|
@@ -178,7 +178,7 @@ const invokeSubmit = async () => {
|
|
|
178
178
|
id="salutation"
|
|
179
179
|
v-model="state.salutationId"
|
|
180
180
|
name="salutation"
|
|
181
|
-
class="border-
|
|
181
|
+
class="border-outline-outline-variant focus:border-brand-primary appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
182
182
|
>
|
|
183
183
|
<option disabled selected value="">
|
|
184
184
|
{{ translations.form.salutationPlaceholder }}
|
|
@@ -200,20 +200,20 @@ const invokeSubmit = async () => {
|
|
|
200
200
|
name="first-name"
|
|
201
201
|
type="text"
|
|
202
202
|
autocomplete="given-name"
|
|
203
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
203
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
204
204
|
:class="[
|
|
205
205
|
$v.firstName.$error
|
|
206
206
|
? 'border-red-600 focus:border-red-600'
|
|
207
|
-
: 'border-
|
|
207
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
208
208
|
]"
|
|
209
209
|
:placeholder="translations.form.firstNamePlaceholder"
|
|
210
210
|
@blur="$v.firstName.$touch()"
|
|
211
211
|
/>
|
|
212
212
|
<span
|
|
213
|
-
v-if="$v.firstName.$error"
|
|
213
|
+
v-if="$v.firstName.$error && $v.firstName.$errors[0]?.$message"
|
|
214
214
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
215
215
|
>
|
|
216
|
-
{{ $v.firstName.$errors[0]
|
|
216
|
+
{{ $v.firstName.$errors[0].$message }}
|
|
217
217
|
</span>
|
|
218
218
|
</div>
|
|
219
219
|
<div class="col-span-4">
|
|
@@ -224,20 +224,20 @@ const invokeSubmit = async () => {
|
|
|
224
224
|
name="last-name"
|
|
225
225
|
type="text"
|
|
226
226
|
autocomplete="family-name"
|
|
227
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
227
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
228
228
|
:class="[
|
|
229
229
|
$v.lastName.$error
|
|
230
230
|
? 'border-red-600 focus:border-red-600'
|
|
231
|
-
: 'border-
|
|
231
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
232
232
|
]"
|
|
233
233
|
:placeholder="translations.form.lastNamePlaceholder"
|
|
234
234
|
@blur="$v.lastName.$touch()"
|
|
235
235
|
/>
|
|
236
236
|
<span
|
|
237
|
-
v-if="$v.lastName.$error"
|
|
237
|
+
v-if="$v.lastName.$error && $v.lastName.$errors[0]?.$message"
|
|
238
238
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
239
239
|
>
|
|
240
|
-
{{ $v.lastName.$errors[0]
|
|
240
|
+
{{ $v.lastName.$errors[0].$message }}
|
|
241
241
|
</span>
|
|
242
242
|
</div>
|
|
243
243
|
<div class="col-span-6">
|
|
@@ -251,17 +251,17 @@ const invokeSubmit = async () => {
|
|
|
251
251
|
:class="[
|
|
252
252
|
$v.email.$error
|
|
253
253
|
? 'border-red-600 focus:border-red-600'
|
|
254
|
-
: 'border-
|
|
254
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
255
255
|
]"
|
|
256
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
256
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
257
257
|
:placeholder="translations.form.emailPlaceholder"
|
|
258
258
|
@blur="$v.email.$touch()"
|
|
259
259
|
/>
|
|
260
260
|
<span
|
|
261
|
-
v-if="$v.email.$error"
|
|
261
|
+
v-if="$v.email.$error && $v.email.$errors[0]?.$message"
|
|
262
262
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
263
263
|
>
|
|
264
|
-
{{ $v.email.$errors[0]
|
|
264
|
+
{{ $v.email.$errors[0].$message }}
|
|
265
265
|
</span>
|
|
266
266
|
</div>
|
|
267
267
|
<div class="col-span-6">
|
|
@@ -272,20 +272,20 @@ const invokeSubmit = async () => {
|
|
|
272
272
|
name="phone"
|
|
273
273
|
type="text"
|
|
274
274
|
autocomplete="phone"
|
|
275
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
275
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
276
276
|
:class="[
|
|
277
277
|
$v.phone.$error
|
|
278
278
|
? 'border-red-600 focus:border-red-600'
|
|
279
|
-
: 'border-
|
|
279
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
280
280
|
]"
|
|
281
281
|
:placeholder="translations.form.phonePlaceholder"
|
|
282
282
|
@blur="$v.phone.$touch()"
|
|
283
283
|
/>
|
|
284
284
|
<span
|
|
285
|
-
v-if="$v.phone.$error"
|
|
285
|
+
v-if="$v.phone.$error && $v.phone.$errors[0]?.$message"
|
|
286
286
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
287
287
|
>
|
|
288
|
-
{{ $v.phone.$errors[0]
|
|
288
|
+
{{ $v.phone.$errors[0].$message }}
|
|
289
289
|
</span>
|
|
290
290
|
</div>
|
|
291
291
|
<div class="col-span-12">
|
|
@@ -296,20 +296,20 @@ const invokeSubmit = async () => {
|
|
|
296
296
|
name="subject"
|
|
297
297
|
type="text"
|
|
298
298
|
autocomplete="subject"
|
|
299
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
299
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
300
300
|
:class="[
|
|
301
301
|
$v.subject.$error
|
|
302
302
|
? 'border-red-600 focus:border-red-600'
|
|
303
|
-
: 'border-
|
|
303
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
304
304
|
]"
|
|
305
305
|
:placeholder="translations.form.subjectPlaceholder"
|
|
306
306
|
@blur="$v.subject.$touch()"
|
|
307
307
|
/>
|
|
308
308
|
<span
|
|
309
|
-
v-if="$v.subject.$error"
|
|
309
|
+
v-if="$v.subject.$error && $v.subject.$errors[0]?.$message"
|
|
310
310
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
311
311
|
>
|
|
312
|
-
{{ $v.subject.$errors[0]
|
|
312
|
+
{{ $v.subject.$errors[0].$message }}
|
|
313
313
|
</span>
|
|
314
314
|
</div>
|
|
315
315
|
<div class="col-span-12">
|
|
@@ -320,21 +320,21 @@ const invokeSubmit = async () => {
|
|
|
320
320
|
name="comment"
|
|
321
321
|
type="text"
|
|
322
322
|
autocomplete="comment"
|
|
323
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
323
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
324
324
|
:class="[
|
|
325
325
|
$v.comment.$error
|
|
326
326
|
? 'border-red-600 focus:border-red-600'
|
|
327
|
-
: 'border-
|
|
327
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
328
328
|
]"
|
|
329
329
|
:placeholder="translations.form.commentPlaceholder"
|
|
330
330
|
rows="5"
|
|
331
331
|
@blur="$v.comment.$touch()"
|
|
332
332
|
/>
|
|
333
333
|
<span
|
|
334
|
-
v-if="$v.comment.$error"
|
|
334
|
+
v-if="$v.comment.$error && $v.comment.$errors[0]?.$message"
|
|
335
335
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
336
336
|
>
|
|
337
|
-
{{ $v.comment.$errors[0]
|
|
337
|
+
{{ $v.comment.$errors[0].$message }}
|
|
338
338
|
</span>
|
|
339
339
|
</div>
|
|
340
340
|
<div class="col-span-12">
|
|
@@ -345,7 +345,7 @@ const invokeSubmit = async () => {
|
|
|
345
345
|
v-model="state.checkbox"
|
|
346
346
|
name="privacy"
|
|
347
347
|
type="checkbox"
|
|
348
|
-
class="mt-1 focus:ring-
|
|
348
|
+
class="mt-1 focus:ring-brand-primary h-4 w-4 border text-brand-primary rounded"
|
|
349
349
|
:class="[
|
|
350
350
|
$v.checkbox.$error ? 'border-red-600' : 'border-gray-300',
|
|
351
351
|
]"
|
|
@@ -363,7 +363,7 @@ const invokeSubmit = async () => {
|
|
|
363
363
|
</div>
|
|
364
364
|
<div class="flex justify-end mt-10">
|
|
365
365
|
<button
|
|
366
|
-
class="group relative flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-
|
|
366
|
+
class="group relative flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-brand-primary hover:bg-brand-primary-hover focus:outline-none focus:ring-2 focus:ring-brand-primary disabled:opacity-75"
|
|
367
367
|
type="submit"
|
|
368
368
|
>
|
|
369
369
|
{{ translations.form.submit }}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed } from "vue";
|
|
3
|
+
import type { Schemas } from "#shopware";
|
|
4
|
+
|
|
5
|
+
type FilterState = {
|
|
6
|
+
manufacturer: Set<string>;
|
|
7
|
+
properties: Set<string>;
|
|
8
|
+
"min-price": number | undefined;
|
|
9
|
+
"max-price": number | undefined;
|
|
10
|
+
rating: number | undefined;
|
|
11
|
+
"shipping-free": boolean | undefined;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type Filter = {
|
|
15
|
+
id: string;
|
|
16
|
+
code: string;
|
|
17
|
+
options?: Array<
|
|
18
|
+
| Schemas["PropertyGroupOption"]
|
|
19
|
+
| { id: string; translated?: { name?: string } }
|
|
20
|
+
>;
|
|
21
|
+
entities?: Array<
|
|
22
|
+
| Schemas["ProductManufacturer"]
|
|
23
|
+
| { id: string; translated?: { name?: string } }
|
|
24
|
+
>;
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const props = defineProps<{
|
|
28
|
+
filters: FilterState;
|
|
29
|
+
availableFilters: Filter[];
|
|
30
|
+
}>();
|
|
31
|
+
|
|
32
|
+
const emit = defineEmits<{
|
|
33
|
+
remove: [{ code: string; value: string | number }];
|
|
34
|
+
}>();
|
|
35
|
+
|
|
36
|
+
const getTranslatedName = (
|
|
37
|
+
item: { translated?: { name?: string }; name?: string } | undefined,
|
|
38
|
+
): string | null => {
|
|
39
|
+
if (!item) return null;
|
|
40
|
+
if ("translated" in item) {
|
|
41
|
+
return item.translated?.name || ("name" in item ? item.name : null) || null;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const activeChips = computed(() => {
|
|
47
|
+
const chips: Array<{ label: string; code: string; value: string | number }> =
|
|
48
|
+
[];
|
|
49
|
+
|
|
50
|
+
// Add property filters
|
|
51
|
+
const properties = Array.from(props.filters.properties);
|
|
52
|
+
for (const propertyId of properties) {
|
|
53
|
+
// Check all filters, not just the one with code "properties"
|
|
54
|
+
// because properties can be in multiple filter groups
|
|
55
|
+
for (const filter of props.availableFilters) {
|
|
56
|
+
if ("options" in filter && filter.options) {
|
|
57
|
+
const option = filter.options.find((o) => o.id === propertyId);
|
|
58
|
+
const name = getTranslatedName(option);
|
|
59
|
+
if (name) {
|
|
60
|
+
chips.push({
|
|
61
|
+
label: name,
|
|
62
|
+
code: "properties",
|
|
63
|
+
value: propertyId,
|
|
64
|
+
});
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Add manufacturer filters
|
|
72
|
+
const manufacturers = Array.from(props.filters.manufacturer);
|
|
73
|
+
for (const manufacturerId of manufacturers) {
|
|
74
|
+
const filter = props.availableFilters.find(
|
|
75
|
+
(f) => f.code === "manufacturer",
|
|
76
|
+
);
|
|
77
|
+
if (filter && "entities" in filter && filter.entities) {
|
|
78
|
+
const entity = filter.entities.find((e) => e.id === manufacturerId);
|
|
79
|
+
const name = getTranslatedName(entity);
|
|
80
|
+
if (name) {
|
|
81
|
+
chips.push({
|
|
82
|
+
label: name,
|
|
83
|
+
code: "manufacturer",
|
|
84
|
+
value: manufacturerId,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Add price filters
|
|
91
|
+
if (props.filters["min-price"] || props.filters["max-price"]) {
|
|
92
|
+
const min = props.filters["min-price"] || 0;
|
|
93
|
+
const max = props.filters["max-price"] || "∞";
|
|
94
|
+
chips.push({
|
|
95
|
+
label: `Price: ${min} - ${max}`,
|
|
96
|
+
code: "price",
|
|
97
|
+
value: "price-range",
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Add rating filter
|
|
102
|
+
if (props.filters.rating) {
|
|
103
|
+
chips.push({
|
|
104
|
+
label: `Rating: ${props.filters.rating}★`,
|
|
105
|
+
code: "rating",
|
|
106
|
+
value: props.filters.rating,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// Add shipping free filter
|
|
111
|
+
if (props.filters["shipping-free"]) {
|
|
112
|
+
chips.push({
|
|
113
|
+
label: "Free Shipping",
|
|
114
|
+
code: "shipping-free",
|
|
115
|
+
value: "true",
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return chips;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const handleRemoveChip = (chip: { code: string; value: string | number }) => {
|
|
123
|
+
emit("remove", chip);
|
|
124
|
+
};
|
|
125
|
+
</script>
|
|
126
|
+
|
|
127
|
+
<template>
|
|
128
|
+
<div
|
|
129
|
+
v-if="activeChips.length > 0"
|
|
130
|
+
class="self-stretch inline-flex justify-start items-center gap-4 flex-wrap content-center mb-6"
|
|
131
|
+
>
|
|
132
|
+
<button
|
|
133
|
+
v-for="(chip, index) in activeChips"
|
|
134
|
+
:key="`${chip.code}-${chip.value}-${index}`"
|
|
135
|
+
@click="handleRemoveChip(chip)"
|
|
136
|
+
class="px-4 py-1.5 bg-brand-tertiary rounded-full inline-flex justify-center items-center gap-1 hover:bg-brand-tertiary-hover transition-colors"
|
|
137
|
+
>
|
|
138
|
+
<span class="text-brand-on-tertiary text-base font-normal leading-normal">
|
|
139
|
+
{{ chip.label }}
|
|
140
|
+
</span>
|
|
141
|
+
<span class="i-carbon-close w-5 h-5 text-brand-on-tertiary"></span>
|
|
142
|
+
</button>
|
|
143
|
+
</div>
|
|
144
|
+
</template>
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { useCmsTranslations, useProductPrice } from "@shopware/composables";
|
|
3
|
+
import { defu } from "defu";
|
|
4
|
+
import { toRefs } from "vue";
|
|
5
|
+
import type { Schemas } from "#shopware";
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
product: Schemas["Product"];
|
|
9
|
+
}>();
|
|
10
|
+
|
|
11
|
+
type Translations = {
|
|
12
|
+
listing: {
|
|
13
|
+
variantsFrom: string;
|
|
14
|
+
previously: string;
|
|
15
|
+
from: string;
|
|
16
|
+
to: string;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
let translations: Translations = {
|
|
21
|
+
listing: {
|
|
22
|
+
variantsFrom: "variants from",
|
|
23
|
+
previously: "previously",
|
|
24
|
+
from: "from",
|
|
25
|
+
to: "to",
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
translations = defu(useCmsTranslations(), translations) as Translations;
|
|
30
|
+
|
|
31
|
+
const { product } = toRefs(props);
|
|
32
|
+
|
|
33
|
+
const {
|
|
34
|
+
price,
|
|
35
|
+
unitPrice,
|
|
36
|
+
displayFromVariants,
|
|
37
|
+
displayFrom,
|
|
38
|
+
isListPrice,
|
|
39
|
+
regulationPrice,
|
|
40
|
+
} = useProductPrice(product);
|
|
41
|
+
</script>
|
|
42
|
+
|
|
43
|
+
<template>
|
|
44
|
+
<div :id="product.id" class="inline-flex justify-start items-center gap-2">
|
|
45
|
+
<!-- Sale price display -->
|
|
46
|
+
<div v-if="isListPrice" class="flex items-center gap-2">
|
|
47
|
+
<div class="text-base font-bold leading-normal">
|
|
48
|
+
<SwSharedPrice :value="unitPrice">
|
|
49
|
+
<template #beforePrice>
|
|
50
|
+
<span v-if="displayFrom || displayFromVariants" class="text-sm">{{
|
|
51
|
+
translations.listing.from
|
|
52
|
+
}}</span>
|
|
53
|
+
</template>
|
|
54
|
+
</SwSharedPrice>
|
|
55
|
+
</div>
|
|
56
|
+
<div class="text-surface-on-surface-variant text-sm font-normal leading-tight line-through">
|
|
57
|
+
<SwSharedPrice :value="price?.listPrice?.price" />
|
|
58
|
+
</div>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<!-- Regular price display -->
|
|
62
|
+
<div v-else class="text-surface-on-surface text-base font-bold leading-normal">
|
|
63
|
+
<SwSharedPrice :value="unitPrice">
|
|
64
|
+
<template #beforePrice>
|
|
65
|
+
<span v-if="displayFrom || displayFromVariants" class="text-sm">{{
|
|
66
|
+
translations.listing.from
|
|
67
|
+
}}</span>
|
|
68
|
+
</template>
|
|
69
|
+
</SwSharedPrice>
|
|
70
|
+
</div>
|
|
71
|
+
|
|
72
|
+
<!-- Variants from price -->
|
|
73
|
+
<div v-if="displayFromVariants" class="text-surface-on-surface text-base font-bold leading-normal">
|
|
74
|
+
<SwSharedPrice :value="displayFromVariants">
|
|
75
|
+
<template #beforePrice>
|
|
76
|
+
<span v-if="displayFromVariants" class="text-sm">{{
|
|
77
|
+
translations.listing.variantsFrom
|
|
78
|
+
}}</span>
|
|
79
|
+
</template>
|
|
80
|
+
</SwSharedPrice>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<!-- Regulation price -->
|
|
84
|
+
<div v-if="regulationPrice" class="flex gap-2 text-surface-on-surface-variant text-sm">
|
|
85
|
+
{{ translations.listing.previously }}
|
|
86
|
+
<SwSharedPrice :value="regulationPrice" />
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
@@ -78,8 +78,18 @@ const { getConfigValue } = useCmsElementConfig(props.content);
|
|
|
78
78
|
const { newsletterSubscribe, newsletterUnsubscribe } = useNewsletter();
|
|
79
79
|
|
|
80
80
|
const getFormTitle = computed(() => getConfigValue("title"));
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
|
|
82
|
+
type NewsletterFormState = {
|
|
83
|
+
option: "subscribe" | "unsubscribe";
|
|
84
|
+
salutationId: string;
|
|
85
|
+
firstName: string;
|
|
86
|
+
lastName: string;
|
|
87
|
+
email: string;
|
|
88
|
+
checkbox: boolean;
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const state = reactive<NewsletterFormState>({
|
|
92
|
+
option: subscriptionOptions[0]?.value ?? "subscribe",
|
|
83
93
|
salutationId: "",
|
|
84
94
|
firstName: "",
|
|
85
95
|
lastName: "",
|
|
@@ -87,7 +97,7 @@ const state = reactive({
|
|
|
87
97
|
checkbox: false,
|
|
88
98
|
});
|
|
89
99
|
|
|
90
|
-
type
|
|
100
|
+
type RequiredRules = {
|
|
91
101
|
email: {
|
|
92
102
|
required: ValidationRuleWithoutParams;
|
|
93
103
|
email: ValidationRuleWithoutParams;
|
|
@@ -96,6 +106,9 @@ type Rules = {
|
|
|
96
106
|
required: ValidationRuleWithoutParams;
|
|
97
107
|
isTrue: (value: boolean) => boolean;
|
|
98
108
|
};
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
type OptionalRules = {
|
|
99
112
|
firstName: {
|
|
100
113
|
required: ValidationRuleWithoutParams;
|
|
101
114
|
minLength: number;
|
|
@@ -105,8 +118,9 @@ type Rules = {
|
|
|
105
118
|
minLength: number;
|
|
106
119
|
};
|
|
107
120
|
};
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
|
|
122
|
+
const rules = computed((): RequiredRules & Partial<OptionalRules> => {
|
|
123
|
+
const temp: RequiredRules & Partial<OptionalRules> = {
|
|
110
124
|
email: {
|
|
111
125
|
required,
|
|
112
126
|
email,
|
|
@@ -117,16 +131,13 @@ const rules = computed(() => {
|
|
|
117
131
|
},
|
|
118
132
|
};
|
|
119
133
|
if (state.option === "subscribe") {
|
|
120
|
-
temp = {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
required,
|
|
128
|
-
minLength: 3,
|
|
129
|
-
},
|
|
134
|
+
temp.firstName = {
|
|
135
|
+
required,
|
|
136
|
+
minLength: 3,
|
|
137
|
+
};
|
|
138
|
+
temp.lastName = {
|
|
139
|
+
required,
|
|
140
|
+
minLength: 3,
|
|
130
141
|
};
|
|
131
142
|
}
|
|
132
143
|
return temp;
|
|
@@ -184,7 +195,7 @@ const invokeSubmit = async () => {
|
|
|
184
195
|
id="option"
|
|
185
196
|
v-model="state.option"
|
|
186
197
|
name="option"
|
|
187
|
-
class="appearance-none relative block w-full px-3 py-2 border border-
|
|
198
|
+
class="appearance-none relative block w-full px-3 py-2 border border-outline-outline-variant placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:border-brand-primary focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
188
199
|
>
|
|
189
200
|
<option
|
|
190
201
|
v-for="subscription in subscriptionOptions"
|
|
@@ -204,19 +215,19 @@ const invokeSubmit = async () => {
|
|
|
204
215
|
type="email"
|
|
205
216
|
autocomplete="email"
|
|
206
217
|
:class="[
|
|
207
|
-
$v.email
|
|
218
|
+
$v.email.$error
|
|
208
219
|
? 'border-red-600 focus:border-red-600'
|
|
209
|
-
: 'border-
|
|
220
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
210
221
|
]"
|
|
211
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
222
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
212
223
|
:placeholder="translations.form.emailPlaceholder"
|
|
213
|
-
@blur="$v.email
|
|
224
|
+
@blur="$v.email.$touch()"
|
|
214
225
|
/>
|
|
215
226
|
<span
|
|
216
|
-
v-if="$v.email?.$
|
|
227
|
+
v-if="$v.email.$error && $v.email.$errors[0]?.$message"
|
|
217
228
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
218
229
|
>
|
|
219
|
-
{{ $v.email
|
|
230
|
+
{{ $v.email.$errors[0].$message }}
|
|
220
231
|
</span>
|
|
221
232
|
</div>
|
|
222
233
|
<div v-if="state.option === 'subscribe'" class="col-span-4">
|
|
@@ -225,7 +236,7 @@ const invokeSubmit = async () => {
|
|
|
225
236
|
id="salutation"
|
|
226
237
|
v-model="state.salutationId"
|
|
227
238
|
name="salutation"
|
|
228
|
-
class=" border-
|
|
239
|
+
class=" border-outline-outline-variant focus:border-brand-primaryappearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
229
240
|
>
|
|
230
241
|
<option disabled selected value="">
|
|
231
242
|
{{ translations.form.salutationPlaceholder }}
|
|
@@ -247,20 +258,20 @@ const invokeSubmit = async () => {
|
|
|
247
258
|
name="first-name"
|
|
248
259
|
type="text"
|
|
249
260
|
autocomplete="given-name"
|
|
250
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
261
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
251
262
|
:class="[
|
|
252
263
|
$v.firstName?.$error
|
|
253
|
-
|
|
254
|
-
|
|
264
|
+
? 'border-red-600 focus:border-red-600'
|
|
265
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
255
266
|
]"
|
|
256
267
|
:placeholder="translations.form.firstNamePlaceholder"
|
|
257
268
|
@blur="$v.firstName?.$touch()"
|
|
258
269
|
/>
|
|
259
270
|
<span
|
|
260
|
-
v-if="$v.firstName?.$error"
|
|
271
|
+
v-if="$v.firstName?.$error && $v.firstName?.$errors[0]?.$message"
|
|
261
272
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
262
273
|
>
|
|
263
|
-
{{ $v.firstName?.$errors[0]
|
|
274
|
+
{{ $v.firstName?.$errors[0].$message }}
|
|
264
275
|
</span>
|
|
265
276
|
</div>
|
|
266
277
|
<div v-if="state.option === 'subscribe'" class="col-span-4">
|
|
@@ -271,20 +282,20 @@ const invokeSubmit = async () => {
|
|
|
271
282
|
name="last-name"
|
|
272
283
|
type="text"
|
|
273
284
|
autocomplete="family-name"
|
|
274
|
-
class="appearance-none relative block w-full px-3 py-2 border placeholder-
|
|
285
|
+
class="appearance-none relative block w-full px-3 py-2 border placeholder-surface-on-surface-variant text-surface-on-surface rounded-md focus:outline-none focus:ring-brand-primary focus:z-10 sm:text-sm"
|
|
275
286
|
:class="[
|
|
276
287
|
$v.lastName?.$error
|
|
277
288
|
? 'border-red-600 focus:border-red-600'
|
|
278
|
-
: 'border-
|
|
289
|
+
: 'border-outline-outline-variant focus:border-brand-primary',
|
|
279
290
|
]"
|
|
280
291
|
:placeholder="translations.form.lastNamePlaceholder"
|
|
281
292
|
@blur="$v.lastName?.$touch()"
|
|
282
293
|
/>
|
|
283
294
|
<span
|
|
284
|
-
v-if="$v.lastName?.$error"
|
|
295
|
+
v-if="$v.lastName?.$error && $v.lastName?.$errors[0]?.$message"
|
|
285
296
|
class="pt-1 text-sm text-red-600 focus:ring-brand-primary border-gray-300"
|
|
286
297
|
>
|
|
287
|
-
{{ $v.lastName?.$errors[0]
|
|
298
|
+
{{ $v.lastName?.$errors[0].$message }}
|
|
288
299
|
</span>
|
|
289
300
|
</div>
|
|
290
301
|
<div class="col-span-12">
|
|
@@ -295,7 +306,7 @@ const invokeSubmit = async () => {
|
|
|
295
306
|
v-model="state.checkbox"
|
|
296
307
|
name="privacy"
|
|
297
308
|
type="checkbox"
|
|
298
|
-
class="mt-1 focus:ring-
|
|
309
|
+
class="mt-1 focus:ring-brand-primary h-4 w-4 border text-brand-primary rounded"
|
|
299
310
|
:class="[
|
|
300
311
|
$v.checkbox?.$error ? 'border-red-600' : 'border-gray-300',
|
|
301
312
|
]"
|
|
@@ -313,7 +324,7 @@ const invokeSubmit = async () => {
|
|
|
313
324
|
</div>
|
|
314
325
|
<div class="flex justify-end mt-10">
|
|
315
326
|
<button
|
|
316
|
-
class="group relative flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-
|
|
327
|
+
class="group relative flex justify-center py-2 px-4 border border-transparent text-sm font-medium rounded-md text-white bg-brand-primary hover:bg-brand-primary-hover focus:outline-none focus:ring-2 focus:ring-brand-primary disabled:opacity-75"
|
|
317
328
|
type="submit"
|
|
318
329
|
>
|
|
319
330
|
{{ translations.form.submit }}
|
|
@@ -36,8 +36,7 @@ defineEmits<(e: "changePage", page: number) => void>();
|
|
|
36
36
|
@click="$emit('changePage', current - 1)"
|
|
37
37
|
>
|
|
38
38
|
<span class="sr-only">{{ translations.listing.previous }}</span>
|
|
39
|
-
|
|
40
|
-
<div class="w-5 h-5 i-carbon-chevron-left" />
|
|
39
|
+
<SwChevronIcon direction="left" :size="20" />
|
|
41
40
|
</button>
|
|
42
41
|
<button
|
|
43
42
|
v-if="current > 2"
|
|
@@ -62,7 +61,7 @@ defineEmits<(e: "changePage", page: number) => void>();
|
|
|
62
61
|
</button>
|
|
63
62
|
<button
|
|
64
63
|
aria-current="page"
|
|
65
|
-
class="bg-
|
|
64
|
+
class="bg-surface-surface-primary border-brand-primary text-brand-primary relative inline-flex items-center px-4 py-2 border text-sm font-medium"
|
|
66
65
|
:class="[
|
|
67
66
|
current - 1 >= 1 ? '' : 'rounded-l-md border border-secondary-300',
|
|
68
67
|
total == current ? 'rounded-r-md border border-secondary-300' : '',
|
|
@@ -99,8 +98,7 @@ defineEmits<(e: "changePage", page: number) => void>();
|
|
|
99
98
|
@click="$emit('changePage', current + 1)"
|
|
100
99
|
>
|
|
101
100
|
<span class="sr-only">{{ translations.listing.next }}</span>
|
|
102
|
-
|
|
103
|
-
<div class="w-5 h-5 i-carbon-chevron-right" />
|
|
101
|
+
<SwChevronIcon direction="right" :size="20" />
|
|
104
102
|
</button>
|
|
105
103
|
</nav>
|
|
106
104
|
</template>
|