AirBnb two column sticky Mapbox with results scroll - React, Mapbox, Tailwind - reactjs

I'd like to create the desired results as seen here.
Please view in Desktop widescreen. AirBnb results.
As you can see with the AirBnb results, the Map on the Righthand side sticks perfectly into place while allowing the user to scroll down to view the results on the Lefthand side.
I've been trying to figure out how they have achieved this but am reaching some road blocks. I found some luck with implementing this bit of code but there is still a slight amount of vertical scrolling before the bottom of the map snaps into place. I believe it has to do with the h-screen class making the map height: 100vh
<main className="flex">
{/* Results & Filters section - Left side */}
<section className='flex-grow'>
<div className='lg:inline-flex mt-5 mb-5 space-x-3 text-gray-800 whitespace-no-wrap'>
<p className='custom-button'>Cancellation Flexibility</p>
<p className='custom-button'>Type of Place</p>
<p className='custom-button'>Price</p>
<p className='custom-button'>Rooms and Beds</p>
<p className='custom-button'>More Filters</p>
</div>
<div className="flex flex-col">
{/* Search results */}
{searchResults.map(
({ img, location, title, description, star, price, total }) => (
<InfoCard
key={img}
img={img}
location={location}
title={title}
description={description}
star={star}
price={price}
total={total}
/>
))}
</div>
</section>
{/* Map section - Right side */}
<aside className="hidden h-screen w-[50%] sticky xl:inline-flex l:min-w-[600px] top-0">
<Map searchResults={searchResults} />
</aside>
</main>
Some help would be greatly appreciated. I've started a codesandbox to make it easier to see what I'm experiencing. Please view in Desktop widescreen
https://codesandbox.io/s/determined-bartik-2tftc?file=/pages/index.js

[Edit] : I just noticed the left side is hidden by the map now since the map is out of the flex flow. I'll keep the answer as an idea. If you can manipulate the architecture of the page, it's easy to fix.
Looks like applying :
position: fixed;
right: 0;
justify-content: end;
to the aside tag that contains the map and removing its top-0 class fix your problem. I see that you are using an external library to display the map so I don't know if there is a way to apply css to it since I can't edit the codesandbox sorry. You could just wrap it in a span with a class and target it with .my-class > aside in your css. But first check the documentation, they are probably exposing some classes for you to apply styles.

So I seemed to have solved this. Took a bit of work but I achieved the result I was looking for.
I added some root css here in globals.css file
:root {
--navigation-bar-offset: 90px;
--gp-placement-max-height: calc(100vh - var(--navigation-bar-offset, 80px));
}
I utilized these root class names to be used in index.js on the component parent div
<div className="w-full
sticky
top-[var(--navigation-bar-offset,80px)]
h-[var(--gp-placement-max-height,auto)]">
<MapBox searchResults={searchResults} />
</div>
I also found, that Mapbox was overriding my height from it's setViewport callback in Map.js. So I overrode Mapbox by adding this code in Map.js in the onViewportChange.
onViewportChange={nextViewport => setViewPort({ ...nextViewport, width: "100%", height: "100%" })}
I updated the Codesandbox to reflect these changes.
Also, if you resize the browser, it maintains height and width.

Related

React, Nextjs, TailwindCSS. Scroll not working

I am facing a problem that in React Next.js, I am unable get the scroll bar vertically. This is my code:
<div className=" hover:bg-violet-400 box-content overflow-y-scroll w-4000">
<div ref={scrollRef}>
{message.map((m) => (
<Message
message={m}
own={m.sender === sender[0]._id}
/>
))}
</div>
</div>
I am using Tailwind Css in this project. The 'overflow-y-scroll' doesnt work. The overflow still happens even this property is empty.
You need to define the height of your div to make your content scrollable inside it. And I just noticed you used w-4000 which is not a tailwind class. So change this as well.
You should remove w-4000 and add w-screen then If your content takes more space than the width, the vertical scrollbar will be available

React-Spring is not animating

So I am trying to animate a container with an background image and some text. I have set a config of duration and opacity of 0 to an opacity of 1 but the component loads normally. I do have the component as part of a private route. Its the page that displays after loggin in.
to= {{opacity:1, marginTop:0 }}
config = {{delay:4000, duration:4000}}>
{(props) => (
<div style={props}>
<div style={{ backgroundImage: `url(${cancer})`}} className="container-img">
<h2> What is Cancer?</h2>
<p className="paragraph">
The dogmatic view of cancer has been around for a long time.
This view is called the Somatic Mutation Theory. This Theory is
believed that cancer arises from damaged DNA in the cells that
causes out of ccontrol growth.
</p>
<p className="paragraph">
New Evidence shows that Cancer is caused by the damage to the
mitochondria causing the cells to fall back on ancient pathways
of fermentation. Cancer cells ferment Glucose and/or Glutamine
for energy or ATP.
</p>
<p className="paragraph">
If Cancer is a genetic disease, then why when they did a
scientic experiment in the 1960's where they took the
mitochondria of a cancer cell and put it in a normal cell the
cell turned cancerous. This theory is called the Metabolic
Theory of Cancer.
</p>
</div>
</div>
)}
</Spring>
</>
);
};
You're passing SpringValues to a regular dom element:
<div style={props}>
What you want to be doing is passing them to an animated element:
// import { animated } from 'react-spring'
<animated.div style={props}>
As described in the docs

