Vue Draggable clone into another list via custom component - javascript

I'm working in a Nuxt JS 2.x project that has Vue Draggable 2.24.3
I have a page where I have two draggable lists as part of a custom component called DraggableList
My DraggableList component is the one that contains the draggable component from Vue Draggable and I've created some options to pass to it.
I can drag my items fine in one list, but cannot seem to drag items into another, what could I be missing?
Here's my markup for the page containing my elements:
<b-row class="mt-2">
<b-col cols="12" lg="6">
<b-card class="shadow" bg-variant="light">
<b-card-title class="mb-1">Assigned tiers</b-card-title>
<b-card-sub-title>The buyer tiers</b-card-sub-title>
<article class="mt-2 p-3 border bg-light rounded">
<DraggableList
:draggable-group-options="{ name: 'tiers', pull: 'clone', revertClone: true, put: false }"
:items="form.tiers" />
</article>
</b-card>
</b-col>
<b-col cols="12" lg="6">
<b-card bg-variant="light">
<b-card-title class="mb-1">Available tiers</b-card-title>
<b-card-sub-title>Assigned tiers</b-card-sub-title>
<section v-if="isLoading" class="bg-white p-3 mt-2">
<AppLoader
loader-title="Getting buyer tiers"
:is-loading="isLoading" />
</section>
<section v-else class="rounded-sm border p-3 mt-2">
<EmptyData
v-if="!buyers"
class="p-3"
state-title="No tiers for buyer"
state-subtitle="Get started by creating a tier">
<template #actions>
<b-button variant="primary" to="/buyers/" class="shadow mt-2">
Go to buyers
</b-button>
</template>
</EmptyData>
<article v-else class="mt-2 bg-light rounded">
<DraggableList
:draggable-group-options="{ name: 'tiers' }"
:items="buyers" />
</article>
</section>
</b-card>
</b-col>
</b-row>
and my DraggableList component:
<template>
<draggable
:list="items"
:group="draggableGroupOptions"
handle=".handle"
#change="onChange"
>
<article v-for="(item, index) in items" :key="item.id" class="draggable-group">
<section class="d-flex mb-2">
<div class="draggable-item w-100 rounded border-transparent">
<div class="d-flex align-items-center justify-content-between p-2">
<div class="ml-1">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" width="16" stroke-width="2" stroke="currentColor" class="handle cursor-move" :class="{ 'mr-1': !item.icon_markup }">
<path stroke-linecap="round" stroke-linejoin="round" d="M3 7.5L7.5 3m0 0L12 7.5M7.5 3v13.5m13.5 0L16.5 21m0 0L12 16.5m4.5 4.5V7.5" />
</svg>
<span>{{ item.name }}</span>
</div>
</div>
</div>
<div class="d-flex align-items-start ml-1 mute">
<b-dropdown variant="link" toggle-class="text-decoration-none p-0 text-dark mt-2" menu-class="shadow-lg" right no-caret>
<template #button-content>
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="24">
<path stroke-linecap="round" stroke-linejoin="round" d="M12 6.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 12.75a.75.75 0 110-1.5.75.75 0 010 1.5zM12 18.75a.75.75 0 110-1.5.75.75 0 010 1.5z" />
</svg>
</template>
<b-dropdown-header>
Options
</b-dropdown-header>
<b-dropdown-item-button>
<div class="d-flex align-items-center w-100">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" width="16" class="text-primary flex-shrink-0 rotate-180 mr-1">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 15L3 9m0 0l6-6M3 9h12a6 6 0 010 12h-3" />
</svg>
Toggle children
</div>
</b-dropdown-item-button>
</b-dropdown>
</div>
</section>
</article>
</draggable>
</template>
<script>
export default {
props: {
items: {
default: [],
type: Array
},
draggableGroupOptions: {
default: () => ({ }),
type: Object
},
itemId: {
type: [String, Number],
default: '',
},
},
methods: {
/*
** On change of a draggable item
*/
onChange (evt) {
console.log(evt)
},
/*
** Send the trashed item id to root
*/
sendTrashedItemToRoot (value) {
this.$emit('onDeleteItem', value)
}
}
}
</script>
The UI looks like:
I'm trying to drag from the right list, to the left.

