Error:
./src/card.js
Attempted import error: 'Bottom' is not exported from './styles/cards.style'.
card.js
import React from 'react'
import {
Bottom,
Color,
Text,
Image
} from "./styles/cards.style";
function Card(props) {
return (
<div>
<Bottom>
<Color />
<Text>{props.text}</Text>
<Text>{props.text}</Text>
</Bottom>
<Image
alt=""
src={props.image}
/>
</div>
);
}
export default Card;
cards.style
import styled from "styled-components";
export default {
colors: {
black: "rgba(0,0,0,1)",
brandPrimary: "rgba(238,120,36,1)",
brandPrimaryLight: "rgba(255,184,8,1)",
brandTertiary: "rgba(0,65,125,1)",
darkSlateGray: "rgba(51,51,51,1)",
white: "rgba(255,255,255,1)"
},
fonts: {
uiMainContent: {
family: "Poppins",
size: "15px",
weight: "300",
lineHeight: "21px"
},
uiSubContent: {
family: "Poppins",
size: "13px",
weight: "300",
lineHeight: "20px"
}
}
};
export const Bottom = styled.div`
width: 100%;
height: calc(100% - 20px);
background-color: ${props => props.theme.colors.white};
border-radius: 4px;
padding: 0 0 20px;
display: flex;
flex-direction: column;
align-items: flex-start;
position: relative;
`;
export const Color = styled.div`
height: 120px;
background-color: ${props =>
props.theme.colors.brandPrimary};
margin-bottom: 16px;
border-radius: 4px 4px 0px 0px;
align-self: stretch;
`;
export const Text = styled.p`
color: ${props => props.theme.colors.black};
margin-left: 16px;
letter-spacing: 0.1px;
font-family: ${props =>
props.theme.fonts.uiSubContent.family};
font-size: ${props =>
props.theme.fonts.uiSubContent.size};
font-weight: ${props =>
props.theme.fonts.uiSubContent.weight};
line-height: ${props =>
props.theme.fonts.uiSubContent.lineHeight};
&:not(:last-of-type) {
margin-bottom: 4px;
}
`;
export const Image = styled.img`
width: 150px;
height: 92px;
position: absolute;
left: 29px;
top: 14px;
`;
I am trying to build cards in reactjs. I usually stick to scss however cannot use props with scss which I will have to use later to dynamically generate components. Not sure what is wrong here as I did export Button. Please can someone shed some insight you see what is so blatantly wrong it is causing this error.
in that case you have an export default as the first thing of you code, if you are exporting more than one thing from the same file, you should stick to exporting each const/function by itself and not having any export default
If you are using ReactJS/NextJS I would really recommend creating a global theme that you normally write and import with the application, so you could have things like
// global.js
const GlobalStyle = createGlobalStyle`
* {
box-sizing: border-box;
}
:root {
--black: rgba(0,0,0,1);
--brandPrimary: rgba(238,120,36,1);
...
...
`
}
Take a look here, it should help you a lot.
Related
I use scss and styled-components together. Recently I don't know why I started to see a race situation over which styles get applied on the final render. Sometimes, usually, when the app is loaded for the first/second time, styles from scss gets applied and when I do a couple of hard refreshes my custom styles written with styled-components get applied. Do you have any idea why is this happening? I don't want to put it! important everywhere to fix it. I would like to understand it.
The below screenshot shows that _sidebar.scss overrode .sidebar styles I wrote.
after some hard refreshes:
after some refreshes, it is another way around:
Here is a component
/* eslint-disable jsx-a11y/anchor-is-valid */
import React from 'react';
import SidebarLinks from './SidebarLinks';
import FormSelectPrinter from "../printer/FormSelectPrinter"
import sidebarData from "../data/";
import {ModalConsumer} from "../components/ModalContext";
import Modal from "../components/Modal";
import { createGlobalStyle } from "styled-components";
const GlobalSidebarStyle = createGlobalStyle`
.sidebar {
background-color: #303b4a;
padding-left: 0;
padding-right: 0;
padding-bottom:40px;
width: 240px;
}
.user__info {
background: #607D8B;
}
.user__info:hover {
background: #607D8B;
}
.user__name {
color: #fff;
}
.user__email {
color: #303b4a;
}
.dropdown-user-menu {
background: #607D8B;
position: relative;
width: 100%;
float: none;
}
.dropdown-select-language {
background: rgba(96, 125, 139, 0.6);
box-shadow: 0 4px 20px rgba(0,0,0,0.9);
right: -26px;
top: 53px;
user-select: none;
}
.dropdown-user-item:hover, .dropdown-user-item:focus {
color: black !important;
}
.dropdown-user-item {
color: white !important;
}
.navigation {
li {
a {
color: #adb5bd;
padding-left: 15px;
&.active {
color: white !important;
}
}
}
}
.navigation li:not(.navigation__active):not(.navigation__sub--active) a:hover {
background-color: rgba(0, 0, 0, 0.19);
color: white;
}
.id-green {
background-color: #73983F;
}
.language-text-color {
color: white !important;
}
.profile_image_style {
border-radius: 100%;
width: 80px;
height: 80px;
}
`
function Sidebar(props) {
const ModalSelectPrinter = ({onClose, ...otherProps}) => {
return (
<Modal>
<FormSelectPrinter onClose={onClose} md={12}></FormSelectPrinter>
</Modal>
)
};
return (
<>
<GlobalSidebarStyle />
<aside className={`sidebar ${props.sidebarToggled? 'toggled' : ''}`}>
<div className="scrollbar-inner">
<div style={{margin: '50px 0 30px 0'}} onClick={() => props.toggleUserInfo()}>
<div className={`user__info ${props.userInfoShown? 'show' : ''}`}>
<div style={{width: '100%', textAlign: 'center'}}>
<div className="user__name">{user.person === null ? user.name : user.person.full_name}</div>
<div className="user__email">{user.email}</div>
</div>
</div>
<div
className={`dropdown-menu dropdown-user-menu ${props.userInfoShown? 'show' : ''}`}>
<ModalConsumer>
{({showModal}) => (
<a className="dropdown-item dropdown-user-item" onClick = {()=>showModal(ModalSelectPrinter, {})}>Select</a>
)}
</ModalConsumer>
<a className="dropdown-item dropdown-user-item" onClick={() => props.logout()}>Log out</a>
</div>
</div>
<SidebarLinks sidebarData={sidebarData} toggleSidebar={props.toggleSidebar}></SidebarLinks>
</div>
</aside>
</>
)
}
export default Sidebar;
I have built a mobile menu in react that uses the Context API. It works as intended in browser but when on a mobile device the menu lags severely. I have tested in dev tools with CPU throttling and it still didn't lag, but on actual mobile device it slows up significantly. Any help would be greatly appreciated.
Mobile Nav Component:
import { useContext } from "react";
import styled from "styled-components";
import CloseIcon from "../assets/close.svg";
import { NavbarContextList } from "../context/NavbarContext";
import { motion } from "framer-motion";
const NavWrapper = styled(motion.div)`
position: absolute;
top: 0;
height: 100vh;
right: 0;
width: 100%;
z-index: 5;
`;
const NavMain = styled(motion.div)`
width: 100%;
height: 100%;
/* border-top-left-radius: 20px;
border-bottom-left-radius: 20px; */
display: flex;
flex-direction: column;
overflow-y: scroll;
`;
const NavTop = styled.div`
display: flex;
justify-content: space-between;
align-items: center;
padding: 32px 32px 0px 32px;
`;
const NavTitle = styled.h3`
color: #50616b;
`;
const CloseButton = styled.button`
width: 32px;
height: 32px;
border-radius: 8px;
border: none;
`;
const NavM = styled.div`
display: flex;
flex-direction: column;
margin-top: 32px;
padding-left: 64px;
`;
const NavItems = styled(motion.h1)`
font-weight: 700;
font-size: 2rem;
margin-bottom: 32px;
:nth-child(3) {
margin-bottom: 0px;
}
`;
const SocialTop = styled.div`
padding: 32px 32px 0px 32px;
`;
const ContactButton = styled.button`
height: 40px;
padding-right: 24px;
padding-left: 24px;
background: #ff661a;
border: 1px solid rgba(255, 255, 255, 0.39);
box-sizing: border-box;
border-radius: 8px;
font-weight: 700;
font-size: 0.8rem;
color: white;
width: 100%;
`;
const NavBottom = styled.div`
padding-left: 32px;
padding-right: 32px;
position: absolute;
bottom: 32px;
width: 100%;
`;
const variants = {
hidden: {
opacity: 0,
transition: {
duration: 0.05,
},
},
show: {
opacity: 1,
transition: {
staggerChildren: 0.2,
},
},
};
const item = {
hidden: {
opacity: 0,
x: -50,
transition: {
duration: 0.05,
},
},
show: {
opacity: 1,
x: 0,
transition: {
duration: 0.5,
},
},
};
const MobileNav = () => {
const { mobileNav, setMobileNav } = useContext(NavbarContextList);
const toggleMenu = () => {
setMobileNav(!mobileNav);
};
return (
<NavWrapper
key="menu"
exit={{ opacity: 0 }}
initial={{ x: 400 }}
animate={{ x: 0 }}
>
<NavMain
initial="hidden"
animate="show"
variants={variants}
delay="0.5"
className="mobile-nav"
>
<NavTop>
<NavTitle>Navigation</NavTitle>
<CloseButton onClick={toggleMenu} className="toggle">
<img
style={{ paddingTop: "2px" }}
alt="Close Button"
src={CloseIcon}
></img>
</CloseButton>
</NavTop>
<NavM>
<NavItems variants={item} className="nav-item">
Work
</NavItems>
<NavItems variants={item} className="nav-item">
About Me
</NavItems>
<NavItems variants={item} className="nav-item">
Skills
</NavItems>
</NavM>
<SocialTop>
<NavTitle>Social Media</NavTitle>
</SocialTop>
<NavM>
<NavItems variants={item} className="nav-item">
LinkedIn
</NavItems>
<NavItems variants={item} className="nav-item">
Dribble
</NavItems>
</NavM>
<NavBottom>
<ContactButton>Contact Me!</ContactButton>
</NavBottom>
</NavMain>
</NavWrapper>
);
};
export default MobileNav;
Home Component (where the component is rendered)
import "./App.css";
import { useContext } from "react";
import Navbar from "./components/Navbar";
import Background from "./components/Background";
import { AnimatePresence } from "framer-motion";
import MobileNav from "./components/MobileNav";
import { NavbarContextList } from "./context/NavbarContext";
import Hero from "./components/Hero";
import Work from "./components/Work";
function Home() {
const { mobileNav } = useContext(NavbarContextList);
return (
<div className="App">
<Background />
<Navbar />
<AnimatePresence>
{mobileNav && <MobileNav key="menu" />}
</AnimatePresence>
<Hero />
<Work />
</div>
);
}
export default Home;
Context File
import React, { useState, createContext } from "react";
export const NavbarContextList = createContext();
const NavbarContextListProvider = (props) => {
const [mobileNav, setMobileNav] = useState(false);
return (
<NavbarContextList.Provider value={{ mobileNav, setMobileNav }}>
{props.children}
</NavbarContextList.Provider>
);
};
export default NavbarContextListProvider;
What I did:
I'm passing some props to functional component Stat.jsx.
What I expected:
I need to pass some background gradient color codes as a string type prop to the Stat.jsx component to make custom color elements.
What happened:
Props aren't passing to the Stat.jsx, also props object is empty.
Stat.jsx
import React from 'react';
import styled from 'styled-components';
const Stat = styled.div`
display: flex;
align-items: center;
justify-content: center;
padding: 0 2.5em;
width: auto;
height: 2.5em;
border-radius: 0.5em;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2);
background: linear-gradient(160deg, ${(props) => console.log(props) });
font-size: 1.8em;
font-family: Rubik-Medium;
color: #fff;
`;
// console.log(props) is returning object: { children: "1000", theme: {} }
export default ({ value }) => <Stat>{value}</Stat>;
Stats.jsx
import React from 'react';
import Stat from './Stat';
import styled from 'styled-components';
const Stats = styled.div`
display: flex;
`;
export default () => (
<div>
<Stats>
<Stat value="1000" background="#F4D03F, #16A085" />
</Stats>
</div>
);
Quick Fix
Because you don't pass the background prop to the actual Stat component:
export default (props) => <Stat {...props}>{props.value}</Stat>;
Explanation
A better way to illustrate the issue is by renaming your components:
import React from 'react';
import styled from 'styled-components';
const StyledStat = styled.div`
display: flex;
align-items: center;
justify-content: center;
padding: 0 2.5em;
width: auto;
height: 2.5em;
border-radius: 0.5em;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2);
background: linear-gradient(160deg, ${(props) => console.log(props) });
font-size: 1.8em;
font-family: Rubik-Medium;
color: #fff;
`;
export default function Stat(props){
const { value } = props;
return (
<StyledStat {...props}>
{value}
</StyledStat>;
};
Styled components props comes from the ThemeProvider usually, this is why you see a theme props while console.logging inside your styled.div
Usually in App.js you have something like that:
// src/App.jsx
import React from 'react'
import { ThemeProvider } from 'styled-components';
const theme: {
colors: {
primary: blue,
}
}
const App = () => (
<ThemeProvider theme={theme}>
<Stat />
</ThemeProvider>
)
export default App;
you can access these attributes with
${(props) => props.theme.colors.primary }
because styled-components provides its theme props to every StyledComponents (there is a Context Provider/consumer thing behind)
import React from 'react';
import styled from 'styled-components';
const Stat = styled.div`
display: flex;
align-items: center;
justify-content: center;
padding: 0 2.5em;
width: auto;
height: 2.5em;
border-radius: 0.5em;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.2);
background: linear-gradient(160deg, ${(props) => props.theme.colors.primary} });
font-size: 1.8em;
font-family: Rubik-Medium;
color: #fff;
`;
Styled components cause build crash
Guys, I have a problem with styled components ;/.
I'm using create-react-app and everything works fine until I "npm run build" and deploy the app on my FTP.
I keep getting this weird error and have not found any solution online. My code is attached below. Should be plain and simple.
Any ideas?
import styled from 'styled-components';
import countriesJSON from './countries.json';
const Container = styled.div`
max-width: 1200px;
margin: 0 auto;
`;
const Wrapper = styled.div`
display: flex;
flex-direction: column;
height: 100vh;
justify-content: center;
align-items: center;
`;
const Button = styled.button`
background: whitesmoke;
border-radius: 3px;
height: 5vh;
width: 20vw;
border: 2px solid orange;
color: 'slategrey';
margin: 0 1em;
padding: 0.25em 1em;
&:hover {
background: whitesmoke;
transform: scale(1.2);
`;
const Text = styled.h1`
font-size: calc(2vw + 10px);
font-weight: bold;
text-align: center;
color: whitesmoke;
`;
const Paragraph = styled.p`
color: whitesmoke;
font-size: calc(1vw + 10px);
`;
const CountryWrapper = styled.div`
display: flex;
flex-direction: column;
align-items: center;
#media (min-width: 600px) {
flex-direction: row;
}
`;
const CountryDetailsWrapper = styled.div`
margin: 10px;
text-align: center;
`;
const CountryImgWrapper = styled.div`
img {
height: 40vh;
margin: 0 auto;
width: 90vw;
padding: 10px;
}
#media (min-width: 596px) {
img {
width: 30vw;
height: 30vh;
}
}
`;
class Homepage extends Component {
constructor(props) {
super(props);
this.state = {
randomCountry: '',
isCountryWrapperVisible: false,
countryFlag: '',
countryRegion: '',
countryCurrency: '',
countryCapital: '',
countryPopulation: '',
countryTimezone: ''
}};
generateRandomCity = () => {
let num = Math.floor(Math.random() * countriesJSON.length);
this.setState({
randomCountry: countriesJSON[num].name
});
};
componentDidUpdate() {
this.fetchCountryInfo();
}
fetchCountryInfo = () => {
fetch(`https://restcountries.eu/rest/v2/name/${this.state.randomCountry}`)
.then(res => res.json())
.then(response =>
this.setState({
countryFlag: response[0].flag,
countryCapital: response[0].capital,
countryRegion: response[0].region,
countryCurrency: response[0].currency,
countryPopulation: response[0].population,
isCountryWrapperVisible: true
})
);
};
render() {
return (
<Container>
<Wrapper>
<Text> Test Your Knowledge of Flags </Text>
<Button onClick={this.generateRandomCity}> HIT ME! </Button>
{this.state.isCountryWrapperVisible && (
<CountryWrapper>
<CountryImgWrapper>
<img src={this.state.countryFlag} alt='flag' className='img-fluid'/>
</CountryImgWrapper>
<CountryDetailsWrapper>
<Paragraph> Name: {this.state.randomCountry} </Paragraph>
<Paragraph> Capital: {this.state.countryCapital} </Paragraph>
<Paragraph> Region: {this.state.countryRegion} </Paragraph>
<Paragraph> Population: {this.state.countryPopulation} </Paragraph>
</CountryDetailsWrapper>
</CountryWrapper>
) }
</Wrapper>
</Container>
)
}
}
export default Homepage;```
It turns out the problem lied in global-style object within parent component I had to recode.
I have this code:
import React, {useState} from 'react';
import PropTypes from 'prop-types';
import styled from "styled-components";
import ArrowTemplate from "./ArrowTemplate";
const AccordionBtn = styled.button`
background-color: #eee;
color: #444;
cursor: pointer;
padding: 18px;
display: flex;
align-items: center;
border: none;
outline: none;
transition: background-color 0.6s ease;
:hover,
:focus,
:active {
background-color: #ccc;
}
`;
const AccordionTitle = styled.p`
font-family: "Open Sans", sans-serif;
font-weight: 600;
font-size: 14px;
`;
const AccordionContent = styled.div`
background-color: red;
overflow: hidden;
transition: 0.6s;
`;
const AccordionText = styled.div`
font-family: "Open Sans", sans-serif;
font-weight: 400;
font-size: 14px;
padding: 18px;
`;
const AccordionSection = styled.div`
display: flex;
flex-direction: column;
`;
Accordion.propTypes = {
title: PropTypes.string.isRequired,
content: PropTypes.node.isRequired,
id: PropTypes.string.isRequired,
};
function Accordion(props) {
const [isAccordionExpanded, setIsAccordionExpanded] = useState(false);
const toggleAccordion = () => {
setIsAccordionExpanded(!isAccordionExpanded);
};
return (
<AccordionSection>
<AccordionBtn onClick={toggleAccordion}>
<AccordionTitle>
{props.title}
</AccordionTitle>
<ArrowTemplate
color={'black'}
direction={isAccordionExpanded === true ? 'up' : 'down'}
onClick={toggleAccordion}
/>
</AccordionBtn>
<AccordionContent
style={{height: isAccordionExpanded === true ? "100px" : "0"}}
>
<AccordionText>
{props.content}
</AccordionText>
</AccordionContent>
</AccordionSection>
);
}
export default Accordion;
What this code does, is extends the accordeon on click. Preety simple. But now, I want to move this height:
<AccordionContent
style={{height: isAccordionExpanded === true ? "100px" : "0"}}
>
here:
const AccordionContent = styled.div`
background-color: red;
overflow: hidden;
transition: 0.6s;
`;
The problem is I need to use state, and if I declare it in the function, it will get re-rendered, and not run the animation. How can I pass the state to the styled-component?
You can just pass the isAccordionExpanded directly to the styled component. Change your style from this:
const AccordionContent = styled.div`
background-color: red;
overflow: hidden;
transition: 0.6s;
`;
to include this
height: ${({ isAccordionExpanded }) => (isAccordionExpanded ? "100px" : "0"};
Another way to do animation in React is using React Transition Group, Quite good