React.js / Next.js - how to link from one article to another? - reactjs

Suppose this example with two articles (full example here https://github.com/codebushi/nextjs-starter-dimension/blob/master/components/Main.js)
import PropTypes from 'prop-types';
class Main extends React.Component {
render() {
let close = <div className="close" onClick={() => {this.props.onCloseArticle()}}></div>
return (
<div id="main" style={this.props.timeout ? {display: 'flex'} : {display: 'none'}}>
<article id="intro" className={`${this.props.article === 'intro' ? 'active' : ''} ${this.props.articleTimeout ? 'timeout' : ''}`} style={{display:'none'}}>
<h2 className="major">Intro</h2>
<span className="image main"><img src="/static/images/pic01.jpg" alt="" /></span>
<p>Nam maximus erat id euismod egestas. By the way, check out my awesome work.</p>
{close}
</article>
<article id="work" className={`${this.props.article === 'work' ? 'active' : ''} ${this.props.articleTimeout ? 'timeout' : ''}`} style={{display:'none'}}>
<h2 className="major">Work</h2>
<span className="image main"><img src="/static/images/pic02.jpg" alt="" /></span>
<p>Adipiscing magna sed dolor elit. Praesent eleifend dignissim arcu, at eleifend sapien imperdiet ac. Aliquam erat volutpat. Praesent urna nisi, fringila lorem et vehicula lacinia quam. Integer sollicitudin mauris nec lorem luctus ultrices.</p>
{close}
</article>
</div>
)
}
}
Main.propTypes = {
route: PropTypes.object,
article: PropTypes.string,
articleTimeout: PropTypes.bool,
onCloseArticle: PropTypes.func,
timeout: PropTypes.bool
}
export default Main
How do I create a link in the intro article to open the work article? In the example there's an <a href='#work'>, but when I click it there's no action at all.

You can do it by importing 'Link' from Next.js:
import Link from "next/link";
Then you can add:
<Link href="work">
<a>Go To Work!</a>
</Link>
Full documentation from Next.js: https://nextjs.org/docs/api-reference/next/link

Related

ReactComponent renders the same SVG Element

I am importing an SVG element using the ReactComponent method as below:
import { ReactComponent as Height } from "../../assets/Height.svg";
import { ReactComponent as Closet } from "../../assets/Closet.svg";
import { ReactComponent as Shirt } from "../../assets/Shirt.svg";
When I render them on the screen like this:
<Height />
<Shirt />
<Closet />
It shows the first Icon for all the three renders, for example, for the above code it renders the Height SVG element for all of them.
Here is the full component:
import React from "react";
import styles from "./Features.module.css";
import featureImage from "../../assets/featureImage.png";
import { ReactComponent as Height } from "../../assets/Height.svg";
import { ReactComponent as Closet } from "../../assets/Closet.svg";
import { ReactComponent as Shirt } from "../../assets/Shirt.svg";
import FeatureBackground from "../../assets/FeatureBackground.png";
const Features = () => {
const bodyContent = [
{
icon: <Height />,
title: "Body measurement tracking",
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi ",
},
{
icon: <Closet />,
title: "In home trial of clothes and closet",
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi ",
},
{
icon: <Shirt />,
title: "Recommendation of clothes using AI",
body: "Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi ",
},
];
return (
<div className={styles.container}>
<div className={styles.mainSection}>
<div className={styles.images}>
<img
className={styles.featureBackground}
src={FeatureBackground}
alt="feature background"
/>
<img
className={styles.featureImage}
src={featureImage}
alt="features Image"
/>
</div>
<div className={styles.content}>
<h1>EVERYTHING YOU NEED!</h1>
<div className={styles.body}>
{bodyContent.map((content, i) => (
<div key={i} className={styles.bodyContent}>
<div className={styles.icon}> {content.icon} </div>
<div>
<h3>{content.title}</h3>
<p>{content.body}</p>
</div>
</div>
))}
</div>
</div>
</div>
<div className={styles.footerSection}>
<h2>
Enhance your shopping experience with elevated expertise and efficient
time constraints.
</h2>
</div>
</div>
);
};
export default Features;

Add transition to accordion with react + tailwind

I tried to copy this code and convert native javascript to React, everything but the transition works (the content suddenly grows but it has no animation)
import { useState } from "react"
import { FaMinus, FaPlus } from "react-icons/fa"
function Accordion({ title, content }: { title: string; content: string }) {
const [expanded, setExpanded] = useState(false)
const toggleExpanded = () => setExpanded((current) => !current)
return (
<div className={`transition hover:bg-indigo-50 ${expanded ? "bg-indigo-50" : "bg-white"}`} onClick={toggleExpanded}>
<div className="accordion-header cursor-pointer transition flex space-x-5 px-5 items-center h-16 select-none">
{expanded ? <FaMinus className="text-indigo-500" /> : <FaPlus className="text-indigo-500" />}
<h3>{title}</h3>
</div>
<div className={`px-5 pt-0 overflow-hidden transition ${expanded ? "max-h-fit" : "max-h-0"}`}>
<p className="leading-6 font-light pl-9 pb-4 text-justify">{content}</p>
</div>
</div>
)
}
function AccordionWrapper() {
return (
<div className="h-screen bg-gradient-to-br from-pink-50 to-indigo-100 grid place-items-center">
<div className="w-6/12 mx-auto rounded border">
<div className="bg-white p-10 shadow-sm">
<h3 className="text-lg font-medium text-gray-800">Several Windows stacked on each other</h3>
<p className="text-sm font-light text-gray-600 my-3">The accordion is a graphical control element comprising a vertically stacked list of items such as labels or thumbnails</p>
<div className="h-1 w-full mx-auto border-b my-5"></div>
<Accordion title="What is term?" content="Our asked sex point her she seems. New plenty she horses parish design you. Stuff sight equal of my woody. Him children bringing goodness suitable she entirely put far daughter." />
</div>
</div>
</div>
)
}
You need more styles that just transition, you will need to add overflow-hidden transition-[max-height] duration-500 ease-in to the div that you want to change it's max-height
Also as explained in this question you can't use max-h-fit, you will need to set a value for it max-h-40
const { useState } = React
const minusIcon = '-'
const plusIcon = '+'
function Accordion({ title, content }) {
const [expanded, setExpanded] = useState(false)
const toggleExpanded = () => setExpanded((current) => !current)
return (
<div className="my-2 sm:my-4 md:my-6 shadow-sm cursor-pointer bg-white" onClick={toggleExpanded}>
<div className="px-6 text-left items-center h-20 select-none flex justify-between flex-row">
<h5 className="flex-1">
{title}
</h5>
<div className="flex-none pl-2">{expanded ? minusIcon : plusIcon}</div>
</div>
<div className={`px-6 pt-0 overflow-hidden transition-[max-height] duration-500 ease-in ${expanded ? "max-h-40" : "max-h-0"}`}>
<p className="pb-4 text-left">
{content}
</p>
</div>
</div>
)
}
const lorem = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
ReactDOM.createRoot(
document.getElementById("root")
).render(
<div className='py-16 md:py-20 lg:py-24 px-4 bg-black'>
<section className="max-w-6xl mx-auto text-center">
<Accordion title="Accordion #1" content={lorem} />
<Accordion title="Accordion #2" content={lorem} />
<Accordion title="Accordion #3" content={lorem} />
</section>
</div>
);
<div id="root"></div>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/react#18/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom#18/umd/react-dom.development.js" crossorigin></script>
When you use transition class only that properties transition when they change:
color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter
You should use transition-all class instead of transition.
tailwind docs

"Your render method should have a return statement" when I do have a return statement

So basically what I am trying to do here is set the toggle state for my modal and then toggle the module on and off via the alert and that should work fine hopefully. However for some reason I am getting the error "Your render method should have a return statement" when I do have a return statement. Does anyone know what could be causing this?
import React, { Component, useState } from "react";
import { Button, Alert, Input, Modal, ModalHeader, ModalBody, ModalFooter } from "reactstrap";
import ViewEmail from "./viewEmail";
class SingleEmail extends Component {
render() {
const ModalExample = (props) => {
const { buttonLabel, className } = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<>
<div>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader toggle={toggle}>Modal title</ModalHeader>
<ModalBody>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={toggle}>
Do Something
</Button>{" "}
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
<Alert
onClick={toggle}
className="SingleEmail"
style={{
backgroundColor: "white",
border: "1px solid lightgray",
color: "black",
}}
>
<div className="CheckBox">
<Input addon type="checkbox" />
</div>
<div className="MarkImportant">
<i class="fas fa-star"></i>
</div>
<p className="EmailFrom">{this.props.From}</p>
<p className="EmailTitle">{this.props.Subject}</p>
<p className="EmailDate">{this.props.Date}</p>
</Alert>
</div>
</>
);
};
}
}
export default SingleEmail;
You do not have a return statement inside the SingleEmail component but inside the ModalExample component which you have defined inside the render method of SingleEmail.
If you wish to use the ModelExample layout as singleEmail component, you can simply export the same component like
const SingleEmail = (props) => {
const { buttonLabel, className } = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<>
<div>
<Modal isOpen={modal} toggle={toggle} className={className}>
<ModalHeader toggle={toggle}>Modal title</ModalHeader>
<ModalBody>
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
in reprehenderit in voluptate velit esse cillum dolore eu fugiat
nulla pariatur. Excepteur sint occaecat cupidatat non proident,
sunt in culpa qui officia deserunt mollit anim id est laborum.
</ModalBody>
<ModalFooter>
<Button color="primary" onClick={toggle}>
Do Something
</Button>{" "}
<Button color="secondary" onClick={toggle}>
Cancel
</Button>
</ModalFooter>
</Modal>
<Alert
onClick={toggle}
className="SingleEmail"
style={{
backgroundColor: "white",
border: "1px solid lightgray",
color: "black",
}}
>
<div className="CheckBox">
<Input addon type="checkbox" />
</div>
<div className="MarkImportant">
<i class="fas fa-star"></i>
</div>
<p className="EmailFrom">{props.From}</p>
<p className="EmailTitle">{props.Subject}</p>
<p className="EmailDate">{props.Date}</p>
</Alert>
</div>
</>
);
};
export default SingleEmail;
you have no return in render function, you can return ModalExample and things will be fine;
like this:
class SingleEmail extends Component {
render() {
const ModalExample = (props) => {
const { buttonLabel, className } = props;
const [modal, setModal] = useState(false);
const toggle = () => setModal(!modal);
return (
<>
<div>
....
....
....
</div>
</>
);
};
return ModalExample;
}
}