My mistake, looks like I'm trying to clone from the wrong list.

Related

custom colors not showing in tailwindcss v3 installed via npm

I am using a tailwind cssv3 installed via NPM and I changed my tailwind.config.js to
module.exports = {
content: ["./*html"],
theme: {
colors: {
transparent: 'transparent',
current: 'currentColor',
'myblack': '#ffffff',
'myblack': '#000000',
'myorange': '#FF7E00',
'mygray': '#A8A8A8',
'mywhiteuse1': '#F1EBEB',
'mywhiteuse2': '#E9E9E9',
'myaction': '#B31717',
'myneutral1': '#A8DFBB',
'myneutral2': '#93BF97',
},
},
plugins: [],
}
and I changed this code from
<div class="flex flex-wrap lg:w-4/5 sm:mx-auto sm:mb-2 -mx-2">
<div class="p-2 sm:w-1/2 w-full ">
<div
class="bg-orange-400 rounded flex p-4 h-full items-centertransition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="3"
class="text-gray-500 w-6 h-6 flex-shrink-0 mr-4" viewBox="0 0 24 24">
<path d="M22 11.08V12a10 10 0 11-5.93-9.14"></path>
<path d="M22 4L12 14.01l-3-3"></path>
</svg>
<span class="title-font font-medium text-gray-600">Attendance management</span>
</div>
</div>
</div>
to
<div class="flex flex-wrap lg:w-4/5 sm:mx-auto sm:mb-2 -mx-2">
<div class="p-2 sm:w-1/2 w-full ">
<div
class="bg-orange-400 rounded flex p-4 h-full items-centertransition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="3" class="text-gray-500 w-6 h-6 flex-shrink-0 mr-4"
viewBox="0 0 24 24">
<path d="M22 11.08V12a10 10 0 11-5.93-9.14"></path>
<path d="M22 4L12 14.01l-3-3"></path>
</svg>
<span class="title-font font-medium text-mywhiteuse1">Attendance management</span>
</div>
</div>
</div>
and the text color is not changing I tried every method in this tailwindcss official documentation link:https://tailwindcss.com/docs/customizing-colors and still no method is working please help me
You can directly use any custom color like this text-[#F1EBEB]
<span class="title-font font-medium text-[#F1EBEB]">Attendance management</span>
This is the complete code
<script src="https://cdn.tailwindcss.com"></script>
<div class="flex flex-wrap lg:w-4/5 sm:mx-auto sm:mb-2 -mx-2">
<div class="p-2 sm:w-1/2 w-full ">
<div
class="bg-orange-400 rounded flex p-4 h-full items-centertransition ease-in-out delay-150 hover:-translate-y-1 hover:scale-110 duration-300">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"
stroke-width="3" class="text-gray-500 w-6 h-6 flex-shrink-0 mr-4"
viewBox="0 0 24 24">
<path d="M22 11.08V12a10 10 0 11-5.93-9.14"></path>
<path d="M22 4L12 14.01l-3-3"></path>
</svg>
<span class="title-font font-medium text-[#F1EBEB]">Attendance management</span>
</div>
</div>
</div>

Multiselect deselect default values in child component

I'm trying to use this multi-select component as a child component in a Edit.vue component (parent)
Parent component
<template>
<Multiselect v-model="form.user_id" :options="users"></Multiselect>
</template>
<script setup>
const props = defineProps({
users: Array,
activity: Object
});
const form = useForm({
user_id: props.activity.users
});
</script>
Child component
<template>
<Listbox v-model="selected" name="people">
<ListboxLabel class="block text-sm font-medium leading-5 text-gray-700"> Assigned to </ListboxLabel>
<div class="relative">
<span class="inline-block w-full rounded-md shadow-sm">
<ListboxButton
class="focus:shadow-outline-blue relative w-full cursor-default rounded-md border border-gray-300 bg-white py-2 pl-2 pr-10 text-left transition duration-150 ease-in-out focus:border-blue-300 focus:outline-none sm:text-sm sm:leading-5">
<span class="block flex flex-wrap gap-2">
<span v-if="selected.length === 0" class="p-0.5">Empty</span>
<span v-for="option in selected" :key="option.id" class="flex items-center gap-1 rounded bg-blue-50 px-2 py-0.5">
<span>{{ option.name }}</span>
<svg class="h-4 w-4 cursor-pointer" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" #click="removePerson(option)">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</span>
</span>
<span class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2">
<svg class="h-5 w-5 text-gray-400" viewBox="0 0 20 20" fill="none" stroke="currentColor">
<path d="M7 7l3-3 3 3m0 6l-3 3-3-3" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" />
</svg>
</span>
</ListboxButton>
</span>
<div class="absolute mt-1 w-full rounded-md bg-white shadow-lg">
<ListboxOptions class="shadow-xs max-h-60 overflow-auto rounded-md py-1 text-base leading-6 focus:outline-none sm:text-sm sm:leading-5">
<ListboxOption v-for="option in options" :key="option.id" :value="option" as="template" v-slot="{ active, selected }">
<li class="relative cursor-default select-none py-2 pl-3 pr-9 focus:outline-none" :class="active ? 'bg-indigo-600 text-white' : 'text-gray-900'">
<span class="block truncate" :class="{ 'font-semibold': selected, 'font-normal': !selected }">
{{ option.name }}
</span>
<span v-if="selected" class="absolute inset-y-0 right-0 flex items-center pr-4" :class="{ 'text-white': active, 'text-indigo-600': !active }">
<svg class="h-5 w-5" viewBox="0 0 20 20" fill="currentColor">
<path
fillRule="evenodd"
d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z"
clipRule="evenodd" />
</svg>
</span>
</li>
</ListboxOption>
</ListboxOptions>
</div>
</div>
</Listbox>
</template>
<script setup>
import { ref } from 'vue';
import { Listbox, ListboxLabel, ListboxButton, ListboxOptions, ListboxOption } from '#headlessui/vue';
import {computed} from "vue";
const props = defineProps({
options: Array,
modelValue: Array
});
//
const emit = defineEmits(['update:modelValue'])
const selectedOption = ref(props.modelValue);
const selected = computed({
get: () => selectedOption.value,
set: v => {
selectedOption.value = v;
emit('update:modelValue', v.id)
}
});
//
function classNames(...classes) {
return classes.filter(Boolean).join(' ');
}
function removePerson() {
e.stopPropagation();
e.preventDefault();
selectedOption.value = selectedOption.value.filter(p => p !== option);
}
</script>
I want the options in the props.activity.user selected by default in the child component. The values gets passed but when I deselect an option it gets added instead. And non-default values gets deselected
e.g.
The user Emi Webb gets added instead of deselected 'cause it's a default value
I'm stick trying to get this to work

Updating tailwindCSS class attributes on button click

I'm working on a project that uses pre-made TailwindUI component code. If you refer to this gif, you can see that the code on the site is responsive to mobile design and the hamburger menu toggles on button click.
However, the code given for this does not include the necessary JS, so the toggling of the hamburger menu does not work.
I am trying to fix this, this is what i've done so far:
I've wrapped the flyout menu code in a div and gave it an id 'mobile-menu' and a state of 'hidden'. Inside this menu is the X button, which i gave an id 'menu-toggle' since i want this button and the hamburger button to toggle the flyout menu. Below is not the whole code but just the relevant parts
<div class="absolute z-30 top-0 inset-x-0 p-2 transition transform origin-top-right md:hidden">
<div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div class="pt-5 pb-6 px-5">
<div class="flex items-center justify-between">
<div>
<img class="h-8 w-auto" src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg" alt="Workflow">
</div>
<div class="-mr-2">
<button id="menu-toggle" onclick="" type="button" class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<span class="sr-only">Close menu</span>
<!-- Heroicon name: outline/x -->
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
Outside of this div and elsewhere in the code is the hamburger menu button, which i also gave an id 'menu-toggle'
<div class="-mr-2 -my-2 md:hidden">
<button id="menu-toggle" type="button" class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" aria-expanded="false">
<span class="sr-only">Open menu</span>
<!-- Heroicon name: outline/menu -->
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
Finally i've added a script tag to the whole .html file (the file does not contain HTML boilerplate because it is a 'partial' in a Hugo project, similar to a component in React) and that looks like this:
<script>
let menuButton = document.getElementById('menu-toggle');
menuButton.addEventListener('click', function () {
let flyout = document.getElementById('mobile-menu').classList
flyout.toggle('hidden')
flyout.toggle('block')
})
</script>
but this JS doesn't work at all. Looking for insight on how to pull this off properly. Thank you!!
I have written a little code to do the work around. Perhaps it is not the effect you want for your final result, but it is a start. The aproach here is that you can't apply a toggle function for the same button and the same element toggling diferent class, without use some css at least. Besides, there are so many code errors to explain one by one. Here I let you the code that allows to you open with burger button and close with cross button.
If you need to toggle with the same button just use the menuButtonBurger event and add flyout.classlist.toggle('visible), and remove menuButtonCross. Combined with the css I wrote you this must work.
let menuButtonBurger = document.getElementById('menu-toggle-burger');
let menuButtonCross = document.getElementById('menu-toggle-cross');
menuButtonBurger.addEventListener('click', function () {
let flyout = document.getElementById('mobile-menu');
flyout.classList.add('visible');
});
menuButtonCross.addEventListener('click', function () {
let flyout = document.getElementById('mobile-menu');
flyout.classList.remove('visible');
});
#mobile-menu {
display: none;
}
#mobile-menu.visible {
display: block;
}
<div class="mr-2 my-2 d-md-hidden">
<button id="menu-toggle-burger" type="button" class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500" aria-expanded="false">
<span class="sr-only">Open menu</span>
<!-- Heroicon name: outline/menu -->
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" />
</svg>
</button>
</div>
<div id="mobile-menu"class="absolute z-30 top-0 inset-x-0 p-2 transition transform origin-top-right d-hidden">
<div class="rounded-lg shadow-lg ring-1 ring-black ring-opacity-5 bg-white divide-y-2 divide-gray-50">
<div class="pt-5 pb-6 px-5">
<div class="flex items-center justify-between">
<div>
<img class="h-8 w-auto" src="https://tailwindui.com/img/logos/workflow-mark-indigo-600.svg" alt="Workflow">
</div>
<div class="-mr-2">
<button id="menu-toggle-cross" onclick="" type="button" class="bg-white rounded-md p-2 inline-flex items-center justify-center text-gray-400 hover:text-gray-500 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-indigo-500">
<span class="sr-only">Close menu</span>
<!-- Heroicon name: outline/x -->
<svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
</div>
</div>
</div>
</div>

