How can I render contentful images dynamically in my gatsby portfolio website - gatsby-plugin-image

I have been struggling to render images from contentful in my gatsby site. I have used gatsby-plugin-image to render the image from contentful. I cannot dynamically render the images. please help me.
I import
import { GatsbyImage, getImage } from "gatsby-plugin-image"
my graphQL query is.
const data = useStaticQuery(graphql`
query {
allContentfulBooks(sort: { bookTitle: ASC }) {
edges {
node {
bookTitle
author
date(formatString: "MMMM Do, YYYY")
type
bookCover {
gatsbyImageData(
width: 300
placeholder: NONE
quality: 75
layout: CONSTRAINED
)
}
slug
summary
}
}
}
contentfulBookHeading {
heading
mainText {
raw
}
}
}
`)
I try to render the book Cover here
<ol>
{data.allContentfulBooks.edges.map((edge) => {
const image = getImage(edge.node.bookCover.gatsbyImageData)
return (
<li className={bookStyles.books}>
<div className={bookStyles.bookThumbnail}>
<div className={bookStyles.bookCover}>
<GatsbyImage src={image} alt="Book Cover" />
</div>
<div>
<Link to={`/book/${edge.node.slug}`}>
<h3 className={bookStyles.title}>{edge.node.bookTitle}</h3>
</Link>
<h5 className={bookStyles.author}>
Author: {edge.node.author}
</h5>
<h6 className={bookStyles.type}>Type: {edge.node.type}</h6>
<p className={bookStyles.date}>Date Read: {edge.node.date}</p>
<p className={bookStyles.summary}> {edge.node.summary}</p>
<Link to={`/book/${edge.node.slug}`}>
<p className={bookStyles.fullnotes}>Read full book notes</p>
</Link>
</div>
</div>
<hr />
</li>
)
})}
</ol>
I tried to render the book cover image from contentful. but it's not working

My first thought when reading your ask was that you are looking to load data dynamically, as in at load time, my original answer would work for that. After rereading your question, I believe you are not having difficulty loading data dynamically at load time but, rather you are not seeing the images display using the useStaticQuery and loading the data at build time.
Steps to ensure you should see the media:
open http://localhost:8000/___graphql in a browser and run your query, ensure you see the media you are expecting.
If you do not see the media:
First, check Contentful and ensure that the media is published.
Next, try stopping your app and restarting it, ctrl c should cancel the running command, then start the site back up. This will ensure that you content is pulled in and ready to render.
If you see the media in graphical, my next suggestion is to debug your site and console.log the data. Try putting in console logs
console.log("gatsbyImageData", edge.node.bookCover.gatsbyImageData)
const image = getImage(edge.node.bookCover.gatsbyImageData)
console.log("image", image)
next open up the developer menu in your browser and click on console
reload the page and verify the output of the console logs. This should help you ensure that data is present.
If you are having a dynamic rendering issue the answer is, useStaticQuery, grabs all of your Contentful data at build time. This is by design and is part of why Gatsby is so fast. You will need to use something like Apollo in order to grab dynamic data in Gatsby. Check out this article that provides more details and a possible solution.

Related

Is there a way to set up "loading: lazy" instead of default "loading: eager" for all inline images in gatsby-source-wordpress?

I'm trying to decrease page loading time. Right now all images which came from Wordpress content are geting "loading: eager". In result all images are downloading immediately all together on the page. So I would like to know is there an option to set up by default "loading: lazy" for all images which come from content of gatsby-source-wordpress.
To show images I'm just using this way:
<div dangerouslySetInnerHTML={{ __html: content }} />
Gatsby v3.14,
NodeJs 12.22.6,
Gatsby-source-wordpress 5.14,
Gatsby-plugin-image 1.14
I think your best chance is customizing the content that is rendering the dangerouslySetInnerHTML or trying gatsby-wpgraphql-inline-images
For the first approach, a library such as html-react-parser may fit your requirements.
Instead of:
<div dangerouslySetInnerHtml={{__html: content}}/>
You will do:
<div>{parse(content, {replace: replaceMedia})}</div>
Where replaceMedia is a function that gets the nodes and replaces them by a custom markup:
const replaceMedia = node => {
if (node.name === 'img') {
console.log("Check the node data:", node)
return <img src={node.attribs.src} loading="lazy" alt="Some alternative text" />
}
};
Test it to check the data inside node and tweak it accordingly. If your images are locally set, you can even use a custom component to return a GatsbyImage.
The second approach will rely on your set up, which has not been provided in the question.
Useful resources:
https://dimitr.im/optimize-loading-images-wordpress-gatsby
https://www.gatsbyjs.com/plugins/gatsby-wpgraphql-inline-images/
https://www.gatsbyjs.com/plugins/gatsby-wpgraphql-inline-images/

