Problem with Load More functionality and responsiveness - reactjs

I'm having trouble with the responsiveness of rendered items from an array of objects that are loaded by clicking a 'Load More' button. On every click 3 extra items are visible. So far so good. But when the screen-width gets smaller I want to render only two items per click and in the end only one item. The problem is that media queries, css-grid or flex-box and the load functionality presets, in the component, cancel each other out. If I want two items rendered I have to adjust the CSS rules and the actual JS code presets like the posts-per-page. In other words how to create a responsive 'Load More' functionality in react (hooks).
The component
const [ soldProperties, setSoldProperties ] = useState([])
const [ loadBtn, setLoadBtn ] = useState('Show More')
const [ currentSlice, setCurrentSlice ] = useState(3)
const [ perPage, setPerPage ] = useState(3)
useEffect(()=> {
setSoldProperties(soldProps.slice(0, currentSlice))
}, [currentSlice, soldProperties.length])
const loadMore = () => {
setCurrentSlice(currentSlice + perPage)
if (soldProperties.length === 6) {
setLoadBtn('Show Less')
}
if (soldProperties.length === soldProps.length){
setCurrentSlice(currentSlice - 6)
setLoadBtn('Show More')
}
}
return (
<div className="soldprops">
<div className="soldprops_header">Sold Properties:</div>
<div className="soldprops_grid">
{soldProperties && soldProperties.map(property => {
const { img, name, price, id } = property
return <div className="soldprops_grid_imageBox" key={id}>
<div className="image"><img src={process.env.PUBLIC_URL + `/soldProps/${img}`} alt="" style={{ width: '100%', height: 'auto' }} /></div>
<div className="footer"><span className="soldChateau">{name}</span><span className="soldPrice">${price},-</span></div>
</div>
})}
</div>
<button type="button" className="loadmoreBtn" onClick={loadMore} >{loadBtn}</button>
</div>
)
}
The scss
.soldprops {
position: relative;
max-width: 1920px;
margin: 0 auto;
height: auto;
#include center-content-column;
&_header {
width: 100%;
height: 50px;
color:rgb(163, 149, 184);
padding: 0 20px;
font-size: 1.2rem;
font-family: Arial, Helvetica, sans-serif;
#include center-content-row-start;
}
&_grid {
width: 100%;
padding: 0 20px;
margin-bottom: 50px;
height: auto;
#include center-content-row;
flex-wrap: wrap;
gap: 15px;
// display: grid;
// grid-template-columns: repeat(3, 1fr);
// grid-template-rows: repeat(1, 1fr);
// gap: 20px;
&_imageBox {
position: relative;
width:32%;
height: auto;
line-height: 0;
box-shadow: 0px 4px 4px rgb(11, 9, 14);
.image {
width: 100%;
height: auto;
opacity: 1;
}
}
}

Related

scroll event and responsiveness in react

i'm trying to somewhat replicate this parallax feature that i found on the website https://spacers.wannathis.one/ (scroll to "12 different poses" section) with React. Here's an example of my code so far:
const App = () => {
const [scrollX, setScrollX] = useState(0);
const [scrollY, setScrollY] = useState(0);
const [marginTop, setMarginTop] = useState();
const [position, setPosition] = useState("static");
const [top, setTop] = useState();
const [left, setLeft] = useState();
useEffect(() => {
const handleScroll = (event) => {
setScrollY(Math.round(window.scrollY));
if (window.scrollY > 2070 && window.scrollY < 6112) {
setMarginTop(0 + "px");
setLeft((-window.scrollY +2525) * 0.55 + "px");
setPosition("fixed");
setTop(window.scrollY * 0.005 + "px");
}
if (window.scrollY <= 2070) {
setPosition("initial");
}
if (window.scrollY >= 6112) {
setPosition("absolute");
}
};
window.addEventListener("scroll", handleScroll);
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []);
return (
<div className="page">
<section className="title_wrapper">
<h3>My projects</h3>
</section>
<section
className="scroll_wrapper"
style={{
marginTop: marginTop,
position: position,
top: top,
left: left,
}}
>
<div className="images_wrapper">
<div className="images_container">
<img src={pic1} />
</div>
<div className="images_container">
<img src={pic2} />
</div>
</div>
</section>
</div>
CSS:
.page {
width: 100vw;
overflow: auto
height: 100vw
display: flex
align-items: center;
position: relative
.title_wrapper {
position: absolute;
display: flex;
.scroll_wrapper {
margin-left: 0px;
display: flex;
overflow: hidden;
width: auto;
justify-content: flex-start;
align-items: center;
z-index: 10;
vertical-align: middle;
margin-top: 0px;
}
.images_wrapper {
overflow-x: hidden;
display: flex;
width: 100%;
align-items: center;
gap: 30px;
max-height: 100vh;
position: absolute;
vertical-align: middle;
top: 10px;
white-space: nowrap;
flex-direction: row;
flex-wrap: nowrap;
left: 100px;
}
h3 {
z-index: 10;
position: absolute;
top: 0;
left: 10px;
}
.image_container {
max-width: 10vw;
width: 10vw;
}
img {
width: 100%;
height: auto;
}
The scroll effect seems to be working fine but whenever i resize the window everything breaks and i'm guessing it might be because the scrollY value should get smaller as the window resizes. I have no idea how to fix it, can somebody help?

Does anyone know how to fix this ?( Dynamic nth-child & after ) react-sass

I'm trying to figure it out, but I haven't been able to...
It's a list with information and it's really almost ready, but the nth-child:after style I can't make it dynamic with react.
My React component:
const PieList = ({ data, colors = [] }: IPieListProps) => {
return data.length > 1 ? (
data.map(( item, index ) => (
<div
key={item.name}
className={styles['pie-list']}
style={{
backgroundColor: colors[index%colors.length]
}}
>
<ul>
{
item.name === 'others'
? <li>Otros<span>{item.value}</span> </li>
: <li>{item.name}<span>{item.value}</span></li>
}
</ul>
</div>
))
) : ''
}`
.pie-list {
ul {
max-width: 240px;
li {
&::after {
content: '';
width: 8px;
height: 8px;
border-radius: 8px;
position: absolute;
left: 0;
top: 0;
bottom: 0;
margin: auto;
}
&:nth-child(1){
&::after {
background-color: $orion;
}
}
&:nth-child(2){
&::after {
background-color: #433F5C;
}
}
&:nth-child(3){
&::after {
background-color: #898798;
}
}
}
}
}
I am trying to get this result:
But I have this:
you should try this:
ul {
list-style: none;
}
ul li::before {
content: "\2022";
color: red;
font-weight: bold;
display: inline-block;
width: 1em;
margin-left: -1em;
}
I solved it with a package called "styled-components", but if someone has a better solution that doesn't involve a library that would be great.
const Bullet = styled.div`
max-width: 240px;
li{
position: relative;
margin-bottom: 10px;
padding-left: 14px;
font-size: 14px;
color: $orion;
display: flex;
align-items: center;
justify-content: space-between;
&::after {
content: '';
width: 8px;
height: 8px;
background-color: ${ props => props.bulletColor };
border-radius: 8px;
position: absolute;
left: 0;
top: 0;
bottom: 0;
margin: auto;
}
`
export const PieBanksList = ({ data, colors }: IPieBanksListProps) => {
return data.length > 1 ? (
data.map(( item, index ) => (
<div
key={item.name}
className={styles['pie-list']}
>
<Bullet
bulletColor={colors[index % colors.length]}
>
{
item.name === 'others'
? <li>Otros<span>{item.value}</span> </li>
: <li>{item.name}<span>{item.value}</span></li>
}
</Bullet>
</div>
))
) : <EmptyGraph />
}

Structuring Sidebar in React

Relatively new to React, and am wanting to recreate the design below
enter image description here
I have the base formatting down, but as you will notice, there are lines separating the logo blocks, from the login and signup blocks, with the signup and login buttons pushed to the bottom.
Below is my current code
CSS:
width: 100vw;
height: 100vh;
}
body {
margin: 0;
padding: 0;
}
.Sidebar {
height: 100%;
width: 20%;
background-color: white;
border-right: 1px solid #F0F4FB;
padding-left: 15px;
box-sizing: border-box;
}
.SidebarList {
height: auto;
width: 100%;
padding-left: 15px;
font-size: 18px;
border: 2px #FD954E;
box-sizing: border-box
}
.SidebarList .row {
width: 100%;
height: 50px;
background-color: white;
list-style-type: none;
margin: 0%;
padding-bottom: 15px;
display: flex;
color: #A7ACB6;
justify-content: center;
align-items: center;
font-family: Arial, Helvetica, sans-serif;
}
.SidebarList .row:hover {
cursor: pointer;
background-color: #E7E7E7 ;
}
.SidebarList #active {
background-color: white;
color: #FD954E
}
.SidebarList .Login {
background-color: white;
color: #FD954E;
width: 279px;
height: 39px;
right: 1596px;
top: 958px;
border: 1px solid #FD954E;
box-sizing: border-box;
border-radius: 19.5px;
}
.SidebarList .SignUp {
width: 279px;
height: 39px;
right: 1596px;
top: 1011px;
background: #FD954E;
border-radius: 19.5px;
border: none;
}
.row #icon {
flex: 30%;
display: grid;
place-items: center;
transform: scale(1.2)
}
.row #title {
flex: 70%;
}
.Logo {
padding-left: 25px;
padding-top: 25px;
padding-bottom: 30px;
border-bottom: 1px solid #F0F4FB;
width: 55%;
}
Sidebar.js
import React from "react";
import "../App.css";
import { SidebarData } from './SidebarData'
import Logo from './Logo.svg'
function Sidebar() {
return (
<div className="Sidebar">
<div>
<img src = {Logo} alt='Logo’ className=‘Logo’ />
</div>
<ul className="SidebarList">
{SidebarData.map((val, key) => {
return (
<li
key={key}
className="row"
id={window.location.pathname == val.link ? "active" : ""}
onClick={() => {
window.location.pathname = val.link;
}}
>
<div id="icon">{val.icon}</div> <div id="title">{val.title}</div>
</li>
);
})}
</ul>
<div className= "SidebarList">
<button className="Login">
Login
</button>
</div>
<div className= "SidebarList">
<button className="SignUp">
Sign Up
</button>
</div>
</div>
);
}
export default Sidebar;
How should I structure my code in order to acheive my desired result? Ex: with the logo at the top with the seperator, the list of navigation elements, and then the login and signup buttons at the bottom with the seperator?
Currently, my sidebar looks as follows, with the seperator not full width between the logo and navigation elements, and the buttons extending beyond the sidebar.
enter image description here
It would be easier to simplify the problem with just HTML and CSS as that's much easier to troubleshoot. Part of your problem is that you are defining the width of the sidebar as a percentage of the screen width but elements within the sidebar are defined with a width in pixels. When the browser window is too small, your buttons will appear outside the full width of the sidebar. You could either code all your values as percentages or in pixels. Alternatively, you could use a mix and just set a min-width for the sidebar so that you don't end up with elements out of place.
The reason that your line break is not the full width of your sidebar is because you are defining it with the border-bottom property of the logo. Your logo is not 100% the width of the sidebar so your line break will only be the width of the logo. A better solution would be to define a div that is set to width: 100%. This way, you will have more control.
Here is a simplified solution to your sidebar problem using pixels to define the widths.
HTML:
<div class="sidebar">
<div class="header">
<div class="logo">Logo</div>
</div>
<div class="line-break" />
<div class="content">
<ul class="nav">
<li>Home</li>
<li>Blog</li>
</ul>
</div>
<div class="line-break" />
<div class="footer">
<button class="login">Login</button>
<button class="sign-up">Sign up</button>
</div>
</div>
CSS:
html, body {
height: 100%;
margin: 0;
padding: 0;
}
.sidebar {
width: 300px;
height: 100%;
border-right: 1px solid grey;
}
.line-break {
height: 1px;
width: 100%;
background-color: grey;
}
.header .logo {
height: 40px;
width: 200px;
background-color: grey;
margin: 20px;
}
ul.nav {
list-style-type: none;
padding: 20px 0 0 40px;
}
ul.nav li {
margin-bottom: 14px;
}
ul.nav li:last-child {
margin-bottom: 0;
}
.footer {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 0;
}
.footer button {
padding: 6px 0;
width: 80%;
margin-bottom: 14px;
}
.footer button:last-child {
margin-bottom: 0;
}
And here is a link to a CodePen
where you can see this in action.

Pushing Sign Up & Login buttons to bottom of sidebar

I am trying to recreate this design:
Click to view
However, the below is currently occurring.
Click to view
I am trying to push the SignUp and Login buttons to the bottom of the sidebar to match the first image. Am I missing a CSS class that would allow me to do so, or would this be a JS configuration? Hope I have not overlooked something basic that would allow me to achieve this state.
Sidebar.js
import React from "react";
import "../App.css";
import { SidebarData } from './SidebarData'
import Logo from './Logo.svg'
import { Login } from './Login'
import { SignUp } from './SignUp'
function Sidebar() {
return (
<div className="Sidebar">
<div className="Header">
<div><img src = {Logo} alt='Logo’ className='Logo’ /></div>
</div>
<div class="line-break" />
<ul className="SidebarList">
{SidebarData.map((val, key) => {
return (
<li
key={key}
className="row"
id={window.location.pathname == val.link ? "active" : ""}
onClick={() => {
window.location.pathname = val.link;
}}
>
<div id="icon">{val.icon}</div> <div id="title">{val.title}</div>
</li>
);
})}
</ul>
<div class="line-break" />
<div className="footer">
<ul className= "SidebarList">
{Login.map((val, key) => {
return (
<li
key={key}
className="Login"
id={window.location.pathname == val.link ? "active" : ""}
onClick={() => {
window.location.pathname = val.link;
}}
>
<div id="title">{val.title}</div>
</li>
)}
)}
</ul>
<ul className= "SidebarList">
{SignUp.map((val, key) => {
return (
<li
key={key}
className="SignUp"
id={window.location.pathname == val.link ? "active" : ""}
onClick={() => {
window.location.pathname = val.link;
}}
>
<div id="title">{val.title}</div>
</li>
)}
)}
</ul>
</div>
</div>
Here is CSS
.App {
width: 100vw;
height: 100vh;
}
body {
margin: 0;
padding: 0;
}
.Sidebar {
height: 100%;
width: 300px;
background-color: white;
border-right: 1px solid #F0F4FB;
padding-left: 15px;
box-sizing: border-box;
}
.SidebarList {
height: auto;
width: 100%;
padding-left: 15px;
font-size: 18px;
border: 2px #FD954E;
box-sizing: border-box
}
.SidebarList .row {
width: 100%;
height: 50px;
background-color: white;
list-style-type: none;
margin: 0%;
padding-bottom: 15px;
display: flex;
color: #A7ACB6;
justify-content: center;
align-items: center;
font-family: Arial, Helvetica, sans-serif;
}
.SidebarList .row:hover {
cursor: pointer;
background-color: #E7E7E7 ;
}
.SidebarList #active {
background-color: white;
color: #FD954E
}
.SidebarList .Login {
background-color: white;
color: #FD954E;
width: 90%;
height: 5vh;
right: 1596px;
top: 958px;
border: 1px solid #FD954E;
box-sizing: border-box;
border-radius: 19.5px;
text-align: center;
font-family: Arial, Helvetica, sans-serif
}
.SidebarList .SignUp {
width: 90%;
height: 5vh;
right: 1596px;
top: 1011px;
background: #FD954E;
border-radius: 19.5px;
border: none;
text-align: center;
font-family: Arial, Helvetica, sans-serif;
}
.row #icon {
flex: 30%;
display: grid;
place-items: center;
transform: scale(1.2)
}
.row #title {
flex: 70%;
}
.Logo {
padding-left: 25px;
padding-top: 25px;
padding-bottom: 30px;
width: 55%;
}
.line-break {
height: 1px;
width: 100%;
background-color: #F0F4FB;
}
ul.nav {
list-style-type: none;
padding: 20px 0 0 40px;
list-style-type: none;
}
ul.nav li {
margin-bottom: 14px;
list-style-type: none;
}
ul.nav li:last-child {
margin-bottom: 0;
list-style-type: none;
}
.footer {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px 0;
}
.footer button {
padding: 6px 0;
width: 80%;
margin-bottom: 14px;
}
.footer button:last-child {
margin-bottom: 0;
}
.header .Logo {
height: 40px;
width: 200px;
background-color: grey;
margin: 20px;
}
Without seeing the source for the entire page and not just a couple of the buttons, it is impossible to say for sure, but my guess would be the following is causing your problem:
.Sidebar {
height: 100%;
...
}
Setting height: 100% will only tell the sidebar to take up 100% of the space it needs for its content (or 100% of the height of its bounding container, depending on the display properties of both). I would recommend changing it to this to solve your problem:
.Sidebar {
min-height: 100vh;
...
}

gridArea React inline style with a variable

I'm trying to return a number of divs and dynamically place them in a grid. I've never tried this before, and I think my syntax may be off. None of the divs are appearing. The template is working, and the divs should currently fill grid container and turn it black with a button.
export const DayColumn = ({ day }) => {
const { timeColumn } = useTableContext();
return (
<Wrapper gridInterval={timeColumn.length}>
<h2>{day}</h2>
{timeColumn.forEach((_, index) => {
index++;
return (
<div
key={index}
className='task-slot'
style={{ gridArea: `${index + 1} / 1 / ${index + 2} / 2;` }}
>
<h1>text</h1>
<BsPlusSquareFill />
</div>
);
})}
</Wrapper>
);
};
The styled component
const Wrapper = styled.div`
height: 100%;
display: grid;
grid-template-columns: 1fr;
grid-template-rows: ${(props) => `100px repeat(${props.gridInterval}, 1fr);`};
grid-gap: 3px;
background-color: var(--clr-background-dark3);
border-radius: 7px;
h2 {
justify-self: center;
font-family: 'Oswald', sans-serif;
letter-spacing: 4px;
font-size: 2rem;
font-weight: 200;
color: var(--clr-text-light);
text-transform: capitalize;
}
.task-slot {
height: 100%;
width: 100%;
background-color: black;
}
`;
I fixed it. Needed to use map instead of forEach

Resources