React Swiper: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'addClass')

I am using react typescript. When I set thumbs={{ swiper: thumbsSwiper }} on my swiper slider component it gives me an error that Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'addClass'). How can I be able to solve it? if I use the below code in the js file it doesn't give me any error but as soon as I use it on the TSX file it through an error.
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null); // Thumbs state
<div key={product._id} className='lg:w-1/2'>
<Swiper
loop={true}
spaceBetween={10}
thumbs={{ swiper: thumbsSwiper }} // PRoblem is Here
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper2"
>
{product?.images.map(({ src }: { src: string }) => {
return <SwiperSlide style={{ height: '500px', width: '300px' }}>
<img src={src} alt={product?.title} />
</SwiperSlide>
})}
</Swiper>
<Swiper
onSwiper={setThumbsSwiper}
loop={true}
spaceBetween={10}
slidesPerView={4}
freeMode={true}
watchSlidesProgress={true}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper mt-4"
>
{product?.images.map(({ src }: { src: string }) => {
return <SwiperSlide style={{ height: '100px', width: '100px' }} >
<img src={src} alt={product?.title} />
</SwiperSlide>
})}
</Swiper>
</div>
Here is my full code:
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import RelatedProducts from '../RelatedProducts/RelatedProducts';
import { Swiper, SwiperSlide } from "swiper/react";
import { FreeMode, Navigation, Thumbs } from "swiper";
import Magnifier from "react-magnifier";
const SingleProduct = () => {
const { id } = useParams();
const [productsDetails, setProductsDetails] = useState<any>([])
const [isLoading, setIsLoading] = useState<boolean>(false)
useEffect(() => {
setIsLoading(true)
fetch(`https://guarded-ocean-73313.herokuapp.com/products`)
.then(res => res.json())
.then((data) => {
console.log(data, 'data')
const product = data.filter(detail => detail._id === id)
setProductsDetails(product);
}).finally(() => setIsLoading(false))
}, [id])
useEffect(() => {
if (!productsDetails.length) {
<h2>Loading</h2>
}
}, [productsDetails.length])
const [thumbsSwiper, setThumbsSwiper] = useState<any>(null);
return (
<div>
<section className="text-gray-700 body-font overflow-hidden bg-white">
<div className="container px-5 py-10 mx-auto">
<div className="lg:w-4/5 mx-auto flex ">
{isLoading ? "Loading" :
productsDetails.map(product => {
return <>
<div key={product._id} className='lg:w-1/2'>
<Swiper
loop={true}
spaceBetween={10}
thumbs={{ swiper: thumbsSwiper }}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper2"
>
{product?.images.map(({ src }: { src: string }) => {
return <SwiperSlide style={{ height: '500px', width: '300px' }}>
<img src={src} alt={product?.title} />
</SwiperSlide>
})}
</Swiper>
<Swiper
onSwiper={setThumbsSwiper}
loop={true}
spaceBetween={10}
slidesPerView={4}
freeMode={true}
watchSlidesProgress={true}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper mt-4"
>
{product?.images.map(({ src }: { src: string }) => {
return <SwiperSlide style={{ height: '100px', width: '100px' }} >
<img src={src} alt={product?.title} />
</SwiperSlide>
})}
</Swiper>
</div>
<div className="lg:w-1/2 w-full lg:pl-10 lg:py-6 mt-6 lg:mt-0">
<div>
<h2 className="text-sm title-font text-gray-500 tracking-widest">Brand: <b>{product.brand}</b></h2>
<h1 className="text-gray-900 text-3xl title-font font-medium mb-1">{product.title}</h1>
<div className="flex mb-4">
<span className="flex items-center">
<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-4 h-4 text-red-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-4 h-4 text-red-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-4 h-4 text-red-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="currentColor" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-4 h-4 text-red-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-4 h-4 text-red-500" viewBox="0 0 24 24">
<path d="M12 2l3.09 6.26L22 9.27l-5 4.87 1.18 6.88L12 17.77l-6.18 3.25L7 14.14 2 9.27l6.91-1.01L12 2z"></path>
</svg>
<span className="text-gray-600 ml-3">4 Reviews</span>
</span>
<span className="flex ml-3 pl-3 py-2 border-l-2 border-gray-200">
<a className="text-gray-500">
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M18 2h-3a5 5 0 00-5 5v3H7v4h3v8h4v-8h3l1-4h-4V7a1 1 0 011-1h3z"></path>
</svg>
</a>
<a className="ml-2 text-gray-500">
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M23 3a10.9 10.9 0 01-3.14 1.53 4.48 4.48 0 00-7.86 3v1A10.66 10.66 0 013 4s-4 9 5 13a11.64 11.64 0 01-7 2c9 5 20 0 20-11.5a4.5 4.5 0 00-.08-.83A7.72 7.72 0 0023 3z"></path>
</svg>
</a>
<a className="ml-2 text-gray-500">
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M21 11.5a8.38 8.38 0 01-.9 3.8 8.5 8.5 0 01-7.6 4.7 8.38 8.38 0 01-3.8-.9L3 21l1.9-5.7a8.38 8.38 0 01-.9-3.8 8.5 8.5 0 014.7-7.6 8.38 8.38 0 013.8-.9h.5a8.48 8.48 0 018 8v.5z"></path>
</svg>
</a>
</span>
</div>
<p className="leading-relaxed"
dangerouslySetInnerHTML={({ __html: product.product_des })}></p>
<div className="flex py-4 space-x-4">
</div>
<div className="flex mt-6 items-center pb-5 border-b-2 border-gray-200 mb-5">
{/* <div className="flex">
<span className="mr-3">Color</span>
<button className="border-2 border-gray-300 rounded-full w-6 h-6 focus:outline-none"></button>
<button className="border-2 border-gray-300 ml-1 bg-gray-700 rounded-full w-6 h-6 focus:outline-none"></button>
<button className="border-2 border-gray-300 ml-1 bg-red-500 rounded-full w-6 h-6 focus:outline-none"></button>
</div> */}
<div className="relative mr-4 mt-3">
<div className="text-center left-0 pt-2 right-0 absolute block text-xs uppercase text-gray-400 tracking-wide font-semibold">Qty</div>
<select className="cursor-pointer appearance-none rounded-xl border border-gray-200 pl-4 pr-8 h-14 flex items-end pb-1">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
{product?.attributes.map(attr => {
return <div className=" mr-6 items-center">
<span className="mr-3"><b>{attr.label}</b></span><br />
<div className="relative">
<select className="rounded appearance-none border border-gray-200 py-2 focus:outline-none focus:border-indigo-500 text-base pl-3 pr-10">
{attr?.selected.map(select => {
return <option>{select.label}</option>
})}
</select>
<span className="absolute right-0 top-0 h-full w-10 text-center text-gray-600 pointer-events-none flex items-center justify-center">
<svg fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-4 h-4" viewBox="0 0 24 24">
<path d="M6 9l6 6 6-6"></path>
</svg>
</span>
</div>
</div>
})}
</div>
<span className="title-font font-sm text-gray-900">Category: <b>{product.categories[0].label}</b></span>
<div className="flex mt-4">
<div className="inline-block align-bottom mr-5">
<span className="text-2xl leading-none align-baseline">$</span>
<span className="font-bold text-5xl leading-none align-baseline">{product.sale_price ? product.sale_price : product.reg_price} </span>
<span className="text-2xl leading-none align-baseline">.00</span>
</div>
<div className="inline-block align-bottom mr-5 mt-5 line-through">
<span className="text-2xl leading-none align-baseline">$</span>
<span className="font-bold text-2xl leading-none align-baseline">{product.sale_price ? product.reg_price : ''} </span>
<span className="text-2xl leading-none align-baseline">.00</span>
</div>
{/* <span className="title-font font-medium text-2xl text-gray-900">${product.price | 0} <span className='line-through text-gray-500'>{product?.sale_price}</span>
</span> */}
<button className="flex ml-auto text-white bg-indigo-500 border-0 py-2 px-6 focus:outline-none hover:bg-indigo-600 rounded items-center">Add to cart</button>
<button className="rounded-full w-10 h-10 bg-gray-200 p-0 border-0 inline-flex items-center justify-center text-gray-500 ml-4">
<svg fill="currentColor" stroke-linecap="round" stroke-linejoin="round" strokeWidth="2" className="w-5 h-5" viewBox="0 0 24 24">
<path d="M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z"></path>
</svg>
</button>
</div>
</div>
</div></>
})
}
</div>
</div>
<div className='bg-slate-300 mb-10 mt-10 shadow'>
<h2 className='text-2xl text-center py-3'>Related Products</h2>
</div>
<RelatedProducts />
</section >
</div >
)
};
export default SingleProduct;
If you open Swiper in a modal, pass null to setThumbsSwiper every time you close the modal. This works for me.
const onCloseModal = () => {
setThumbsSwiper(null)
}
https://snipboard.io/pN3cIl.jpg
I have solved it this way. I am validating first if there are any images available on my images property or not, if there is an image then render swiperSlide and it solved my issue.
{
product.images ? <Swiper
loop={true}
spaceBetween={10}
thumbs={{ swiper: thumbsSwiper }}
modules={[FreeMode, Navigation, Thumbs]}
className="mySwiper2"
>
{product?.images.map(({ src }: { src: string }) => {
return <SwiperSlide style={{ height: '500px', width: '300px' }}>
<img src={src} alt={product?.title} />
</SwiperSlide>
})}
</Swiper> : 'No img'
}
React does not allow className to be passed to the swiper component thou their are two ways of doing this
React Strict from <React.Strict>
Upgrade Swiper Js to the latest version
One of this solution should definitely work for you.

