I'm building my portfolio right now and I would like to hide the download link of my projects when href is empty
<GridContainer>
{projects.map(({id, image, title, description, tags, source, visit, pdf}) =>
<BlogCard key={id}>
<div>
<Img src={image} style={{alignContent:"flex-start", display:"flex"}}/>
<br/>
<TitleContent>
<HeaderThree title>{title}</HeaderThree>
<Hr />
</TitleContent>
<CardInfo>{description}</CardInfo>
</div>
<div >
<br/>
<TitleContent>Technologies utilisées :</TitleContent>
<TagList>
{tags.map((tag, i) => (
<Tag key ={i}>{tag}</Tag>
))}
</TagList>
<UtilityList>
<ExternalLinks href={source}>Code</ExternalLinks>
<ExternalLinks href={pdf} download >PDF</ExternalLinks>
<ExternalLinks href={visit}>Live</ExternalLinks>
</UtilityList>
</div>
</BlogCard>
)}
</GridContainer>
The href is imported from :
export const projects = [
{
title: 'test',
description: "test",
image: 'test',
tags: ['PHP', 'MYSQL', 'HTML', 'CSS'],
source: 'https://google.com',
visit: 'https://google.com',
pdf:'#',
id: 0,
},
I import the css from styled-components like so:
export const ExternalLinks = styled.a`
color:#d4c0c0;
font-size: 1.6rem;
padding:1rem 1.5rem;
background: #6b3030;
border-radius: 15px;
transition: 0.5s;
&:hover{
background: #801414;
}
`;
The idea is to hide the PDF ExternalLinks only when pdf:'#' but I still don't know how to do that. Can you help me please ?
Tell me if you need some details about my code, and thanks for your help !
You could wrap the component effected in a condition checking that the value of href is not equal to "#".
{pdf !== "#" ? <ExternalLinks href={pdf}>PDF</ExternalLinks> : null }
You can use a ternary operator to conditionally render a particular element, in this case your ExternalLinks component and it'll not render, until the condition met.
{pdf.length > 1 ? <ExternalLinks href={pdf} download >PDF</ExternalLinks> : null}
You can alter this condition(pdf.length > 1) based on the data set you've.
Related
I am trying to use the NPM React module for Mailchimp: https://www.npmjs.com/package/react-mailchimp-form. It works great and gives you all the forms that you may need but I am struggling to style it.
It says that you can add a personalized class for CSS styling, but how will that contain styles for all elements on the form?
Currently the form looks like this:
function MailchimpForm() {
return (
<div>
<Mailchimp
action=
fields={[
{
name: 'EMAIL',
placeholder: 'Email',
type: 'email',
required: true
},
{
name: 'COMPANY',
placeholder: 'name',
type: 'text',
required: true
}
]}
// Change predetermined language
messages={
{
sending: "Sending...",
success: "Thank you for subscribing!",
error: "An unexpected internal error has occurred.",
empty: "You must write an e-mail.",
duplicate: "Too many subscribe attempts for this email address",
button: "Subscribe!"
}
}
// Add a personalized class
className='MailchimpStyle'
/>
</div>
)
}
Where MailchimpStyle is my CSS style class. Is there a way to have multiple CSS styles in a class?
The current class looks like:
.MailchimpStyle {
clear: left;
font: 200px Helvetica, Arial, sans-serif;
}
You should be able to access the elements by specifying the elements after the className in the css sheet. Example for button:
.MailchimpStyle button {
clear: left;
color: black;
background-color: white;
margin: 2px;
}
The following question came up when I wanted to migrate from Styled Components to CSS Modules.
Let's say I have the following styled component which accepts a dynamic parameter offset and a dynamic CSS string theme:
const Li = styled.li`
&.selected {
background-color: grey;
}
margin-left: ${({ offset }) => offset}px;
${({ theme }) => theme};
`;
In my code, I'd use it the following way:
const Parent = () => (
<List>
{list.map((item) => (
<Item
key={item.id}
id={item.id}
selectedIds={[]}
offset={24}
theme={`
&.selected {
background-color: green;
}
`}
>
{item.name}
</Item>
))}
</List>
);
const Item = ({ id, offset = 0, theme, children }) => {
return (
<Li
theme={theme}
offset={offset}
className={selectedIds.includes(id) && 'selected'}
>
{children}
</Li>
);
};
Requirement: Now I would really keep the Item's component API: passing a number offset and a style string theme. So essentially everything in Parent component should stay this way.
How can I convert the Item component internally to use CSS Modules instead of the styled Li component?
It's probably a different way of thinking than you used to but it can work
You can use css variable
style={{ [`--offset`]: `${offset}px` }}
.item {
margin-left: var(--offset);
}
You can have a css module (file) dedicated to themes. In your case, it has withSelected
.withSelected {
&.selected {
background-color: green;
}
}
So you could pass it as "theme"
theme={themes.withSelected}
This is how the components look
import styles from "./style.module.scss";
import themes from "./themes.module.scss";
const Parent = () => (
<ul>
{list.map((item) => (
<Item
key={item.id}
id={item.id}
selectedIds={[1]}
offset={24}
theme={themes.withSelected}
>
{item.name}
</Item>
))}
</ul>
);
const Item = ({ id, offset = 0, theme, children, selectedIds }) => {
return (
<li
className={`${styles.item} ${theme} ${
selectedIds.includes(id) && themes.selected
}`}
theme={theme}
style={{ [`--offset`]: `${offset}px` }}
>
{children}
</li>
);
};
Demo: https://codesandbox.io/s/styledcomponent-to-css-modules-1kbqx
With 1 I'd concur with #Mosh to just use the style prop. Css modules are static by design and there no way to get this done otherwise (I think that styled-components also uses the style prop so you're not losing anything).
For 2 you can leverage Sass modules which allow you to define your theme in a single place and import them as required:
/theme/_colors.scss
$red: rgb(200, 0 50);
/components/Item.module.scss
#import "../theme/colors"
.selected {
background: $red;
}
Note: if you use Create React App absolute paths you can import from root as ~theme/colors
I'm coding a React function with parent component containing an array of objects:
let const ingredients = [
{name:"lettuce",color:"green"},
{name:"tomato",color:"red"}
]
...
In a child component, there is a map function that breaks down an array to single items to be displayed in a div.
What is the best practice for defining CSS styling for an object className:"name" to set backgroundColor: {ingredient.color};? I'm trying to avoid manual entry of the entire set of key/values of 'ingredients', to allow updating the object without breaking the code.
I'm currently using inline styling, which I have been advised against. Currently using:
let burg = props.toppings.map((item) => {
const divColor = {backgroundColor: item.color};
return (<div style={divColor}>{item.name}</div>)
Inline style is bad when you have other solution to do what you want. Here, you have a string that is the color (red, green, etc.) so you could write a css class for every color, but that is of course a really bad idea. Inline style is the good way to do it here.
I would suggest setting the class of the div instead of the style. That way you can change the look without resorting to inlining the style.
You could create a css class for lettuce with the background color green, instead of using the item.color you'd set class={ item.name }
You can use this way.
css can be more handy if you use scss
// css
.color-green {
color: green;
}
.color-red {
color: red;
}
import React from "react";
import "./styles.css";
const ingredients = [
{ name: "lettuce", color: "green" },
{ name: "tomato", color: "red" }
];
const Vegetable = ({ color, text }) => {
return (
<p>
this is <span className={`color-${color}`}>{text}</span> color{" "}
</p>
);
};
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
{ingredients.map((item, index) => {
return <Vegetable key={index} color={item.color} text={item.name} />;
})}
</div>
);
}
I want to adjust my textarea height dynamically with Refs and pass it to the state but it don't work correctly.
I created a codesandbox to help you to understand what exactly I want.
https://codesandbox.io/s/ol5277rr25
You can solve this by using useRef and useLayoutEffect built-in hooks of react. This approach updates the height of the textarea before any rendering in the browser and therefor avoids any "visual update"/flickering/jumping of the textarea.
import React from "react";
const MIN_TEXTAREA_HEIGHT = 32;
export default function App() {
const textareaRef = React.useRef(null);
const [value, setValue] = React.useState("");
const onChange = (event) => setValue(event.target.value);
React.useLayoutEffect(() => {
// Reset height - important to shrink on delete
textareaRef.current.style.height = "inherit";
// Set height
textareaRef.current.style.height = `${Math.max(
textareaRef.current.scrollHeight,
MIN_TEXTAREA_HEIGHT
)}px`;
}, [value]);
return (
<textarea
onChange={onChange}
ref={textareaRef}
style={{
minHeight: MIN_TEXTAREA_HEIGHT,
resize: "none"
}}
value={value}
/>
);
}
https://codesandbox.io/s/react-textarea-auto-height-s96b2
Here's a simple solution that doesn't involve refs. The textarea is dynamically adusted using some CSS and the rows attribute. I used this myself, recently (example: https://codesandbox.io/embed/q8174ky809).
In your component, grab the textarea, calculate the current number of rows, and add 1:
const textArea = document.querySelector('textarea')
const textRowCount = textArea ? textArea.value.split("\n").length : 0
const rows = textRowCount + 1
return (
<div>
<textarea
rows={rows}
placeholder="Enter text here."
onKeyPress={/* do something that results in rendering */}
... />
</div>
)
And in your CSS:
textarea {
min-height: 26vh; // adjust this as you see fit
height: unset; // so the height of the textarea isn't overruled by something else
}
You can check the repo. Or you can add the package to your project.
https://github.com/andreypopp/react-textarea-autosize
Also if you really willing to learn how the logic working exactly;
https://github.com/andreypopp/react-textarea-autosize/blob/master/src/calculateNodeHeight.js
There is a source code with all calculations together.
So I am creating an Electron app that allows the user to create an invoice and then produce a PDF of that invoice. I'm using a PDF npm package that allows me to pass in HTML. So I am using JSX to create the invoice dynamically then I am turning that JSX into an HTML string. Because I am doing it like this I cannot use typical css files to set styling. So I need to use JSX's inline styling. But for some reason I can't get it to work with CSS Grids. Am I doing anything wrong. I've tried researching it and can't really find any good information on what I'm trying to do.
let headerStyle = {
display: 'grid',
gridTemplateColumns: '3fr 1fr',
gridTemplateRows: 'auto auto',
}
let invoiceHeaderInfoStyle = {
gridColumn: '2 / 3',
gridRow: '1 / 2'
}
let invoiceHeaderCompanyInfoStyle = {
gridColumn: '1 / 2',
gridRow: '1 / 2'
}
let invoiceHeaderClientInfoStyle = {
gridColumnStart: '1',
gridColumnEnd: '2',
gridRow: '2 / 3'
}
return (<div>
<header style={headerStyle}>
<h1>Invoice</h1>
<section style={invoiceHeaderInfoStyle}>
<div className="invoiceHeaderInfoDetails">
<span>Invoice #:</span>
<span>{invoice.number}</span>
</div>
<div className="invoiceHeaderInfoDetails">
<span>Date:</span>
<span>{invoice.date}</span>
</div>
</section>
<section style={invoiceHeaderCompanyInfoStyle}>
<div><p>Company Name</p></div>
<div><p>Some City, KS</p></div>
<div><p>(555)555-5555</p></div>
<div><p>companyname#email.com</p></div>
</section>
<section style={invoiceHeaderClientInfoStyle}>
<div>{this.getFormattedAddressHeader()}</div>
</section>
</header>
</div>)
I'm sure you figured this out, but for others, you have to include style as JSX object:
import style from './app.css';
export default () => (
...
<div className={style.box}>A</div>
...
It's interesting the element style works in normal way, but references to classes have to be specified as JSX variables.