Adding a backround image for each page in my web-app

i am building a web-app using react js and i am trying to put a backround image which will stay there for every page i visit.My App.js render code is this :
render() {
return (
<div > ---> Case 2: <div className="classN"> instead of <div>
<NavBar user={this.state.user} />
<main>
<Switch>
...Routes...
<Route path="/evcharge/api/admin/healthcheck" component={Healthcheck}></Route>
... More Routes...
</Switch>
</main>
----> Case 1: <img src="/images/backround.png"/>
</div>
);
}
}
What i have tried after searching online is 2 things.
As shown above in case_1 source the image there which will cause this in main page:
picture1
But if i go to,for example,login this happens:
Picture2
For the second case this is my css code:
.classN{
background-image: url(./images/backround.png);
}
In this case the image is like this :
Picture3
This both wont get bigger than the Menubar and will also disorder my other elements of the page.
What i would like to achieve is just have the same backround image be displayed in the backround of each page without influencing the other elements of each page,such as the login form.I have been stuck in this for a while and i can't seem to get it to work.Any advide would be helpful.
Thanks in advance.
If you want to use it in every page put that background image directly in body so It will be global
body {
background-image: url(./images/backround.png);
}

ARIA accessibility issues with <Select>

Background
We are using #axe-core/react to work on ARIA accessibility in react application. By default, on page reload no issues are reported, but on Select click we are facing various issues with accessibility, according to axe-core/react.
Problems
serious: Page must have means to bypass repeated blocks
https://dequeuniversity.com/rules/axe/4.0/bypass?application=axeAPI
moderate: Document must have one main landmark
https://dequeuniversity.com/rules/axe/4.0/landmark-one-main?application=axeAPI
moderate: All page content must be contained by landmarks
https://dequeuniversity.com/rules/axe/4.0/region?application=axeAPI
In addition to problems, there are 2 more:
moderate: Page must contain a level-one heading https://dequeuniversity.com/rules/axe/4.0/page-has-heading-one?application=axeAPI
serious: Elements must have sufficient color contrast https://dequeuniversity.com/rules/axe/4.0/color-contrast?application=axeAPI
Code
import React from "react";
import ReactDOM from "react-dom";
import axe from "#axe-core/react";
import { BrowserRouter, Route, Link } from "react-router-dom";
import { MenuItem, Select, InputLabel } from "#material-ui/core";
const BypassRepeatedBlocks = () => (
<div aria-hidden="true">
<a href="#select-content" style={{ display: "none" }}>
bypass repeated blocks
</a>
</div>
);
const NavigationSample = () => (
// we must have <nav> here in order to put content inside landmark. Otherwise we would get issue.
<nav>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
</ul>
</nav>
);
const HomePage = () => <div></div>;
const App = () => (
// BrowserRouter, Route and <Link> (NavigationSample) are the cause of bypass repeated blocks issue
<BrowserRouter>
{/**but with BypassRepeatedBlocks portion of code, it can be solved */}
<BypassRepeatedBlocks />
<NavigationSample />
<main>
<Route path="/home" component={HomePage} />
{/**without <h1> there is heading issue on page loading */}
<h1>H1</h1>
<InputLabel id="my-input" style={{ color: "black" }}>
Sort
</InputLabel>
<Select
id="select-content"
labelId="my-input"
value="item1"
style={{ width: "200px" }}
>
<MenuItem key="item1" value="item1">
item1
</MenuItem>
<MenuItem key="item2" value="item2">
item2
</MenuItem>
</Select>
</main>
</BrowserRouter>
);
axe(React, ReactDOM, 1000);
ReactDOM.render(<App />, document.getElementById("root"));
Observations
As with shown code, when drop-down menu is shown I can navigate through menuitems (options) with key down and key up from keyboard, and that is what is important, from accessibility point of view, right?
After clicking on Select and inspecting HTML elements of web page, I can see two things: first, that my main content gets hidden <div id="root" aria-hidden="true">, and second that new <div> is generated with role='presentation' which contains this drop-down content. And it is outside of <main> which sort of explains the issue All page content must be contained by landmarks, as well as Document must have one main landmark and Page must contain a level-one heading
In addition to previous observation, I tried to add MenuProps={{ disablePortal: true }} to Select element, and issue All page content must be contained by landmarks was removed but i don't know if and what negative impacts this can have
from what i read on internet on this topic, I find this case (select, drop-down) to be very specific and advance.
Questions
Is there a proper way to handle mentioned issues for Select element? How?
Is this one of the situations to be considered as a trade-off (don't have to / can't get rid of all issues)?
If 2. is true, is then that bug to axe-core/react tool?
Let me know if I can provide more details, or update some content.
Thanks.
EDIT
Github repo for reproduction: https://github.com/StefanZivkovic/aria-accessibility-problems.
When you git clone it from cmd, navigate to cd aria-accessibility-problems, execute npm i, thennpm start and wait for server to start. If you use VS code, from cmd do code . to open the files and check the code if you want.
By the way, i found how to overcome Page must have means to bypass repeated blocks, at least on this simple example. That particular issue was caused by react-router-dom, and its elements, Link, BrowserRouter and Route. Might be useful for some.