Vee Validate 3 validate at least one item inside v-for required rule

I have Vee Validate 3 set up in my project and I'm trying to validate whether a particular element has been checked within a v-for loop. I have several v-fors within v-fors so am trying to find something that works well for all of them.
I've wrapped my input within a validation-provider component that exists inside of my loop, but the required rule seems to be applied on each and every element, and I need to simply check whether at least one has been checked with my v-model.
Here's my markup:
<validation-observer v-slot="{ handleSubmit }">
<form #submit.stop.prevent="handleSubmit(submitForm)">
<!-- Step 1 -->
<validation-observer v-if="editor.step == 1" :key="1">
// inputs
</validation-observer>
<!-- Step 2: Choose Sources -->
<validation-observer v-if="editor.step == 2" :key="2">
<ul v-for="(source, table, sourceIndex) in editor.sources" :key="sourceIndex" class="mb-3">
<li>
<!-- Data Source (Table) -->
<validation-provider
name="data source"
:rules="{ required: { allowFalse: false } }"
v-slot="{ errors, classes }"
>
<label :for="'source-'+sourceIndex" class="font-medium text-gray-700 cursor-pointer block p-4 border rounded-md">
<div class="flex">
<div class="flex-1">
<p class="text-xs font-medium text-gray-400">Data Source</p>
<h5 class="text-sm font-bold text-gray-500" :class="source.isChecked ? 'text-indigo-600' : ''">{{ table }}</h5>
</div>
<div v-if="source.isChecked" class="flex-1 items-center flex justify-end" :class="source.isChecked ? 'text-indigo-600' : ''">
<svg xmlns="http://www.w3.org/2000/svg" fill="none" height="24" width="24" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12l2 2 4-4m6 2a9 9 0 11-18 0 9 9 0 0118 0z" />
</svg>
</div>
</div>
<input :id="'source-'+sourceIndex" v-model="source.isChecked" type="checkbox" class="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded cursor-pointer hidden">
</label>
<span class="text-xs text-red-500">{{ errors[0] }}</span>
</validation-provider>
</li>
</ul>
</validation-observer>
</form>
</validation-observer>
Right now, the required rule is listening for whether I've checked all of the elements inside of my loop, I just need to check whether at least one has been selected, why isn't this working?

Categories

Resources