I don't see SVG on my website while using NEXTjs - svg

i have problem with importing SVG to my NextJS website.
I've tried using <Image /> tag, <img /> tag too and <svg> tag also.
Webstorm sees the image, but browser doesn't.
code:
import Logo from "../public/file.svg"
const Navbar = () => {
return (
<div>
<nav>
<div>
<Image src={Logo} alt="logo" height={50} width={50}/>

I had a problem like this. The problem was gone when I replaced the imported .svg file and placed the URL directly in the Image. like this:
const Navbar = () => {
return (
//...
<Image src="/file.svg" alt="logo" height="50px" width="50px"/>
);
}
Notice that with this method, you start your URL with a / from public folder and should not include ../public itslef.

Related

Load specific DIV with a react component without reloading the whole page

I have a menu where every menu item is a button and I want to load a specific reactjs component into a specific div without reloading the whole page.
This is the current code, clearly is bad but I don't know where to start fixing it...
...
<Button onClick={this.loadTarget}>
{menuItem.name}
</Button>
...
loadTarget(event) {
document.getElementById("datapanel").innerHTML="abc<TranslationsList />";
}
When I click a menu Item I want to load my div with the value "abc<TranslationsList />". "abc" is displayed but the custom component "TranslationsList" is not and I guess this is normal as the TranslationsList tag is not a HTML tag. But how could I load my component?
I could use links instead of buttons but in this case the question is how could I update the div content with a specific link?
It's hard if you've programmed plain JS before, but you have to forget the "good old JS pattern" in React. I also had a hard time getting used to not using standard JS elements (target, innerHTML, etc.) to solve such a problem.
So the solution in React is to use the framework and your page reload problem will be solved immediately. useState for the state of the component and handlers for the click. My main code looks like this. You can find a working application at Codesandbox.
export default function App() {
const [showComponent, setShowComponent] = useState(false);
const handleButtonClick = (e) => {
setShowComponent(!showComponent);
};
return (
<div className="App">
<h1>
Load specific DIV with a react component without reloading the whole
page
</h1>
<a href="https://stackoverflow.com/questions/74654088/load-specific-div-with-a-react-component-without-reloading-the-whole-page">
Link to Stackoverflow
</a>
<div style={{ marginTop: "20px" }}>
<button onClick={handleButtonClick}>Magic</button>
</div>
{showComponent ? (
<div style={{ marginTop: "20px" }}>
This is the place of your component!
</div>
) : (
""
)}
</div>
);
}
In the first place I wpuld not use vanilla JS syntax on a react app if it is not necessary. i.e: document.getElementById("datapanel").innerHTML="abc<TranslationsList />".
If you are using React you should be managing the State in the component of the DIV, giving the order to make an element appear once the button is clicked.
A simple example can be this:
CodeSandbox
import { useState } from "react";
export default function App() {
const [divState, setDivState] = useState(null);
const divElement = () => <div>I am the element that should appear</div>;
const handleDiv = () => {
setDivState(divElement);
};
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<button onClick={handleDiv}>Show DIV</button>
<div>{divState}</div>
</div>
);
}
I agree with the answers given above. Since you are already using React, you should take advantage of its features/functionalities. No need to reinvent the wheel.
However, if you are still interested in how to make your current implementation work. You may use renderToString(), which can be imported from ReactDOMServer. Please refer to the following code snippet as an example.
import { renderToString } from 'react-dom/server'
const TranslationsList = () => {
return <div>TranslationsList Content</div>
}
export default function App() {
const loadTarget = () => {
document.getElementById("datapanel").innerHTML=`abc${renderToString(<TranslationsList />)}`;
}
return (
<div>
<button onClick={loadTarget}>Insert Component</button>
<div id="datapanel">Data Panel Holder</div>
</div>
);
}

CKEditor5 image resize not working correctly

I integrate CKEditor5 editor on my project to do email template. Below is my CKEditor code:
<CKEditor
editor={ ClassicEditor }
config={ {
toolbar: [ 'heading', 'bold', 'italic', 'bulletedList', 'numberedList', 'blockQuote' , 'fontColor' , 'fontBackgroundColor' , 'code', 'uploadImage'],
ckfinder:{
uploadUrl:'upload url'
}} }
data={template}
onReady={ editor => {
// You can store the "editor" and use when it is needed.
//console.log( 'Editor is ready to use!', editor );
} }
onChange={ ( event, editor ) => {
const data = editor.getData();
console.log(data)
setTemplate(data)
} }
/>
When I store image using CKEditor in my database the CKEditor code comes like this:
<figure class="image image_resized" style="width:2.82%;"><img src="https://www.w3schools.com/html/pic_trulli.jpg"></figure><p> welcome to {{first_name}}</p>
My template comes like this:
I styled in CKEditor like the below image, but the image resize not coming in my template:
The issue is when use figure tag like this it works:
<figure>
<img src="pic_trulli.jpg" alt="Trulli" style="width:10%">
<figcaption>Fig.1 - Trulli, Puglia, Italy.</figcaption>
</figure>
but in CKEditor automatically code generating like this:
<figure style="width:20%;">
<img src="https://www.w3schools.com/html/pic_trulli.jpg">
<figcaption>Fig.1 - Trulli, Puglia, Italy.</figcaption>
</figure>
look at this, I guess you need to change the figure tag display to block.
<html>
<head>
<style>
figure {
display: block;
}
</style>
</head>
<body>
<p>A figure element is displayed like this:</p>
<figure>
<img src="img_pulpit.jpg" alt="The Pulpit Rock" width="2%" >
</figure>
<p>Change the default CSS settings to see the effect.</p>
</body>
</html>

How do I create show page based on id of item clicked

I am creating list of items looped through .map function. I want each of these items be rendered in a single page with some other details.
import React from 'react'
import {faArrowRight, faMusic, faPlay, faPlayCircle, faTachometerAlt} from "#fortawesome/free-solid-svg-icons";
import {FontAwesomeIcon} from "#fortawesome/react-fontawesome";
import music from '../mocks/music.json'
import { Link } from 'gatsby'
import Music from '../pages/music'
const newData = music.map( (data) => {
return (
<div className="row no-gutters justify-content-between align-items-center">
<div className="col-auto">
<button className="btn-gradient btn-circle">
<FontAwesomeIcon icon={faPlayCircle} />
</button>
</div>
<div className="col">
<div className="music-list-content">
<span className="artist">{data.author}</span>
<Link to={`/music/${data.id}`}>{data.title}</Link>
<span className="play">
<FontAwesomeIcon icon={faPlay} /> {data.duration}
</span>
</div>
</div>
<div className="col-auto">
<span className="badge-dark badge">{data.genre}</span>
</div>
</div>
)
})
const membersToRender = music.filter(member => member.id)
const numRows = membersToRender.length
const Musics = () => {
return (
<div>
<div className="title">
<h5>New Music</h5>
<span>{numRows} new songs</span>
</div>
<div>
<div className="music-list card-wrapper">
{newData}
</div>
</div>
<div className="footer-wrapper">
<div>
<FontAwesomeIcon icon={faMusic} />
<span>Song Library</span>
</div>
<FontAwesomeIcon icon={faArrowRight} />
</div>
</div>
)
}
export default Musics
I created a link which whenever I click, it takes me to another page (page not found) with id appended and .js extension.
Please, how do go about it? I want a click on the title and have it displayed on a full page.
Your logic seems good, however, you are missing the most important part, the page creation, since you are not creating the pages, all of your links are broken.
In Gatsby, you have two different ways of creating pages:
Using gatsby-node.js to create pages dynamically: when dealing with a huge amount of data, like your JSON, it's easier to let Gatsby deal with this responsibility of creating pages for Gatsby. Since you are sourcing from a JSON, you need everything set to create dynamic pages.
const path = require("path")
// Implement the Gatsby API “createPages”. This is called once the
// data layer is bootstrapped to let plugins create pages from data.
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
const musics= require("./data/mocks/musics.json")
const musicTemplate = path.resolve(`src/templates/music-template.js`)
musics.forEach(music) => {
createPage({
path: `/music/${music.slug}`
component: musicTemplate,
context: {
title: music.title,
description: music.description,
// and so on for the rest of the fields
},
})
})
}
Note: I'm assuming that your JSON is properly defined and formatted, having all the fields I queried.
Your musicTemplate must be a template (inside /templates folder).
Notice that you are passing some fields through Gatsby's context, this means that those fields will be available through props.pageContext in your template. So, there, create a template like:
import React from "react"
import Layout from "../components/layout"
export default function MusicTemplate({pageContext}) {
return (
<Layout>
<div>Hello musician {pageContext.title}</div>
</Layout>
)
}
So, as I said, with this approach you are creating dynamic pages based on your JSON file, and they will be available inside localhost:8000/music/{music.slug}, and all your reference and links that point there, will be valid.
I would also recommend using static query/useStaticQuery to retrieve data from your JSON in that loop. If you create a static query from that data (in a separate component) you will be able to fetch it on-demand across your project, so you will be reusing an interesting part of logic. It's better to use it rather than requesting a JSON directly.
You can follow this guide from the great Jason Lengstorf which is mostly what you need.
Adding .js files in your /pages folder: Gatsby infers the internal structure of your /pages folder and will create pages accordingly to that structure. For instance, if you have a structure like: /pages/musicians/name1.js Gatsby will create a page like localhost:8000/musicians/name1.
As it has been said, the first approach fits your requirements and it's preferred for this use-cases, since the second one will be less scalable and maintainable.
You should do some routing with React-Router (https://reactrouter.com/web/example/basic).
So the link have to point to a Route in a Switch, as is in the example of the link.

How to render the HTML into react component

I want to render the pure HTML coming from some external source into react component. I saw few solutions where people are talking about some conversion tools (HTML to JSX) but I want to handle everything in my component so while mounting it will get the HTML response and that needs to render.
You can use dangerouslySetInnerHTML for this:
function createMarkup() { return {__html: 'First · Second'}; };
<div dangerouslySetInnerHTML={createMarkup()} />
But as the method name suggests: you should be very sure of what you are doing there and the security implications it has.
This shouldn't be difficult to do . Assign your HTML to a div and then render it using {variable name} JSX allows you to do this and with ES6 integration you can also use class instead of className.
var Hello = React.createClass({
render: function() {
var htmlDiv = <div>How are you</div>
return <div>Hello {this.props.name}
{htmlDiv}
</div>;
}
});
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script>
<div id="container">
<!-- This element's contents will be replaced with your component. -->
</div>

SVG + Angular2 code sample does not work with interpolation

My goal is to convert code from Angular 1.3 to Angular 2 (with SVG in both cases).
I tried the following simple test code, which works in case #1 that does not involve interpolation, but does not work in case #2 (which uses interpolation), and AFAICS the only difference in the generated SVG code is the inclusion of an extra attribute in the element: class="ng-binding"
Is there a way to suppress the preceding class attribute, or is there another solution?
Btw I wasn't able to get the formatting quite right (my apologies).
Contents of HTML Web page:
<html>
<head>
<title>SVG and Angular2</title>
<script src="quickstart/dist/es6-shim.js"></script>
</head>
<body>
<!-- The app component created in svg1.es6 -->
<my-svg></my-svg>
<script>
// Rewrite the paths to load the files
System.paths = {
'angular2/*':'/quickstart/angular2/*.js', // Angular
'rtts_assert/*': '/quickstart/rtts_assert/*.js', // Runtime assertions
'svg': 'svg1.es6' // The my-svg component
};
System.import('svg');
</script>
</body>
</html>
Contents of the JS file:
import {Component, Template, bootstrap} from 'angular2/angular2';
#Component({
selector: 'my-svg'
})
#Template({
//case 1 works:
inline: '<svg><ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse></svg>'
//case 2 does not work:
//inline: "<svg>{{graphics}}</svg>"
})
class MyAppComponent {
constructor() {
this.graphics = this.getGraphics();
}
getGraphics() {
// return an array of SVG elements (eventually...)
var ell1 =
'<ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse>';
return ell1;
}
}
bootstrap(MyAppComponent);
SVG elements do not use the same namespace as HTML elements. When you insert SVG elements into the DOM, they need to be inserted with the correct SVG namespace.
Case 1 works because you are inserting the whole SVG, including the <svg> tags, into the HTML. The browser will automatically use the right namespace because it sees the <svg> tag and knows what to do.
Case 2 doesn't work because you are just inserting an <ellipse> tag and the browser doesn't realise it is supposed be created with the svg namespace.
If you inspect both SVGs with the browser's DOM inspector, and look at the <ellipse> tag's namespace property, you should see the difference.
You can use outerHtml of an HTML element like:
#Component({
selector: 'my-app',
template: `
<!--
<svg xmlns='http://www.w3.org/2000/svg'><ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse></svg>
-->
<span [outerHTML]="graphics"></span>`
})
export class App {
constructor() {
this.graphics = this.getGraphics();
}
getGraphics() {
// return an array of SVG elements (eventually...)
var ell1 =
'<svg><ellipse cx="100" cy="100" rx="80" ry="50" fill="red"></ellipse></svg>';
return ell1;
}
}
note that the added string has to contain the <svg>...</svg>
See also How can I add a SVG graphic dynamically using javascript or jquery?

Resources