Passing className values using useLocation

Im creating a project that needs to have variable styles and images dependent on the route its in so that i dont have to recreate components.
I've successfully gotten images and text in in the code below. but i am unsuccessful in getting the string value for className in the first div into the css.
Please help!
import React, { Fragment, useEffect } from "react";
import { useLocation } from "react-router-dom";
import homeimg from "../../images/homeimg.jpg";
import consimg from "../../images/consimg.jpg";
import solsimg from "../../images/solsimg.jpg";
const Hero = () => {
useEffect(() => {}, []);
const location = useLocation();
const { pathname } = location;
let img = null;
if (pathname === "/") {
img = homeimg;
} else if (pathname === "/consultants") {
img = consimg;
} else if (pathname === "/solutions") {
img = solsimg;
}
return (
<Fragment>
<div
className={
{pathname === "/" && ("grid-home")}
{pathname === "/consultants" && ("grid-consultants")}
{pathname === "/solutions" && ("grid-solutions")}
}>
<div className='overlay'>
<div>
<p className='bg-dark'></p>
<img src={img} alt='' />
</div>
</div>
<div className='copy'>
{pathname === "/" && (
<div>
<h1 className='text-primary'>Snorem Snipsem</h1>
<h3 className='text-danger'>Lorem ipsum dolor sit.</h3>
<p className='text-light'>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
<br />
Repellat nemo, in odit culpa, illo earum voluptatum
<br />
aliquam quaerat iure sunt, quos similique quod <br />
Recusandae voluptates voluptatum nisi sint dicta.
</p>
</div>
)}
{pathname === "/consultants" && (
<div>
<h1 className='text-primary'>Lorem, ipsum.</h1>
<h3 className='text-danger'>Lorem ipsum dolor sit.</h3>
<p className='text-light'>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
<br />
Repellat nemo, in odit culpa, illo earum voluptatum
<br />
aliquam quaerat iure sunt, quos similique quod <br />
Recusandae voluptates voluptatum nisi sint dicta.
</p>
</div>
)}
{pathname === "/solutions" && (
<div>
<h1 className='text-primary'>Forem, ipsum.</h1>
<h3 className='text-danger'>Lorem ipsum dolor sit.</h3>
<p className='text-light'>
Lorem ipsum dolor sit amet consectetur adipisicing elit.
<br />
Repellat nemo, in odit culpa, illo earum voluptatum
<br />
aliquam quaerat iure sunt, quos similique quod <br />
Recusandae voluptates voluptatum nisi sint dicta.
</p>
</div>
)}
</div>
</Fragment>
);
};
export default Hero;
At first declare it and try to use
let cn = "";
if(pathname === '/'){
cn = grid-home
}
....
return(
<div className={cn}>
..
..
You may use classnames library in order to add dynamically classnames https://www.npmjs.com/package/classnames
const divClass = classNames({
'grid-home': pathname === "/" ,
'grid-consultants': pathname === "/consultants",
'grid-solutions': pathname === "/solutions"
});
<div className={divClass}>

unable to get article id - createPages

I am trying to create new pages and display related data based on the article ID. But, I am running into issues. Right now I create a slug/id which brings up my article template and creates a link seen in the browser window.
I am not able to display any related data on those article pages. What I want is to find the ID of the page and show the information related to that ID. This is my configuration so far:
gatsby-node.js:
const path = require(`path`)
exports.createPages = ({ graphql, actions }) => {
const { createPage } = actions
const articleTemplate = path.resolve(`./src/templates/article.js`)
return graphql(`
{
umdHub {
articles {
data {
id
title
subtitle
body
summary
hero_image {
url_1200_630
}
authorship_date {
formatted_short
unix
unix_int
formatted_long
formatted_short
time
}
slug
}
}
}
}
`
).then(result => {
if (result.errors) {
throw result.errors
}
// Create blog post pages.
result.data.umdHub.articles.data.forEach(data => {
createPage({
path: `/articles/${data.slug}-${data.id}`,
component: articleTemplate,
id: data.id,
context: {
slug: `/articles/${data.slug}-${data.id}`
},
})
})
return;
})
}
Article template:
import React from 'react'
import { graphql } from 'gatsby'
import { ListGroup, ListGroupItem } from 'reactstrap';
// eslint-disable-next-line
import Layout from "../components/layout"
import Header from "../components/header"
import Footer from "../components/footer"
export default ({ data }) => {
console.log(data)
return (
<div>
<Header />
<div className="container spaces article">
<div className="row">
<section className="col-md-9">
<div className="tag-list">
<ul className="list-inline">
<li className="list-inline-item">Highlighted</li>
<li className="list-inline-item">Innovation</li>
<li className="list-inline-item">Web Only</li>
<li className="list-inline-item">February 28, 2019</li>
</ul>
</div>
<h1>hello</h1>
{data.umdHub.articles.data.map((article) => (
<div>
<h1>{article.title}</h1>
</div>
))}
<div className="row article-content">
<div className="col-md-10 offset-md-1">
<h2 className="subheader">Subtitle</h2>
<div className="author">
<p>By Jane Doe | Photos by ISTOCK</p>
<hr />
</div>
<div>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non
proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
</div>
</div>
</div>
</section>
<aside className="col-md-3">
<div>
<ListGroup flush>
<ListGroupItem disabled tag="a" href="#">Recent Posts</ListGroupItem>
<ListGroupItem tag="a" href="#">Dapibus ac facilisis in</ListGroupItem>
<span>February 27, 2019</span>
<ListGroupItem tag="a" href="#">Morbi leo risus</ListGroupItem>
<span>February 27, 2019</span>
<ListGroupItem tag="a" href="#">Porta ac consectetur ac</ListGroupItem>
<span>February 27, 2019</span>
<ListGroupItem tag="a" href="#">Vestibulum at eros</ListGroupItem>
<span>February 27, 2019</span>
</ListGroup>
</div>
</aside>
</div>
</div>
<Footer />
</div>
)
}
export const query = graphql`
query($id:String!) {
umdHub {
articles(id: $id) {
data {
id
title
subtitle
body
summary
hero_image {
url_1200_630
}
}
}
}
}
`
gatsby-config.js:
plugins: [
{
resolve: `gatsby-source-graphql`,
options: {
typeName: `HUBAPI`,
fieldName: `umdHub`,
url: `https://umd-hub-middleware.herokuapp.com/graphql`,
},
},
...

Resources