Modify HTML tag from dangerouslySetInnerHTML in React

I am building a Gatsby Blog using React/Gatsby & the Wordpress API.
I render an excerpt of the latest articles on the landing page like so:
<span
className="mb-0"
id="excerpt-wrapper"
dangerouslySetInnerHTML={{ __html: this.props.post.node.excerpt}
/>
The problem is, my this.props.post.node.excerpt comes with an unwanted wrapping <p> tag. This tag inherit from Bootstrap CSS as I am using Bootstrap 4 in my whole project, and from the user agent stylesheet.
Hence I need to find a way either to :
get rid of the wrapping p tag
modify the CSS once the excerpt is mounted
I tried the following solution:
componentDidMount() {
this.removePTagMargin();
}
removePTagMargin = () => {
const excerptWrapper = document.querySelector("#excerpt-wrapper");
excerptWrapper.firstChild.style.marginBottom = "0px !important"
excerptWrapper.firstChild.style.marginBlockEnd = "0px !important"
}
but it does not work (maybe because it executes before the WP API call is done ?).
How can I solve my problem ?
This is assuming the excerpt comes from gatsby-transformer-remark.
You can choose the format of your excerpt in your GraphQL query for the post, it looks like the format you're using is HTML, you want PLAIN:
https://www.gatsbyjs.org/packages/gatsby-transformer-remark/#format
Try modifying your query by putting the format parameter on the excerpt field:
{
allMarkdownRemark {
edges {
node {
excerpt(format: PLAIN)
}
}
}
}
Edit: Hacky way of removing the <p> tags due to the inefficiencies in this gatsby-source-wordpress plugin.
Add a helper called removeParagraphTags this will simply trim the first three chars from the string and the last 4 chars from the string.
removeParagraphTags (excerpt) {
return excerpt.substr(3, excerpt.length - 7)
}
Then you can use this helper when setting the excerpt HTML.
dangerouslySetInnerHTML={{
__html: this.removeParagraphTags(this.props.post.node.excerpt)
}}

Images not displaying when Print Preview (Or Print) in IE/Chrome/Firefox

I'm Web Developer and almost never work with design but have been given this bug which I'm struggling to rectify.
Some images appear correctly when I print/display the print preview page, however others don't. The key difference that I can see is that the images that don't appear are span tags with the image applied in css whilst the working images use the img tag.
Here are examples of the html:
Span with "icon" birth does not display:
<li class="media">
<div class="img">
<div class="h2 mtm">1889</div>
<span class="timeline-icon icon-birth"></span>
</div>
<div class="bd">
<h3 class="profile-subtitle mts">Born in ?</h3>
<p class="deemphasis mbn">
Search for Birth Record
</p>
</div>
</li>
Image.gif does display:
<li class="media">
<div class="img">
<div class="h6">
<strong>Spouse</strong></div>
<img src="image.gif" alt="" class="person-thumb dropshadow" />
</div>
<div class="bd">
<p class="mbn">Husband</p>
<h3 class="profile-subtitle">
Thomas <strong>Name</strong>
</h3>
<p class="mbn">?-?</p>
</div>
</li>
In some browsers it looks ok in the preview but does not print, in others it doesn't and still does not print.
Thankyou in advance!
I had the same problem over two months ago. I had a button that redirected users to a printer-friendly page and then I triggered print dialog using Javascript.
The problem was that browsers did not wait till images specified in CSS background were downloaded.
I put timeout before triggering the print dialog to give browser time to download images. This approach is not reliable since nobody has constant download speed and it would open the print dialog before the images are downloaded to users with very slow Internet connection.
In the end, I used HTML img tags to embed images on my page and jQuery to trigger the print dialog when the last image is downloaded.
You need to put delay before print. There is a native bug in chrome. Code would as under :-
function PrintDiv(data) {
var mywindow = window.open();
var is_chrome = Boolean(mywindow.chrome);
mywindow.document.write(data);
if (is_chrome) {
setTimeout(function() { // wait until all resources loaded
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10
mywindow.print(); // change window to winPrint
mywindow.close(); // change window to winPrint
}, 250);
} else {
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10
mywindow.print();
mywindow.close();
}
return true;
}
Just add the below styles to make it work img{max-width:100%;height:auto;}
Its the width of the image being set to 0 in the print which is causing the issue.
make a print stylesheet, set your span to display:block

Resources