Rendering code with syntax highlighting from a CMS - reactjs

I am using a headless CMS(Strapi) and React on the frontend. I would like to render code blocks with highlighting using PrismJS (or anything).
In my render():
<div>
<pre>
<code className="language-css">{`p { color: red }`}</code>
</pre>
<h2>{this.state.title}</h2>
<div dangerouslySetInnerHTML={{ __html: `${content}` }} />
</div>
The code wrapped with <pre> tags serves as an example of what I'm trying to do.
The problem is that since I'm using the Strapi CMS, the code block not recognized by PrismJS. Here's how it's rendered:
The top part is the code directly written in my component while the bottom is returned from the CMS. In the WYSIWYG of the CMS I have the following <pre><code class="language-css">p { color: red }</code></pre>
Is there a way that I can write content with text and code and have the code highlighted properly?
This seems like a similar issue: React : Rendering a syntax highlighted code block

This solved my problem: https://github.com/akiran/react-highlight
Be sure to set your CSS in index.html and I added the following in my project:
<Highlight language="javascript" innerHTML={true}>
{content}
</Highlight>
Works perfectly! Hope this helps someone.

Related

Embed GitHub Gist using Remix

Is it possible to embed a Gist in Remix? I'm trying to embed the following gist in Remix using:
<script src='https://gist.github.com/AnthonyLzq/7d1cfeda389b7f5f38b62bd2640a32ba.js'></script>
But it is not displaying anything.
The problem is that React is trying to hydrate the <script> element. Since you don't want React to process this, you need to treat it as raw HTML.
<div
dangerouslySetInnerHTML={{
__html: `<script src="https://gist.github.com/AnthonyLzq/7d1cfeda389b7f5f38b62bd2640a32ba.js"></script>`,
}}
/>

Issues using react-loading-overlay

I have a simple react app, and im trying to add a simple loading overlay.
I saw the most common usage is react-loading-overlay.
My main app.js structure looks like that, I have a simple menu and a deck.gl map
<div className="container">
<AppMenu/>
<div className="deckgl_map">
<DeckMap/>
</div>
</div>
If I get it correctly, to use the loading overlay, I need to do something like that (using true for testing):
<LoadingOverlay
active={isActive}
spinner
text='Loading your content...'
>
<div className="container">
<AppMenu/>
<div className="deckgl_map">
<DeckMap/>
</div>
</div>
</LoadingOverlay>
But once I do that, my entire app page, instead of filling the whole screen, just takes the top 20% of the screen (and the rest is empty white).
Why wrapping my component with the LoadOverlay component causes the whole page to look weird?
Do I need to "play" with the CSS for the LoadOverlay component?

How can I inject arbitrary string HTML content into the head of my gatsbyjs site?

