I need to use a Vue props, in a tailwindcss class.
The class is "bg-[url('address')]" (background image), and the adress is a props.
But no matter how I write that code, I always get the error:
Module not found: Error: Can't resolve this 'this.icon'.
I tried:
`bg-[url(${this.icon})]`
"`bg-[url(${this.icon})]`"
'bg-[url('+this.icon+')]'
I try to use that sintax with computed too. Like this:
classIcon() {
return `bg-[url(${this.icon})]`
}
My complete code component:
Template:
<template>
<div class="flex items-center rounded-lg bg-gray-100 p-4 font-lato">
<div class="bg-no-repeat w-full" :class=`bg-[url(${this.icon})]`>trstestes</div>
<div class="flex flex-col">
<p>
<span class="font-bold">
{{ title }}
</span>
{{ benefit }}
</p>
</div>
</div>
</template>
Script
export default {
props: {
icon: {
type: String,
require: true,
default: "Γcone",
},
}
}
With computed:
Template:
<template>
<div class="flex items-center rounded-lg bg-gray-100 p-4 font-lato">
<div class="bg-no-repeat w-full" :class="classIcon" >trstestes</div>
<div class="flex flex-col">
<p>
<span class="font-bold">
{{ title }}
</span>
{{ benefit }}
</p>
</div>
</div>
</template>
Script:
classIcon() {
return `bg-[url(${this.icon})]`
}
}
}
Anybody can helpe me? Thank's
Related
"use client";
import { groq } from "next-sanity";
import Image from "next/image";
import { client } from "../../../../lib/sanity.client";
import urlFor from "../../../../lib/urlFor";
import { PortableText } from "#portabletext/react";
import { RichTextComponents } from "../../../../components/RichTextComponents";
import { useForm, SubmitHandler } from "react-hook-form";
interface IFormInput {
_id: string;
name: string;
email: string;
comment: string;
}
type Props = {
params: {
slug: string;
};
};
export const revalidate = 30;
export async function generateStaticParams() {
const query = groq`
*[_type=="post"]
{
slug
}
`;
const slugs: Post[] = await client.fetch(query);
const slugRoutes = slugs.map((slug) => slug.slug.current);
return slugRoutes.map((slug) => ({
slug,
}));
}
const Post = async ({ params: { slug } }: Props) => {
const {
register,
handleSubmit,
formState: { errors },
} = useForm<IFormInput>();
const query = groq`
*[_type=='post' && slug.current == $slug][0]
{
...,
author->,
categories[]->
}
`;
const post: Post = await client.fetch(query, { slug });
const onSubmit: SubmitHandler<IFormInput> = async (data) => {
await fetch("/api/createComment", {
method: "POST",
body: JSON.stringify(data),
})
.then(() => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
};
return (
<>
<article className="px-10 pb-28 mt-10">
<section className="space-y-2 borber border-[#f7ab0a] text-white">
<div className="relative min-h-56 flex flex-col md:flex-row justify-between">
<div className="absolute top-0 w-full h-full opacity-10 blur-sm p-10">
<Image
className="object-cover object-center mx-auto"
src={urlFor(post.mainImage).url()}
alt={post.author.name}
fill
/>
</div>
<section className="p-5 bg-[#f7ab0a] w-full">
<div className="flex flex-col md:flex-row justify-between gap-y-5">
<div>
<h1 className="text-4xl font-extrabold">{post.title}</h1>
<p>
{new Date(post._createdAt).toLocaleDateString("en-US", {
day: "numeric",
month: "long",
year: "numeric",
})}
</p>
</div>
<div className="flex items-center space-x-2">
<Image
className="rounded-full"
src={urlFor(post.author.image).url()}
alt={post.author.name}
height={40}
width={40}
/>
<div className="w-64">
<h3 className="text-lg font-bold">{post.author.name}</h3>
<div> {/* */} </div>
</div>
</div>
</div>
<div>
<h2 className="italic pt-10">{post.description}</h2>
<div className="flex items-center justify-end mt-auto space-x-2">
{post.categories.map((category) => (
<p
className="bg-gray-800 text-white px-3 py-1 rounded-full text-sm font-semibold mt-4"
key={category._id}
>
{category.title}
</p>
))}
</div>
</div>
</section>
</div>
</section>
<PortableText value={post.body} components={RichTextComponents} />
</article>
<div>
<hr className="max-w-lg my-5 mx-auto border border-yellow-500" />
<form
onSubmit={handleSubmit(onSubmit)}
className="flex flex-col p-5 max-w-2xl mx-auto mb-10"
>
<h3 className="text-md text-yellow-500">Enjoyed this article?</h3>
<h4 className="text-3xl font-bold">Leave a comment below!</h4>
<hr className="py-3 mt-2" />
<input
{...register("_id")}
type="hidden"
name="_id"
value={post._id}
/>
<label className="block mb-5 ">
<span className="text-gray-700">Name</span>
<input
{...register("name", { required: true })}
className="shadow border rounded py-2 px-3 form-input mt-1 block w-full outline-none ring-yellow-500 focus:ring"
placeholder="John Doe..."
type="text"
/>
</label>
<label className="block mb-5 ">
<span className="text-gray-700">Email</span>
<input
{...register("email", { required: true })}
className="shadow border rounded py-2 px-3 form-input mt-1 block w-full outline-none ring-yellow-500 focus:ring"
placeholder="example#gmail.com"
type="email"
/>
</label>
<label className="block mb-5 ">
<span className="text-gray-700">Comment</span>
<textarea
{...register("comment", { required: true })}
className="shadow border rounded py-2 px-3 form-textarea mt-1 block w-full outline-none ring-yellow-500 focus:ring"
placeholder="type your comments..."
rows={8}
/>
</label>
<div className="flex flex-col p-5">
{errors.name && (
<span className="text-red-500">
-- The name field is required
</span>
)}
{errors.email && (
<span className="text-red-500">
-- The email field is required
</span>
)}
{errors.comment && (
<span className="text-red-500">
-- The comment field is required
</span>
)}
</div>
<input
type="submit"
className="shadow bg-yellow-500 hover:bg-yellow-400 w-full
focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded cursor-pointer
"
/>
</form>
</div>
<div className="relative">
<a
id="topp"
rel="noreferrer"
href="#top"
className="back-to-top absolute bottom-4 right-0 rounded-3xl bg-[#f7ab0a] text-white hover:-translate-y-2 hover:bg-lime-600 hover:text-[#f7ab0a] p-2 text-2xl"
>
<i className="fas fa-angle-up " aria-hidden="true"></i>
</a>
</div>
</>
);
};
export default Post;
I tried to post comments from my blog post to sanity v3 studio backend. But whenever I tried to test on the localhost:3000 dev build it claims that "Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead." I didn't understand where I render children as object.
I would like have my comment function working, this problem to be solved.
Thanks in advance.
Following line in your Post component is causing the issue:
// ...
const post: Post = await client.fetch(query, { slug });
// ...
You are using post variable to access title, author, categories fields and trying to render it in the JSX.
However, post is a Promise which is not resolved while React is rendering the component.
So, basically you are rendering Promise inside the JSX which is not supported (that's what the error is saying)
So, the better way is to define a state for post variable and make an api call inside a function and when that api is resolved set the response data inside the post state and use that post state inside the JSX.
Something like:
const Post = async ({ params: { slug } }: Props) => {
//... your component body
const [post, setPost] = useState(null) // initialise post state to be null
const fetchPost = async() => {
try {
let response = await client.fetch(query, { slug })
setPost(response.data) // it will be response.data or something else based on your response structure where you are getting the post
} catch(err) {
console.log(err)
}
}
useEffect(() => {
fetchPost()
}, [])
// .... remaining code
// handle loader
if(!post) return <p>loading...</p>
return (
<>
{/* JSX similar to what you are rendering */}
</>
)
}
You can create separate loader state in the component to handle loading more accurately.
Let me know if you have further queries. Happy to resolve them! :-)
I am trying to make an index page and I want it to have the following layout
Index page layout
I am using Deno Fresh thus I have tailwind for styling.
I have the following export for my index page that uses a footer and a header component an image and a Sign In island like so:
return (
<div className={'bg-[#5C7EB5]'}>
<Header active={"/"} flag={false}/>
<div className={"flex h-full gap-52 p-auto justify-center items-center"}>
<SignIn/>
<img src={"https://cdn-icons-png.flaticon.com/512/2974/2974498.png"}
alt={"Couldn't load image..."}
className={"w-1/4 h-1/4"}/>
</div>
<Footer/>
</div>
);
}
The components and the island are the following
Header:
export function Header({ active, flag }: Props, ) {
const menus = [
{ name: "Home", href: "/" },
{ name: "Rack Temperatures", href: "/test-header" },
{ name: "Entrees", href: "/docs" },
{ name: "Temperature Humidity", href: "/dummy"}
];
return (
<div class="sticky top-0 bg-[#28374F] w-full py-5 px-8 flex flex-col md:flex-row gap-4 mx-0">
<div class="flex items-center flex-1">
<div className="ml-1 text-2xl text-gray-50 font-bold">
<a href={"/"}>FlyMonitoring</a>
</div>
<a href={"/"}>
<img src={"https://pngimage.net/wp-content/uploads/2018/06/heisenberg-logo-png-2.png"}
alt={"Couldn't load image..."}
class={"w-12 h-12"}/>
</a>
</div>
<ul class="flex items-center gap-6">
{menus.map((menu) => (
<li>
<a
href={menu.href}
class={"text-gray-50 hover:text-blue-200 py-1 border-gray-50" +
(menu.href === active ? " font-bold border-b-2" : "")}
>
{menu.name}
</a>
</li>
))}
</ul>
<div>
{flag
? <button type={'submit'}
className={"bg-blue-600 hover:bg-blue-700 text-white rounded px-6 py-2.5"}>
Log Out</button>
: ""}
</div>
</div>
);
}
Footer:
import BrandGithub from "https://deno.land/x/tabler_icons_tsx#0.0.1/tsx/brand-github.tsx";
export default function Footer() {
const menus = [
{
title: "Device Control",
children: [
{ name: "Rack Temperature", href: "/rack-temperature" },
{ name: "Temperature Humidity", href: "/temperature-humidity" },
{ name: "Water Level", href: "/water-level" },
{ name: "Smoke", href: "/smoke" },
{ name: "Entrees", href: "/entrees" },
],
},
{
title: "Information",
children: [
{ name: "Email", href: "#" },
{ name: "Phone", href: "#" },
{ name: "Discord", href: "#" }
],
},
];
return (
<div class="bg-[#28374F] w-full flex flex-col md:flex-row w-full gap-2 md:gap-16 px-8 py-4 text-sm">
<div class="flex-1">
<div class="flex items-center gap-1">
<div class="font-bold text-2xl text-gray-50">
FlyMonitoring
</div>
</div>
<div class="text-gray-100">
Application for high security room monitoring
</div>
</div>
{menus.map((item) => (
<div class="mb-4" key={item.title}>
<div class="font-bold text-gray-50">{item.title}</div>
<ul class="mt-2">
{item.children.map((child) => (
<li class="mt-2" key={child.name}>
<a
class="text-gray-200 hover:text-blue-200"
href={child.href}
>
{child.name}
</a>
</li>
))}
</ul>
</div>
))}
<div class="text-gray-100 space-y-2">
<div class="text-xs">
Copyright Β© 2020<br />
All right reserved.
</div>
<a
href="https://github.com/****************"
class="inline-block hover:text-blue-200"
>
<BrandGithub />
</a>
</div>
</div>
);
}
Your code is unfortunately not reproducible:
Follow the below code structure:
flex flex-col
|_ h-40
|_ flex-1 π This fills the entire space
|_ h-60
<div class="flex h-screen flex-col bg-slate-500">
<header class="flex h-20 items-center justify-center bg-blue-600 text-6xl">Header</header>
<main class="flex flex-1 items-center justify-center bg-green-300 text-6xl">Main</main>
<footer class="flex h-40 items-center justify-center bg-yellow-400 text-6xl">Footer</footer>
</div>
tailwind-play
I have put in a mouseenter and mouseleave on the li tag that i want when a person hovers over it, it will display the price on product.price. However, when i hover over it, it will display the price for all 6 rendered data instead of just the 1 its hovered on. I only want it to display pricing on the specific item its hovered on and not all. The data is being loaded from firebase. Please see below template code and image here for reference.
<div class="relative w-full pb-6 -mb-6 overflow-x-auto scrollbar-hide">
<ul role="list" class="mx-4 inline-flex space-x-0 gap-2 sm:mx-6 lg:mx-0 lg:space-x-0 lg:grid lg:grid-cols-6 lg:gap-x-4">
<li v-if="products.length" v-for="product in products" :key="product.id" #mouseenter="hover = true" #mouseleave="hover = false" class="w-44 inline-flex border hover:border-black rounded-lg p-4 lg:w-auto">
<div class="group relative">
<div class="w-[70%] lg:w-[55%] bg-gray-white overflow-hidden">
<img :src="product.imageSrc" :alt="product.imageAlt" class="w-full h-20 overflow-hidden object-center object-contain" />
</div>
<div class="mt-2">
<h3 class="mt-1 font-rubikreg h-11 overflow-hidden text-xs lg:text-base uppercase text-gray-900">
<a :href="product.href">
<span class="absolute inset-0" />
{{ product.name }}
</a>
</h3>
<p class="mt-3 lg:mt-6 font-rubiklight uppercase text-xs lg:text-sm text-gray-900">
Cheapest At
</p>
<p class="mt-1 font-rubikreg underline-offset-2 underline uppercase text-xs lg:text-sm text-gray-900">
{{ product.cheapestat }}
</p>
<p v-if="hover" class="mt-5 text-2xl uppercase font-rubik text-gray-900">
<span class="text-xs">From</span>
A${{ product.price }}
</p>
</div>
</div>
</li>
</ul>
</div>
script code on firebase data
setup() {
onMounted(() => {
onSnapshot(collection(db, "malesneakers") , (querySnapshot) => {
const maleProducts = [];
querySnapshot.forEach((doc) => {
const mlproducts = {
id: doc.id,
imageSrc: doc.data().imageSrc,
name: doc.data().name,
price: doc.data().price,
cheapestat: doc.data().cheapestat,
svgSrc: doc.data().svgSrc,
href: doc.data().href,
}
maleProducts.push(mlproducts)
});
products.value = maleProducts
});
});
Try with product.id instead of boolean for hover variable:
const { ref } = Vue
const app = Vue.createApp({
setup() {
const products = ref([{id: 1, name: 'aaa', href: '#', cheapestat: 5, price: 7}, {id: 2, name: 'bbb', href: '#', cheapestat: 5, price: 5}])
const hover = ref(null)
return {
products, hover
};
},
})
app.mount('#demo')
<script src="https://unpkg.com/vue#3/dist/vue.global.prod.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.19/tailwind.min.css" integrity="sha512-wnea99uKIC3TJF7v4eKk4Y+lMz2Mklv18+r4na2Gn1abDRPPOeef95xTzdwGD9e6zXJBteMIhZ1+68QC5byJZw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<div id="demo">
<div class="relative w-full pb-6 -mb-6 overflow-x-auto scrollbar-hide">
<ul v-if="products.length" role="list" class="mx-4 inline-flex space-x-0 gap-2 sm:mx-6 lg:mx-0 lg:space-x-0 lg:grid lg:grid-cols-6 lg:gap-x-4">
<!-- π here you set hover to product.id -->
<li v-for="product in products" :key="product.id"
#mouseenter="hover = product.id" #mouseleave="hover = null" class="w-44 inline-flex border hover:border-black rounded-lg p-4 lg:w-auto">
<div class="group relative">
<div class="w-[70%] lg:w-[55%] bg-gray-white overflow-hidden">
<img :src="product.imageSrc" :alt="product.imageAlt" class="w-full h-20 overflow-hidden object-center object-contain" />
</div>
<div class="mt-2">
<h3 class="mt-1 font-rubikreg h-11 overflow-hidden text-xs lg:text-base uppercase text-gray-900">
<a :href="product.href">
<span class="absolute inset-0" />
{{ product.name }}
</a>
</h3>
<p class="mt-3 lg:mt-6 font-rubiklight uppercase text-xs lg:text-sm text-gray-900">
Cheapest At
</p>
<p class="mt-1 font-rubikreg underline-offset-2 underline uppercase text-xs lg:text-sm text-gray-900">
{{ product.cheapestat }}
</p>
<!-- π here you check hover for product.id -->
<p v-if="hover === product.id" class="mt-5 text-2xl uppercase font-rubik text-gray-900">
<span class="text-xs">From</span>
A${{ product.price }}
</p>
</div>
</div>
</li>
</ul>
</div>
</div>
So I'm trying to give conditional render div a width of full, but bcz I've given padding to its parent it's not taking the full width of the container
here is the code:
import Image from "next/image";
import DoubleTickIcon from "../PersonalChatAssets/DoubleTick.png";
import SingleTickIcon from "../PersonalChatAssets/SingleTick.png";
import { useRef, useEffect } from "react";
interface textbody {
content: string;
sent: boolean;
time: string;
replyReference: any;
}
const TextMessage = (props: textbody) => {
console.log("Referece::::", props.replyReference);
return (
<div className="flex flex-col items-end w-[332px] ml-[52px] mr-[20px] mb-[18px]">
<div className="flex justify-center items-center">
<Image src={props.sent ? DoubleTickIcon : SingleTickIcon} alt="" />
<h1 className="font-normal text-[12px] mb-0 font-[#787580]">
{props.time}
</h1>
</div>
//this is its parent
<div className="flex flex-col justify-center items-center bg-[#F7CA16] rounded-l-[16px] pr-[14px] pl-[14px] pt-[8px] pb-[8px] font-inter font-[14px] rounded-b-[16px] min-h-[40px] max-w-[340px] min-w-[60px] break-words">
//This is Conditional rendring part
{props.replyReference?.message !== undefined && (
<div className="h-[52px] reply-gradient p-2 ">
<div className="-space-y-3 overflow-ellipsis truncate border-l-[4px] border-solid border-[#1F1D25] pl-2">
<h1 className="">to {props.replyReference?.author}</h1>
<p className="max-w-[230px] truncate ">
{props.replyReference?.message}
</p>
</div>
</div>
)}
<h1 className="flex justify-center item-center w-full h-full mb-0">{props.content}</h1>
</div>
</div>
);
};
export default TextMessage;
This is the output I'm getting now:
This is the output I want:
You should move pr-[14px] pl-[14px] pt-[8px] pb-[8px] to reply-gradient and h1 elements.
Similarly, you also need to add rounded-l-[16px] rounded-b-[0] to reply-gradient to have the same border styles with the parent component.
import Image from "next/image";
import DoubleTickIcon from "../PersonalChatAssets/DoubleTick.png";
import SingleTickIcon from "../PersonalChatAssets/SingleTick.png";
import { useRef, useEffect } from "react";
interface textbody {
content: string;
sent: boolean;
time: string;
replyReference: any;
}
const TextMessage = (props: textbody) => {
console.log("Referece::::", props.replyReference);
return (
<div className="flex flex-col items-end w-[332px] ml-[52px] mr-[20px] mb-[18px]">
<div className="flex justify-center items-center">
<Image src={props.sent ? DoubleTickIcon : SingleTickIcon} alt="" />
<h1 className="font-normal text-[12px] mb-0 font-[#787580]">
{props.time}
</h1>
</div>
//this is its parent
<div className="flex flex-col justify-center items-center bg-[#F7CA16] rounded-l-[16px] font-inter font-[14px] rounded-b-[16px] min-h-[40px] max-w-[340px] min-w-[60px] break-words">
//This is Conditional rendring part
{props.replyReference?.message !== undefined && (
<div className="h-[52px] reply-gradient p-2 pr-[14px] pl-[14px] pt-[8px] pb-[8px] rounded-l-[16px] rounded-b-[0]">
<div className="-space-y-3 overflow-ellipsis truncate border-l-[4px] border-solid border-[#1F1D25] pl-2">
<h1 className="">to {props.replyReference?.author}</h1>
<p className="max-w-[230px] truncate ">
{props.replyReference?.message}
</p>
</div>
</div>
)}
<h1 className="flex justify-center item-center w-full h-full mb-0 pr-[14px] pl-[14px] pt-[8px] pb-[8px]">{props.content}</h1>
</div>
</div>
);
};
export default TextMessage;
You can check this playground
I'm using VueJS 3 with "vue-draggable-next": "^2.1.1".
Nothing happens when I try to drag.
I see in the HTML this:
<div class="flex m-10" data-v-52c58f0f="">
<draggable list="[object Object],[object Object],[object Object],[object Object]" data-v-52c58f0f="">
<div class="list-group-item bg-gray-300 m-1 p-3 rounded-md text-center" data-v-52c58f0f="">John</div>
<div class="list-group-item bg-gray-300 m-1 p-3 rounded-md text-center" data-v-52c58f0f="">Joao</div>
<div class="list-group-item bg-gray-300 m-1 p-3 rounded-md text-center" data-v-52c58f0f="">Jean</div>
<div class="list-group-item bg-gray-300 m-1 p-3 rounded-md text-center" data-v-52c58f0f="">Gerard</div>`
</draggable>
</div>
When I implement the code like this:
import { VueDraggableNext } from "vue-draggable-next";
components: {
draggable: VueDraggableNext
},
with
list: [
{ name: 'John', id: 1 },
{ name: 'Joao', id: 2 },
{ name: 'Jean', id: 3 },
{ name: 'Gerard', id: 4 },
],
and im the template I already tried:
<draggable class="dragArea list-group w-full" :list="list" #change="log">
<div
class="list-group-item bg-gray-300 m-1 p-3 rounded-md text-center"
v-for="element in list"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
and this:
<draggable
:list="list"
:disabled="!enabled"
item-key="name"
class="list-group"
ghost-class="ghost"
:move="checkMove"
#start="dragging = true"
#end="dragging = false"
>
<template #item="{ element }">
<div class="list-group-item" :class="{ 'not-draggable': !enabled }">
{{ element.name }}
</div>
</template>
</draggable>
In the case where I use
<template #item="{ element }">
Nothing is showing, and in the other case, nothing is draggable.
The component is loaded, I can see it with the Vue extension for Chrome:
Does anyone have any idea why it is not working?
You did not correctly import the vue draggable package.
Do it like this:
import { VueDraggableNext } from "vue-draggable-next";
and after that use it like this:
<draggable :list="list">
<div
class="list-group-item bg-gray-300 m-1 p-3 rounded-md text-center"
v-for="element in list"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
Hope it works!!
Edit: This is an example, why you should post your whole code...
So, after hours and hours of trying different things, I came across that I have added, components: to the data().
Now, it works fine with this:
export default {
components: {
draggable: VueDraggableNext },
and this is what I was doing:
data() {
return {
components: {
draggable: VueDraggableNext
},
Hope this helps someone in the future...