I am using NEXT Image component to Fit in with a flex box without shrinking. However, based on the content that is there in the other element, it keeps shrinking:
Here's my code:
import React from 'react';
import Image from 'next/image';
type Props = {
imageUrl?: string;
senderName: string;
newMessageCount?: number;
latestMessage: string;
};
export default function MessageBox({
imageUrl,
senderName,
newMessageCount,
latestMessage,
}: Props) {
const isNewMessageDefined = newMessageCount ? true : false;
const newMsgValue =
latestMessage.length > 80
? `${latestMessage.slice(0, 80)}...`
: latestMessage;
return (
<div className='flex w-full gap-2' aria-label='Funfuse-Message-Container'>
<Image
alt='Message Image'
src={imageUrl ?? '/funfuse/avatar-02.jpg'}
className='rounded-full shadow-lg shrink-0 shadow-indigo-500/50'
height={80}
width={80}
objectFit='cover'
objectPosition='center'
/>
<div className='flex flex-col'>
<div
aria-label='Funfuse-Message-Header'
className='flex flex-row items-center gap-2'>
<h2 className='text-xl text-black'>{senderName ?? 'John Doe'}</h2>
{isNewMessageDefined && (
<div className='h-[1.2rem] w-[1.2rem] rounded-full relative bg-funfuse'>
<label className='absolute text-xs text-white transform -translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2'>
{newMessageCount}
</label>
</div>
)}
</div>
<div aria-label='Funfuse-Message-Body'>
<label className='text-sm font-semibold text-gray-400'>
{newMsgValue}
</label>
</div>
</div>
</div>
);
}
Can someone help me identify how to prevent this issue as I always want my image to be of the size and never shrink. I tried using the property: flex-shrink: 0 but that didn't work too.
it may be because of the layout attribute in the default Image tag is responsive, it reduces its size when it reduces the width of the parent.
Set the layout fixed to keep the width of the image fixed.
Here you can read more about next/image: https://nextjs.org/docs/api-reference/next/image
return (
<div className='flex w-full gap-2' aria-label='Funfuse-Message-Container'>
<Image
alt='Message Image'
src={imageUrl ?? '/funfuse/avatar-02.jpg'}
className='rounded-full shadow-lg shrink-0 shadow-indigo-500/50'
height={80}
layout="fixed"
width={80}
objectFit='cover'
objectPosition='center'
/>
<div className='flex flex-col'>
<div
aria-label='Funfuse-Message-Header'
className='flex flex-row items-center gap-2'>
<h2 className='text-xl text-black'>{senderName ?? 'John Doe'}</h2>
{isNewMessageDefined && (
<div className='h-[1.2rem] w-[1.2rem] rounded-full relative bg-funfuse'>
<label className='absolute text-xs text-white transform -translate-x-1/2 -translate-y-1/2 top-1/2 left-1/2'>
{newMessageCount}
</label>
</div>
)}
</div>
<div aria-label='Funfuse-Message-Body'>
<label className='text-sm font-semibold text-gray-400'>
{newMsgValue}
</label>
</div>
</div>
</div>
);
Related
I'm using Next.js with typescript and Tailwind CSS. (T3 stack)
I'm having trouble making the button clickable here is the code. I susspect that the div page is blocking the div and making all unclickable but I don't know how to do it. I think that the fix may be making the div where I call the component somehow not clickable
import React, { useRef, useContext, useState, useCallback } from "react";
import Image from "next/image";
import { FaChevronDown } from "react-icons/fa";
import { ScrollContext } from "../utils/scroll-observer";
const Masthead: React.FC = () => {
const refContainer = useRef<HTMLDivElement>(null);
const { scrollY } = useContext(ScrollContext);
let progress = 0;
const { current: elContainer } = refContainer;
if (elContainer) {
progress = Math.min(scrollY / elContainer.clientHeight, 1);
}
return (
<div
ref={refContainer}
className="min-h-screen flex flex-col items-center justify-center sticky top-0 -z-10"
style={{
transform: `translateY(-${progress * 20}vh)`,
}}
>
<video
autoPlay
loop
muted
playsInline
className="bg-white absolute w-full h-full object-cover"
>
<source src="/assets/background_video.mp4" />
</video>
<div className={`flex-grow-0 pt-10 transition-opacity duration-1000`}>
<Image src="/logoLiteContract.png" width={70} height={70} alt="logo" />
</div>
<div className="p-12 font-bold z-10 text-white drop-shadow-[0_5px_3px_rgba(0,0,0,0.4)] text-center flex-1 flex items-center justify-center flex-col">
<h1 className="mb-6 text-4xl xl:text-5xl">Lite contract</h1>
<h2 className="mb-2 text-2xl xl:text-3x tracking-tight">
<span>Registrate y empieza subir tus contratos</span>
</h2>
{/* Create a div in z-10 to make the button clickable */}
{/* Create a button for registration with hover effect and animation ensure that the button is on top of the video */}
{/* Space between the buttons*/}
<div className="h-10"></div>
<button className="bg-gray-700 hover:bg-black text-white font-bold py-2 px-4 rounded-full">
Registrate
</button>
{/* Space between the buttons*/}
<div className="h-10"></div>
{/* Create a button for login with hover effect and animation */}
<button className="bg-gray-500 hover:bg-gray-900 text-white font-bold py-2 px-4 rounded-full">
Iniciar sesiĆ³n
</button>
</div>
<div className="flex-grow-0 pb-20 md:pd-10 transition-all duration-1000">
<FaChevronDown className="w-10 h-10 text-white animate-bounce" />
</div>
</div>
);
};
export default Masthead;
Any Ideas?
In my react.js frontend, I have 2 columns (Dislay event list, create event) This is how my website look like in full screen.
However, when I tried to view it with smaller screen to test the responsiveness, the background white '#F2F2F2' is not showing for the 2nd column.
How do I solve this issue?
import axios from "axios";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { Button } from "../Components/customButton";
import KeyboardArrowLeftIcon from "#mui/icons-material/KeyboardArrowLeft";
import TopicList from "../Components/topicList";
import EventList from "../Components/eventList";
import { ToastContainer, toast } from "react-toastify";
import "react-toastify/dist/ReactToastify.css";
const BASE_URL = process.env.REACT_APP_BASE_URL;
function CreateEvent(success, message) {
const navigate = useNavigate();
const [eventName, setEventName] = useState("");
const [eventDesc, setEventDesc] = useState("");
const [startDate, setStartDate] = useState("");
const [endDate, setEndDate] = useState("");
const [multiplierType, setMultiplierType] = useState("");
const [multiplier, setMultiplier] = useState("");
const [topic, setTopic] = useState("");
const [eventNameCharLeft, setEventNameCharLeft] = useState(100);
const [eventDescCharLeft, setEventDescCharLeft] = useState(255);
const getDataFromTopicList = (val) => {
setTopic(val);
};
const handleEventNameChange = (event) => {
setEventName(event.target.value);
setEventNameCharLeft(100 - event.target.value.length);
};
const handleEventDescChange = (event) => {
setEventDesc(event.target.value);
setEventDescCharLeft(255 - event.target.value.length);
};
const handleSubmit = (event) => {
event.preventDefault();
axios({
method: "POST",
url: BASE_URL + "events/submitEvent",
data: {
eventName: eventName,
eventDesc: eventDesc,
eventStart: startDate,
eventEnd: endDate,
topicId: topic,
multiplierType: multiplierType,
multiplier: multiplier,
status: "Upcoming",
},
headers: { "Content-Type": "application/json" },
})
.then((response) => {
if (response.status === 200) {
toast.success("Successfully Created", {
position: toast.POSITION.TOP_CENTER,
});
} else {
toast.error(response.data.message, {
position: toast.POSITION.TOP_CENTER,
});
}
})
.catch((err) => {
if (err.response) {
toast.error(err.response.data.message, {
position: toast.POSITION.TOP_CENTER,
});
} else {
toast.error("Failed to Create", {
position: toast.POSITION.TOP_CENTER,
});
}
});
};
return (
<div className="min-h-screen">
<Button
variant="primary"
className="absolute top-4 left-6 px-0 py-2 font-bold btn btn-primary text-main-blue"
onClick={() => {navigate(`/Admin`);}}
isDisabled={false}
buttonText="Back"
icon={<KeyboardArrowLeftIcon color="main-green" />}
/>
<div className=" grid grid-cols-2 p-20 space-x-8 sm:grid-cols-1 md:grid-cols-1 h-screen lg:grid-cols-2 xl:grid-cols-2 2xl:grid-cols-2">
<div className="px-4 pt-4 pb-8 mb-4 bg-slate-50 drop-shadow-xl rounded-2xl">
{/* Ongoing Events */}
<h1 className="py-3 my-2 font-semibold border-b-2 text-main-blue border-main-blue">Ongoing Events</h1>
<div className="grid grid-cols-3 pt-2 gap-x-10">
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Event Name</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Start Date</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">End Date</h1>
</div>
</div>
<EventList url="events/getOngoing" />
{/* Upcoming Events */}
<h1 className="py-3 my-2 font-semibold border-b-2 text-main-blue border-main-blue">Upcoming Events</h1>
<div className="grid grid-cols-3 pt-2 gap-x-10">
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Event Name</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">Start Date</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-main-blue">End Date</h1>
</div>
</div>
<EventList url="events/getUpcoming" />
{/* Past Events */}
<h1 className="py-3 my-2 font-semibold text-gray-400 border-b-2 border-gray-400">Past Events</h1>
<div className="grid grid-cols-3 pt-2 gap-x-10">
<div className="">
<h1 className="pb-3 text-sm font-semibold text-gray-400">Event Name</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-gray-400">Start Date</h1>
</div>
<div className="">
<h1 className="pb-3 text-sm font-semibold text-gray-400">End Date</h1>
</div>
</div>
<EventList url="events/getPast" />
</div>
<form
className="px-8 pt-6 pb-8 mb-4 rounded sm:grid-cols-1 md:grid-cols-1 bg-white" onSubmit={handleSubmit}>
<h1 className="text-2xl font-bold pt-15 text-main-blue">Create an Event</h1>
<div>
<textarea
className="block w-full px-5 py-2 mt-2 overflow-y-auto text-sm break-words border border-gray-300 rounded-md bg-slate-50 text-main-blue drop-shadow-lg"
name="eventName" placeholder="Event Name" required onChange={handleEventNameChange} value={eventName}maxLength={100}>
</textarea>
<div className="mt-2 text-sm text-gray-500">
{eventNameCharLeft}/100 characters left
</div>
<textarea
className="block w-full px-5 py-2 mt-2 overflow-y-auto text-sm break-words border border-gray-300 rounded-md bg-slate-50 text-main-blue drop-shadow-lg"
name="eventDesc" placeholder="Event Description" required onChange={handleEventDescChange} value={eventDesc} maxLength={255}>
</textarea>
<div className="mt-2 text-sm text-gray-500">
{eventDescCharLeft}/255 characters left
</div>
<div className="grid grid-cols-2 gap-x-2 mt-4">
<div className="relative">
<label className="absolute text-sm text-gray-500">Start Date</label>
<input
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md my-5 block w-full p-2.5"
type="datetime-local" name="startDate" placeholder="Start Date" required onChange={(event) => setStartDate(event.target.value)} value={startDate}/>
</div>
<div className="relative">
<label className="absolute text-sm text-gray-500">End Date</label>
<input
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md my-5 block w-full p-2.5"
type="datetime-local" name="endDate" placeholder="End Date" required onChange={(event) => setEndDate(event.target.value)} value={endDate}/>
</div>
</div>
<div className="grid grid-cols-2 gap-x-2">
<TopicList getDataFromTopicList={getDataFromTopicList} />
<select
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md block w-auto p-2.5"
name="multiplierType" required onChange={(event) => setMultiplierType(event.target.value)} value={multiplierType}>
<option value="" disabled selected>Select Multiplier</option>
<option value="+">Add</option>
<option value="*">Multiply</option>
</select>
</div>
<input
className="bg-slate-50 text-main-blue border border-gray-300 drop-shadow-lg text-sm rounded-md my-5 block w-full p-2.5"
type="number" name="multiplier" placeholder="Multiplier Value (Eg 1-100)" min="1" max="100" required onChange={(event) => setMultiplier(event.target.value)} value={multiplier}/>
</div>
<div className="relative p-4">
<Button
variant="primary"
className="absolute bottom-0 right-0 px-4 py-2 -my-5 font-bold border rounded btn btn-primary bg-slate-50 text-main-blue border-main-blue hover:border-transparent hover:bg-main-blue hover:text-slate-50"
isDisabled={false}
buttonText="Submit"
type="submit"
/>
<ToastContainer autoClose={4000} />
</div>
</form>
</div>
</div>
);
}
export default CreateEvent;
This is the output for small screen in tailwind playground.
This seems to work just fine for me !
Code Link: tailwind_playground
Output in large screen:
Output in small screen:
Your problem is "h-screen" in the class name on the element you have selected in your screenshot. This prevents it from extending to the height of the elements inside it. You can change this to "min-h-screen" as well however, I would recommend just removing it entirely.
I'm currently working on an application using Next.JS where a user can navigate to a page that contains a table with say 'Projects'. Above the table I have a button that, when clicked, should show a modal to a user that will allow him to add a new project.
I defined a Modal component but I can't seem to get it working when the user clicks the 'Add' button in my application.
Here is the Modal component code:
const Modal = ({ show, onClose }) => {
const handleCloseClick = (e) => {
e.preventDefault();
onClose();
};
return ( show ? (
<div className="modal fade fixed top-0 left-0 hidden w-full h-full outline-none overflow-x-hidden overflow-y-auto" id="exampleModalCenteredScrollable" tabIndex="-1" aria-labelledby="exampleModalCenteredScrollable" aria-modal="true" role="dialog">
<div className="modal-dialog modal-dialog-centered modal-dialog-scrollable relative w-auto pointer-events-none">
<div className="modal-content border-none shadow-lg relative flex flex-col w-full pointer-events-auto bg-white bg-clip-padding rounded-md outline-none text-current">
<div className="modal-header flex flex-shrink-0 items-center justify-between p-4 border-b border-gray-200 rounded-t-md">
<h5 className="text-xl font-medium leading-normal text-gray-800" id="exampleModalCenteredScrollableLabel">
Modal title
</h5>
<button type="button"
className="btn-close box-content w-4 h-4 p-1 text-black border-none rounded-none opacity-50 focus:shadow-none focus:outline-none focus:opacity-100 hover:text-black hover:opacity-75 hover:no-underline"
data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div className="modal-body relative p-4">
<p>This is some placeholder content to show a vertically centered modal. We've added some extra copy here to show how vertically centering the modal works when combined with scrollable modals. We also use some repeated line breaks to quickly extend the height of the content, thereby triggering the scrolling. When content becomes longer than the predefined max-height of modal, content will be cropped and scrollable within the modal.</p>
<p>Just like that.</p>
</div>
<div
className="modal-footer flex flex-shrink-0 flex-wrap items-center justify-end p-4 border-t border-gray-200 rounded-b-md">
<button type="button"
onClick={handleCloseClick}
className="inline-block px-6 py-2.5 bg-purple-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-purple-700 hover:shadow-lg focus:bg-purple-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-purple-800 active:shadow-lg transition duration-150 ease-in-out"
data-bs-dismiss="modal">
Close
</button>
<button type="button"
className="inline-block px-6 py-2.5 bg-blue-600 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-blue-700 hover:shadow-lg focus:bg-blue-700 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-blue-800 active:shadow-lg transition duration-150 ease-in-out ml-1">
Save changes
</button>
</div>
</div>
</div>
</div>
) : null
);
};
export default Modal;
Below you can find the code that contains the table and the 'Add' button that should show the Modal.
import ProjectCols from '../data/projectcols';
import DataTable from 'react-data-table-component';
import React, { useState } from 'react';
import Modal from './modal';
const Table = () => {
const [showModal, setShowModal] = useState(false);
const data = [
{
id: 1,
project: 'Test Project A',
client: 'Customer A',
pm: 'John Doe',
active: true
},
{
id: 2,
project: 'Test Project B',
client: 'Customer B',
pm: 'Jane Doe',
active: false
}
];
return (
<div className="bg-slate-100 h-screen w-full overflow-y-auto">
<div className='flex justify-end h-20 w-3/4 m-auto'>
<div className='flex space-x-2 h-full'>
<button type='button' onClick={() => setShowModal(true)} className='self-center inline-block px-6 py-2.5 bg-green-500 text-white font-medium text-xs leading-tight uppercase rounded shadow-md hover:bg-green-600 hover:shadow-lg focus:bg-green-600 focus:shadow-lg focus:outline-none focus:ring-0 active:bg-green-700 active:shadow-lg transition duration-150 ease-in-out'>Add</button>
<Modal onClose={() => setShowModal(false)} show={showModal}></Modal>
</div>
</div>
<div className='w-3/4 m-auto'>
<DataTable
columns={ProjectCols}
data={data} //This will need to be retrieved from the database
direction="auto"
fixedHeaderScrollHeight="300px"
pagination
responsive
/>
</div>
</div>
);
};
export default Table;
When I click the 'Add' button however, nothing happens. The modal does not get shown. I added a console.log in the Modal component just to check if it got called by the 'Add' button function and it did but I still cannot figure out why the modal doesn't show.
I'm using Tailwind CSS in my project and the table page is part of bigger page that contains a sidebar. You can find that code below:
import { useAuth } from '../../../lib/hooks/auth';
import SideBar from '../../../components/sidebar/sidebar';
import Table from '../../../components/table';
const ProjectOverview = () => {
const { user, loading, error, loggedIn } = useAuth();
return (
<div className='flex'>
{loading && <p>Loading...</p>}
{error && <p>An error occured...</p>}
{loggedIn && (
<SideBar user={user} /> //Pass in the user role as a prop to decide which items to show in the sidebar
)
}
<Table />
</div>
);
};
export default ProjectOverview;
Can anyone explain me what I'm doing wrong? Is it CSS related or is there another thing that is blocking the modal of being displayed on screen?
Thanks!
Found it! I copied pasted the Modal code from a tutorial and didn't notice that the top of the modal component had a 'hidden' class property in it... Removed it and now everything works fine!
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 have the following React code (+Tailwind CSS):
<section className={"flex flex-col items-center"}>
{managers.map((manager) => (
<UserCard user={manager} />
))}
<section className={"flex flex-row"}>
{coWorkers.map((coWorker) => (
<UserCard user={coWorker} isMarked={user.id === coWorker.id} />
))}
</section>
{engineers.map((engineer) => (
<UserCard user={engineer} />
))}
</section>
While UserCard is simple as:
export default function Error({ user, isMarked }: Props) {
return (
<article
className={`bg-purple-500 shadow-lg m-3 p-3 text-white rounded-lg ${
isMarked && "border-4 border-purple-800 font-bold"
}`}
>
<h1>
{user.firstName} {user.lastName}
</h1>
<h2>{user.email}</h2>
</article>
);
}
The issue: the Cards are not in the same width, e.g:
Any idea how I can make sure they are in the same width using tailwindcss? (in each row/column)
You can specify a fix width to the main div
flex flex-col items-center w-1/3
Then for each child have full width
bg-purple-500 shadow-lg m-3 p-3 text-white rounded-lg w-full