I have a GatsbyJS site that I am working on where the main content source is a Wordpress install. One of the things I like to add to my sites is the ability to have placeholder areas in the site where I can control the content via the CMS. Usually I have a header_scripts area that goes at the bottom of the <head> tag, a body_scripts area that goes at the start of the <body> tag, and a footer_scripts area that goes at the bottom of the page <body>. With these three, I can usually integrate third-party add-ins pretty easily without having to do code deployments.
Sometimes I need to embed stylesheets, sometimes I need to embed script tags, and sometimes I need to throw in <meta> tags. Really the content could be anything. This data comes back as a raw string from my Wordpress GraphQL endpoint.
So now my question is, how do I get this content injected into my Gatsby site in the following places:
<html>
<head>
...
{header_scripts}
</head>
<body>
{body_scripts}
...
{footer_scripts}
</body>
</html>
I've found so far that I can just include the body_scripts and footer_scripts in a fairly regular manner in my Gatsby page template. In gatsby-node.js, I pass in the property values using the pageContext. It's kind of a bummer that they need to be wrapped in a <div /> tag, but they seem to work just fine.
import React from 'react'
export default class PageTemplate extends React.Component {
render = () => {
return (
<React.Fragment>
{this.props.pageContext.bodyScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.bodyScripts}} />
)}
{/* my page content here */}
{this.props.pageContext.footerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
)}
</React.Fragment>
)
}
}
Now for the real question. I am stumped on how to get the dynamic content from the header_scripts into the Gatsby server-side-rendering <head> tag. The closest thing I have found to being able to inject content into the head is to leverage the gatsby-ssr.js onRenderBody function. However, this seems to require pre-determined React component instances in order to function. I can't just pass it in plain raw string content and see the output in the page source:
export const onRenderBody = async ({
pathname,
setHeadComponents,
setHtmlAttributes,
setBodyAttributes,
setPreBodyComponents,
setPostBodyComponents,
setBodyProps
}, pluginOptions) => {
setHeadComponents(['<script>alert("hello");</script>'])
}
This results in an escaped string getting inserted into the <head> tag:
<html>
<head>
...
<script>alert("hello");</script>
</head>
<body>
...
</body>
</html>
I'm at a loss as to how to proceed. I can't just wrap my string in a <div /> tag like in the body because div tags can't go inside the head tag. I can't think of any head-capable HTML tags that would accept this kind of content.
The only idea I've had is to actually parse the string content into full React components. This seems daunting given the number of possible tags & formatting that I would need to support.
Am I going about this the wrong way? How can I get my arbitrary content into my Gatsby site's head tag?
It's a broad question and it will need some trials and errors to ensure that it's fully working without caveats in all scenarios but, among the things you've tried, you can add a few more options to the list to check which ones fit better.
Regarding the body_scripts and footer_scripts both can be inserted using the:
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
In any desired page or template. For the header_scripts and the meta tags (SEO), you can use the <Helmet> component. Basically, using this component, everything that is wrapped inside, it's becomes transpiled inside the <head> tag once compiled.
export default class PageTemplate extends React.Component {
render = () => {
return (
<React.Fragment>
<Helmet>
{this.props.pageContext.headerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.headScripts}} />
)}
</Helmet>
{this.props.pageContext.bodyScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.bodyScripts}} />
)}
{/* my page content here */}
{this.props.pageContext.footerScripts && (
<div dangerouslySetInnerHTML={{__html:this.props.pageContext.footerScripts}} />
)}
</React.Fragment>
)
}
}
However, if the data comes from a CMS, it won't be available in the SSR yet, so, one easy thing you can do is to customize the outputted HTML (html.js) that Gatsby generates in each compilation. From the docs:
Customizing html.js is a workaround solution for when the use of the
appropriate APIs is not available in gatsby-ssr.js. Consider using
onRenderBody or onPreRenderHTML instead of the method above. As a
further consideration, customizing html.js is not supported within a
Gatsby Theme. Use the API methods mentioned instead.
Run:
cp .cache/default-html.js src/html.js
Or manually, copy the .cache/default-html.js file and paste it /src folder. There you can customize the final HTML.

inject a react component as background-image

I am looking for the best way to inject a dynamically built image as my background image. I can build the image and I can display it as a div but I want it as the background of my body.
<div className="App">
<mycomonent />
</div>
works but it is not what I want
<body styles="background-image: {mycomponent}"></body>
You can change using regular DOM object within React.
document.body.style.backgroundImage = `url("https://www.placecage.com/c/460/300")`;
Working Demo

Botkit embed with React + React-Router results in 404 error

With React 16 and React-Router 4, I'm trying to using Botkit's embed code in a component, but it's just stuck in "Disconnected...reconnecting":
Code Sandbox is here
(I've removed the OnClick header and embedded_messenger divs as I want it to launch full-sized)
<div>
<iframe
title="botkit"
id="botkit_client"
src="//arrow-tarn.glitch.me/chat.html"
style={{ height: "80vh", width: "100%" }}
/>
<script src="//arrow-tarn.glitch.me/embed.js" />
<link rel="stylesheet" href="//arrow-tarn.glitch.me/css/embed.css" />
<script>var options = {}; Botkit.boot(options);</script>
</div>
);
When I run the app, I also get the following console error in Chrome:
GET http://arrow-tarn.glitch.me/%7B%7B%7Burl%7D%7D%7D 404 (Not Found)
Which of course translates unescaped to {{url}} not found.
I'm thinking it has to do with the initialization/options in React:
<script>var options = {}; Botkit.boot(options);</script>
Any clue what am I doing wrong?
The {{url}} problem is your browser parsing the template and rendering the (hidden) image tag. This isn't the issue causing it to fail.
Something about your iframe is causing the chat client to fail when connecting to the server... did you make any changes to the off the shelf code?

Resources