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`,
},
},
...
Related
I saw another question about installing tailwind elements in nextjs project.
How to install the tailwind elements in nextjs?
I followed it on my react project.It doesn't work. How can use tailwind elements in react project?
import React, { useEffect } from "react";
// import "tw-elements";
const Stepper = () => {
useEffect(() => {
const use = async () => {
await import("tw-elements");
};
use();
}, []);
return (
<>
<ul
className="stepper"
data-mdb-stepper="stepper"
data-mdb-stepper-type="vertical"
>
<li className="stepper-step stepper-active">
<div className="stepper-head">
<span className="stepper-head-icon"> 1 </span>
<span className="stepper-head-text"> step1 </span>
</div>
<div className="stepper-content">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.
</div>
</li>
<li className="stepper-step">
<div className="stepper-head">
<span className="stepper-head-icon"> 2 </span>
<span className="stepper-head-text"> step2 </span>
</div>
<div className="stepper-content">
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat.
</div>
</li>
<li className="stepper-step">
<div className="stepper-head">
<span className="stepper-head-icon"> 3 </span>
<span className="stepper-head-text"> step3 </span>
</div>
<div className="stepper-content">
Duis aute irure dolor in reprehenderit in voluptate velit esse
cillum dolore eu fugiat nulla pariatur.
</div>
</li>
</ul>
</>
);
};
tailwind.config.js
module.exports = {
content: [
"./src/**/*.{js,jsx,ts,tsx}",
"./node_modules/tw-elements/dist/js/**/*.js",
],
theme: {
extend: {},
},
plugins: [require("tw-elements/dist/plugin")],
};
The code above is what i write to stepper. It work sometime, but sometime it doesn't . stepper-content is never hided or never showed. Am i did something wrong? Thank you
As stated in this link, you should import tw-elements in a useEffect in the _app file, not in the same component that you use them in.
/_app.jsx/tsx
function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
const use = async () => {
(await import('tw-elements')).default;
};
use();
}, []);
return <Component {...pageProps} />;
}
export default MyApp;
There is also another solution to use the _document.js file and Script element to use the script for tw_elements
import { Html, Head, Main, NextScript } from 'next/document'
import Script from 'next/script'
// import 'tw-elements';
export default function Document() {
return (
<Html>
<Head />
<body>
<Main />
<NextScript />
<Script src="./TW-ELEMENTS-PATH/dist/js/index.min.js"/>
</body>
</Html>
)
}
but I don't recommend it as _document.js will be replaced soon in the upcoming updates for NextJS
I'm stuck. So what do I want from my app:
to animate sections with left fading and opacity (0 to 1) when I scroll down or up.
reuse this component later with different separate components.
What I have now:
Js function that perfectly works with simple HTML and CSS.
nothing from my 'want list'
Please help!
My code is next:
import React from 'react';
const TestAnimation = () => {
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
entry.target.classList.add('.opacity-100');
} else {
entry.target.classList.remove('.opacity-100');
}
});
});
const hiddenElements = document.querySelectorAll('.opacity-0');
hiddenElements.forEach((el) => {
observer.observe(el);
});
return (
<div className='m-0 bg-slate-900 p-0 text-white'>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h1>Test</h1>
</section>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h2>This is first page</h2>
<p>
Lorem ipsum dolor, sit amet consectetur adipisicing elit. Autem modi voluptatem est iste a commodi
nesciunt saepe quisquam id dignissimos odit, repellat asperiores laboriosam quibusdam expedita
itaque blanditiis eos pariatur.
</p>
</section>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h2>This is third page</h2>
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur veniam sint illo quas beatae,
eum omnis, deleniti error, eveniet praesentium fugiat quia quod? Maxime, placeat reiciendis ab
debitis exercitationem nemo. Laborum perspiciatis eum architecto laboriosam, necessitatibus
voluptatibus cupiditate accusantium corrupti placeat mollitia omnis tenetur! Incidunt fugiat
possimus quod, quidem itaque ducimus, perspiciatis eligendi, commodi voluptate cupiditate nihil
corrupti soluta maxime.
</p>
</section>
<section className='grid min-h-screen place-items-center content-center opacity-0'>
<h2>this is Fourth page</h2>
<p className='text-center'>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quos similique harum, officiis facere odit
adipisci maxime obcaecati placeat, quibusdam totam magni eaque? Dicta id commodi saepe dignissimos
quam unde eaque.
</p>
</section>
</div>
);
};
export default TestAnimation;
You should move the initiation of the intersection observer into a useEffect hook.
Here is an example of an Observer component I've used in the past:
export default function Observer({ children, sectionRef, callback }) {
function onObserver(entries) {
const entry = entries[0];
console.log(entry);
if (entry.isIntersecting) {
callback(sectionRef.current.id);
console.log("element in:", entry.target.id);
} else {
console.log("element left:", entry.target.id);
}
}
useEffect(() => {
const refCopy = sectionRef;
let options = {
root: null,
rootMargin: "0% 0% -5% 0%",
threshold: [0.5],
};
let observer = new IntersectionObserver(onObserver, options);
if (refCopy.current) {
observer.observe(refCopy.current);
}
return () => {
if (refCopy.current) {
observer.unobserve(refCopy.current);
}
};
}, [sectionRef]);
return <div id="observation">{children}</div>;
}
And here is how to use it:
export default function Education({ children, handleInView }) {
const sectionRef = useRef(null);
return (
<Observer sectionRef={sectionRef} callback={handleInView}>
<section
ref={sectionRef}
id="education"
className="education"
data-scroll-section
data-scroll
data-scroll-class="purpleColor"
>
<Pencils />
<div className="details">
<div className="side-by-side">
<div className="title" data-scroll data-scroll-speed={2}>
<span>Fullstack</span>
<span> Software </span>
<span>Engineer</span>
</div>
</div>
</div>
</section>
</Observer>
);
}
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;
I have a component that will take an array of objects and will render a grid of lists
//Awards
import React from "react";
import MarkDown from "components/Design/MarkDown";
import { Grid } from "components/Design/Grid/Grid";
export const Awards = ({ list }) => {
return (
<Grid>
{list
.sort((a, b) => b.year - a.year)
.map((award) => (
<div
key={award.id}
className="flex flex-col gap-16 font-mulish col-span-4">
<h3 className="font-bold text-14-24 text-gray-dark">
{award.year}
</h3>
<div className="text-14-24 text-gray-text">
<MarkDown>{award.description}</MarkDown>
</div>
</div>
))}
</Grid>
);
};
When I try to write a story for the component, I get a warning TypeError: Object(...) is not a function. After several refresh I get Cannot access 'Awards' before initialization
//Awards.stories.jsx
import React from "react";
import { Awards } from "components/Awards";
export default {
title: "component/Awards",
component: Awards,
};
const list = [
{
id: 1,
year: 2018,
description:
"- Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\n - Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\n\n - Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\n\n - Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.",
},
{
id: 2,
year: 2017,
description:
"- Lorem ipsum dolor sit amet\n\n - consectetur adipiscing elit.",
},
{
id: 3,
year: 2016,
description:
"- Lorem ipsum dolor sit amet\n\n - consectetur adipiscing elit.",
},
{
id: 4,
year: 2015,
description:
"- Lorem ipsum dolor sit amet\n\n - consectetur adipiscing elit.",
},
{
id: 5,
year: 2014,
description: "- Lorem ipsum dolor sit amet",
},
];
export const AwardsBlock = () => {
return <Awards list={list} />;
};
While debugging I found that if replace the part
{list
.sort((a, b) => b.year - a.year)
.map((award) => (
<div
key={award.id}
className="flex flex-col gap-16 font-mulish col-span-4">
<h3 className="font-bold text-14-24 text-gray-dark">
{award.year}
</h3>
<div className="text-14-24 text-gray-text">
<MarkDown>{award.description}</MarkDown>
</div>
</div>
))}
with something static
<span>——</span>
It works like a charm. Maybe something to do with lists throwing some error or not rendering.
What am I missing here?
Did you mean to do a named import for the Markdown component?
As in
import {MarkDown} from "components/Design/MarkDown";
instead of
import MarkDown from "components/Design/MarkDown";
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;
}
}