I want to use RTL, but not through all of my components

I want to use RTL for some of my components in Nextjs. I also use material-ui. Unfortunately when I change direction in _documents.js with <HTML dir="rtl">, the direction of all of my components will change. material-ui's direction in createMuiTheme() doesn't affect direction at all.
Some of the components (like arrows) must not change based on direction. What should I do in order to keep them safe from changing direction.
Material Ui createMuiTheme get direction as an option itself
I also remember that it respect the direction of body tag
So for changing the direction of some part of your component, you have 3 ways as I know.
Change direction option in material createMuiTheme
It could be handle via your theme provider component for example
Use other instance of material Theme provider around your rtl components
Theme nesting
Put dir="rtl" on native DOM tags these will affect all lower subtree styles if you want e.g. flex-box direction and ...
for example
const ARABIC_PATTERN = /[\u0600-\u06FF]/
const getDirection = text => (ARABIC_PATTERN.test(text) ? 'rtl' : 'ltr')
<div dir={getDirection('what you want to test')}>
<Components />
</div>
Hacky suggestion. It's probably not the best answer, but it might be handy/decent if you need to just "reset" the position of 1-2 elements.
First invert everything like your are doing, then put a CSS class on the elements that shall not be "inverted":
.not-rtl-inteverted {
transform: scaleX(-1);
}
This way, you are basically inverting everything, and then inverting once again the elements with the class above.
section {
display: flex;
justify-content: space-around;
}
div {
background: green;
padding: 20px;
margin: 0 10px;
flex-basis: 33%;
}
.rtl {
transform: scaleX(-1);
}
<section>
<div>
<p>No RTL</p>
</div>
<div>
<p>Yes RTL</p>
</div>
<div>
<p>Yes RTL - but reset it on the 2nd line (by applying the same CSS class again)</p>
</div>
</section>
<section>
<div>
<p>text 1</p>
<p>text 2</p>
</div>
<div class="rtl">
<p>text 1</p>
<p>text 2</p>
</div>
<div class="rtl">
<p>text 1</p>
<p class="rtl">text 2</p>
</div>
</section>
In the example, by using twice the same class (once in the parent and once again the children that doesn't need to be rtl'd, we have this reset effect).
Again, might be handy for very simple use cases. I won't suggest this as a general solution to your problem.

How to put a logo in React Material UI Toolbar

I want to put a logo on the left side of the Toolbar in React (Material-UI Apppbar), but I don't get why it doesn't work. The logo is not showing at all.
import logo from '../../assets/companylogo.png';
const useStyles = makeStyles((theme) => ({
...
logo: {
width: '10%',
},
...
}));
<AppBar position='sticky'>
<Toolbar className={classes.toolbar} variant='dense'>
<img scr={logo} className={classes.logo}/>
<div className={classes.search}>
...
</div>
<div className={classes.grow} />
<div className={classes.sectionDesktop}>
...
</div>
<div className={classes.sectionMobile}>
...
</div>
</Toolbar>
</AppBar>
When <img/> is included I can see the width changes on the left depending on what the width of the logo is set to.
Here it is without the <img/>
I tried different images both .png and other formats, but id doesn't solve anything. I made sure the path to images is correct and also tried to wrap the <img/> with <div></div>, but nothing solved it. I thought it might be a z-index issue and the image is simply hiding behind the Toolbar, but that doesn't make sense to me and after playing a bit with zIndex value for image it didn't solve it either. I'm out of ideas here.
Any idea what am I doing wrong here?

make flex-item honour width only if there is content

I want create a flex-item which takes a width of 33% of the container only if there is some content present as follows:
<FlexItem width='33%'> <Somedom /> </FlexItem>
Here, the FlexItem is a component that can take all flex properties as props and renders a div. Now, Somedom can render null in the dom in which case I want the FlexItem to take no width at all and allow the sibling div to fill the entire container.
I was wondering if there is any flex based arrangement which can help me achieve that. Further I have no good way of knowing if its going to render content or not. I don't want to move FlexItem component in Somedom as well.
Using #04FS suggestion of :empty
You could do something as simple as this.
.FlxRw {
display: flex;
}
.Flx {
flex:0 0 33%;
background:#cdf;
}
.Flx:empty {
flex:0 0 0%;
}
<div class="FlxRw">
<div class="Flx"></div>
</div>
<div class="FlxRw">
<div class="Flx">Content</div>
</div>
<div class="FlxRw">
<div class="Flx"></div>
</div>

Resources