Snipcart Crawling product failed in a nextjs app - javascript

I'm using snipcart in a nextjs with strapi app.
I receive an error when processing a payment :
A 'cart-confirmation' error occured in Snipcart. Reason:
'product-crawling-failed'
[Details] We have not been able to find item with id '59' at
'https://cmeditions.fr/products/selfless'. Please make sure the
product is correctly defined.
and :
An attempt to create an order with invalid products has been made.
Don't forget you can't add/update items attributes in the cart
dynamically with javascript as it will cause crawling issues
It works when data-item-id is replaced by a static value but not with somthing like {product.id}
Here is my component [sulg].js :
const ProductPage = ({ product }) => {
const router = useRouter()
if (router.isFallback) {
return <div>Loading product...</div>
}
return (
<div className="carousel-container m-6 grid grid-cols-1 gap-4 mt-8 items-start">
<Head>
<title>{product.title}</title>
</Head>
<div className="rounded-t-lg pt-2 pb-2 m-auto h-auto">
<EmblaCarousel {...product} />
</div>
<div className="w-full p-5 flex flex-col justify-between">
<div>
<h4 className="mt-1 font-semibold leading-tight truncate text-slate">
<span className="uppercase text-lg font-bold">{product.title}</span>
<br />
{product.author}
</h4>
<LanguageDesc {...product} />
</div>
<div className="flex flex-col md:flex-row">
<div className="mt-4 font-semibold leading-tight truncate text-slate">
<p>{product.year}</p>
<p>Format: {product.size}</p>
<p>Printing: {product.technic}</p>
<p>Paper: {product.medium}</p>
<p>{product.page}</p>
<p>{product.copies} copies</p>
<p>{product.price}€</p>
</div>
{product.status === "published" ? (
<button
className="snipcart-add-item mt-4 ml-16 self-center bg-slate border border-gray-200 d hover:shadow-lg hover:bg-brique focus:outline-none text-white font-semibold leading-none py-2 px-4 w-20 h-20 rounded-full"
data-item-id={product.id}
data-item-price={product.price}
data-item-url={router.asPath}
data-item-description={product.description}
data-item-image={getStrapiMedia(
product.image.formats.thumbnail.url
)}
data-item-name={product.title}
v-bind="customFields"
>
Add to cart
</button>
) : (
<div className="text-center mr-10 mb-1" v-else>
<div
className="p-2 bg-indigo-800 items-center text-indigo-100 leading-none lg:rounded-full flex lg:inline-flex"
role="alert"
>
<span className="flex rounded-full bg-indigo-500 uppercase px-2 py-1 text-xs font-bold mr-3">
Coming soon...
</span>
<span className="font-semibold mr-2 text-left flex-auto">
This article is not available yet.
</span>
</div>
</div>
)}
</div>
</div>
</div>
)
}
export async function getStaticProps({ params }) {
const product = await getProduct(params.slug)
return { props: { product } }
}
export async function getStaticPaths() {
const products = await getProducts()
return {
paths: products.map((_product) => {
return {
params: { slug: _product.slug },
}
}),
fallback: true,
}
}
export default ProductPage
EDIT
I tried to return a json to the validator, but I think it isn't right
/api/products.js
import { getProducts } from "../../utils/api"
// eslint-disable-next-line import/no-anonymous-default-export
export default async function (_req, res) {
return new Promise((resolve) => {
getProducts()
.then((response) => {
res.statusCode = 200
res.setHeader("Content-Type", "application/json")
res.setHeader("Cache-Control", "max-age=180000")
res.end(JSON.stringify(response))
resolve()
})
.catch((error) => {
res.json(error)
res.status(405).end()
resolve() // in case something goes wrong in the catch block (as vijay commented)
})
})
}
api.js
export function getStrapiURL(path) {
return `${
process.env.NEXT_PUBLIC_STRAPI_API_URL || "http://localhost:1337"
}${path}`
}
// Helper to make GET requests to Strapi
export async function fetchAPI(path) {
const requestUrl = getStrapiURL(path)
const response = await fetch(requestUrl)
const data = await response.json()
return data
}
export async function getCategories() {
const categories = await fetchAPI("/categories")
return categories
}
export async function getCategory(slug) {
const categories = await fetchAPI(`/categories?slug=${slug}`)
return categories?.[0]
}
export async function getProducts() {
const products = await fetchAPI("/products")
return products
}
export async function getProduct(slug) {
const products = await fetchAPI(`/products?slug=${slug}`)
return products?.[0]
}
export async function getLibrairies() {
const librairies = await fetchAPI("/librairies")
return librairies
}
export async function getLibrairie(slug) {
const librairies = await fetchAPI(`/librairies?slug=${slug}`)
return librairies?.[0]
}

It sounds like you will need to validate the orders with a JSON file that you can assign to the buy button with data-item-url.
You can read the full guide here:
https://docs.snipcart.com/v3/setup/order-validation#json-crawler.
Let me know if that helps!

It finally wasn't a matter of JSON crawler but something to see with the domain on the snipcart dashboard. I had to put the vercel.app domain first and my own domain name as a subdomain. It worked when I changed this. This is the only explaination I got

Related

View confirmed attendees from past events on web3 app; Javascript; imports from React and Apollo Client - how to fix a Syntax error in code

The page for my web3-based event application works fine until I go into my "past events" and click "attendees." When I do that, I get Syntax error: Unexpected token.
The issue is specifically on line 86 of my code, for (let i = 0; < event.confirmedAttendees.length; i++) {. In VS Code, I have 4 errors, all of which point to this line. The errors are "parsing error: unexpected token", 2 "identifier expected" errors, and 1 "expression expected."
I've checked the code against the GitHub repo I forked the entire project file from, edited it, and now it all matches.
I'm new to coding with no previous JS experience. I've been scratching my head on this one all day. I have no idea what the issue is.
Here is the entire code from my [id].js file. The issue is with line 86.
import { useState, useEffect } from "react";
import Head from "next/head";
import Link from "next/link";
import { gql } from "#apollo/client";
import client from "../../../apollo-client";
import { ConnectButton } from "#rainbow-me/rainbowkit";
import { useAccount } from "wagmi";
import connectContract from "../../../utils/connectContract";
import formatTimestamp from "../../../utils/formatTimestamp";
import DashboardNav from "../../../components/DashboardNav";
import Alert from "../../../components/Alert";
function PastEvent({ event }) {
const { data: account } = useAccount();
console.log("event", event);
const [success, setSuccess] = useState(null);
const [message, setMessage] = useState(null);
const [loading, setLoading] = useState(null);
const [mounted, setMounted] = useState(false);
const confirmAttendee = async (attendee) => {
try {
const rsvpContract = connectContract();
if (rsvpContract) {
const txn = await rsvpContract.confirmAttendee(event.id, attendee);
setLoading(true);
console.log("Minting...", txn.hash);
await txn.wait();
console.log("Minted -- ", txn.hash);
setSuccess(true);
setLoading(false);
setMessage("Attendance has been confirmed.");
} else {
console.log("Ethereum object doesn't exist!");
}
} catch (error) {
setSuccess(false);
// setMessage(
// `Error: ${process.env.NEXT_PUBLIC_TESTNET_EXPLORER_URL}tx/${txn.hash}`
// );
setMessage("Error!");
setLoading(false);
console.log(error);
}
};
const confirmAllAttendees = async () => {
console.log("confirmAllAttendees");
try {
const rsvpContract = connectContract();
if (rsvpContract) {
console.log("contract exists");
const txn = await rsvpContract.confirmAllAttendees(event.id, {
gasLimit: 300000,
});
console.log("await txn");
setLoading(true);
console.log("Mining...", txn.hash);
await txn.wait();
console.log("Mined -- ", txn.hash);
setSuccess(true);
setLoading(false);
setMessage("All attendees confirmed successfully.");
} else {
console.log("Ethereum object doesn't exist!");
}
} catch (error) {
setSuccess(false);
// setMessage(
// `Error: ${process.env.NEXT_PUBLIC_TESTNET_EXPLORER_URL}tx/${txn.hash}`
// );
setMessage("Error!");
setLoading(false);
console.log(error);
}
};
function checkIfConfirmed(event, address) {
// console.log(event.confirmedAttendees);
for (let i = 0; < event.confirmedAttendees.length; i++) {
let confirmedAddress = event.confirmedAttendees[i].attendee.id;
if (confirmedAddress.toLowercase() == address.toLowercase()) {
return true;
}
}
return false;
}
useEffect(() => {
setMounted(true);
}, []);
return (
mounted && (
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<Head>
<title>My Dashboard | web3rsvp</title>
<meta name="description" content="Manage your events and RSVPs" />
</Head>
<div className="flex flex-wrap py-8">
<DashboardNav page={"events"} />
<div className="sm:w-10/12 sm:pl-8">
{loading && (
<Alert
alertType={"loading"}
alertBody={"Please wait"}
triggerAlert={true}
color={"white"}
/>
)}
{success && (
<Alert
alertType={"success"}
alertBody={message}
triggerAlert={true}
color={"palegreen"}
/>
)}
{success === false && (
<Alert
alertType={"failed"}
alertBody={message}
triggerAlert={true}
color={"palevioletred"}
/>
)}
{account ? (
account.address.toLowerCase() ===
event.eventOwner.toLowerCase() ? (
<section>
<Link href="/my-events/past">
<a className="text-indigo-800 text-sm hover:underline">
← Back
</a>
</Link>
<h6 className="text-sm mt-4 mb-2">
{formatTimestamp(event.eventTimestamp)}
</h6>
<h1 className="text-2xl tracking-tight font-extrabold text-gray-900 sm:text-3xl md:text-4xl mb-8">
{event.name}
</h1>
<div className="-my-2 -mx-4 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle md:px-6 lg:px-8">
<div className="overflow-hidden shadow ring-1 ring-black ring-opacity-5 md:rounded-lg">
<table className="min-w-full divide-y divide-gray-300">
<thead className="bg-gray-50">
<tr>
<th
scope="col"
className="py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-gray-900 sm:pl-6"
>
Attendee
</th>
<th
scope="col"
className="text-right py-3.5 pl-3 pr-4 sm:pr-6"
>
<button
type="button"
className="items-center px-4 py-2 border border-transparent text-sm font-medium rounded-full text-indigo-700 bg-indigo-100 hover:bg-indigo-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
onClick={confirmAllAttendees}
>
Confirm all
</button>
</th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200 bg-white">
{event.rsvps.map((rsvp) => (
<tr key={rsvp.attendee.id}>
<td className="whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-900 sm:pl-6">
{rsvp.attendee.id}
</td>
<td className="relative whitespace-nowrap py-4 pl-3 pr-4 text-right text-sm font-medium sm:pr-6">
{checkIfConfirmed(event, rsvp.attendee.id) ? (
<p>Confirmed</p>
) : (
<button
type="button"
className="text-indigo-600 hover:text-indigo-900"
onClick={() =>
confirmAttendee(rsvp.attendee.id)
}
>
Confirm attendee
</button>
)}
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
</section>
) : (
<p>You do not have permission to manage this event.</p>
)
) : (
<ConnectButton />
)}
</div>
</div>
</div>
)
);
}
export default PastEvent;
export async function getServerSideProps(context) {
const { id } = context.params;
const { data } = await client.query({
query: gql`
query Event($id: String!) {
event(id: $id) {
id
eventID
name
eventOwner
eventTimestamp
maxCapacity
totalRSVPs
totalConfirmedAttendees
rsvps {
id
attendee {
id
}
}
confirmedAttendees {
attendee {
id
}
}
}
}
`,
variables: {
id: id,
},
});
return {
props: {
event: data.event,
},
};
}
It looks like you missed the i in the for loop check in this function:
function checkIfConfirmed(event, address) {
// console.log(event.confirmedAttendees);
for (let i = 0; < event.confirmedAttendees.length; i++) {
let confirmedAddress = event.confirmedAttendees[i].attendee.id;
if (confirmedAddress.toLowercase() == address.toLowercase()) {
return true;
}
}
return false;
}
Take a look at the second line in your function:
// currently:
for (let i = 0; < event.confirmedAttendees.length; i++)
// missing i in the check, should be:
for (let i = 0; i < event.confirmedAttendees.length; i++)
Let me know if anything seems unclear regarding for loops!

Alpine js and Tailwind fetch data

I start to learn the alpine js combine with the tailwind. But I don't know how to print the fetch result from json response, try with this
<div x-data="orderSearch()"
class="container mx-auto py-6 px-4"
>
<div class="flex border-2 border-gray-200 rounded">
<input type="text" class="px-4 py-2 w-100 uppercase" placeholder="Search" name="orderidSearch"
x-model="orderidSearch">
<button #click="fetchFulfillment()" class="px-2 py-1 text-white bg-blue-500 rounded hover:bg-green-600">Cari Fulfillment</button>
but return the error in console alpine.js:115 Alpine Error: "TypeError: Cannot read properties of undefined (reading 'inv_id')"
Anyone know how to print the result inside div?
My js function:
function orderSearch() {
return {
orderidSearch: '',
// other default properties
orders: [],
fetchOrders() {
this.isLoading = true;
fetch(`check.php?order_id=${this.orderidSearch}`)
.then(res => res.json())
.then(data => {
this.isLoading = false;
this.orders = data.orders;
console.log(data);
});
console.log(this.orders);
},
....
json return data:
{"data":[{"inv_id":"8768768768"]}
The problem occurs because you will get an iterable object. I rewrite your code a little bit and put the function inline to show the first entry. If you have a collection then build your loop to sow every item.
<div
class="container mx-auto py-6 px-4"
x-data="{
orders: null,
isLoading: false,
orderSearch() {
this.isLoading = true;
fetch(`check.php?order_id=${this.orderidSearch}`)
.then((response) => response.json())
.then((json) => this.orders = json);
}
}" x-init="orderSearch()">
<p x-text="orders[0].inv_id"></p>
</div>

GraphQL query giving a "cannot read properties of undefined error"

I wrote a graphql query to get recent posts for a blog app in NextJs in other to display them as widgets
export const getRecentPosts = async () =\> {
const query = gql`
query MyQuery {
posts(orderBy: createdAt_ASC
last: 3 )
{title
featuredImage {url}
createdAt
slug
}
}
`;
const result = await request(graphAPI, query);
return result.posts;
};
but i keep getting a "Cannot read properties of undefined (reading 'document')" error
and it keeps displaying this error
NextJs error
I imported the function into the component
function PostWidget({ categories, slug }) {
const [relatedPosts, setRelatedPosts] = useState([]);
useEffect(() => {
if (slug) {
getSimilarPosts(categories, slug).then((result) => {
setRelatedPosts(result);
});
} else {
getRecentPosts().then((result) => {
setRelatedPosts(result);
});
}
}, [slug]);
console.log(relatedPosts)
return (
<div className="bg-white shadow-lg rounded-lg p-8 mb-8">
<h3 className="text-xl mb-4 font-semibold border-b p-4">
{slug ? "Related posts" : "Recent posts"}
</h3>
{
relatedPosts.map((post) => (
<div key={post.title} className="flex items-center w-full mb-4">
<div className="w-16 flex-none">
<img
alt={post.title}
height="60px"
width="60px"
className="align-middle rounded-full"
src={post.featuredImage.url}
/>
</div>
</div>
))
}
</div>
)
}
but it gives an empty array when i console.log the related posts

Unhandled Runtime Error while executing a JS code

On my Localhost:3000, when I am running the code, I am getting an error saying:
Unhandled Runtime Error
TypeError: Cannot read properties of undefined (reading 'id')
For the Source part, it is showing a certain section of my code, which is:-
;(async () => {
20 | setSelectedMarketNft(
> 21 | listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
| ^
22 | )
23 | })()
24 | }, [selectedNft, listings, isListed])
There are certain questions of the similar type on stackOverflow, but I am unable to find any answers from any of them. I am making a web3 project, where I am using next.js, sanity and thirweb.
The source code that contains this is:-
const MakeOffer = ({ isListed, selectedNft, listings, marketPlaceModule }) => {
const [selectedMarketNft, setSelectedMarketNft] = useState()
const [enableButton, setEnableButton] = useState(false)
useEffect(() => {
if (!listings || isListed === 'false') return
;(async () => {
setSelectedMarketNft(
listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
)
})()
}, [selectedNft, listings, isListed])
useEffect(() => {
if (!selectedMarketNft || !selectedNft) return
setEnableButton(true)
}, [selectedMarketNft, selectedNft])
Link to the full source code of the file where this error is occuring is:-
https://github.com/hemang-h/Standard-Demo-Marketplace-and-Minting/blob/main/components/nft/Purchase.js
Can anyone guide me what I am doing wrong here?
EXTRAS
Just for a better understanding, this is the full source code of the file where I am facing this error:
import { useEffect, useState } from 'react'
import { HiTag } from 'react-icons/hi'
import { IoMdWallet } from 'react-icons/io'
import toast, { Toaster } from 'react-hot-toast'
const style = {
button: `mr-8 flex items-center py-2 px-12 rounded-lg cursor-pointer`,
buttonIcon: `text-xl`,
buttonText: `ml-2 text-lg font-semibold`,
}
const MakeOffer = ({ isListed, selectedNft, listings, marketPlaceModule }) => {
const [selectedMarketNft, setSelectedMarketNft] = useState()
const [enableButton, setEnableButton] = useState(false)
useEffect(() => {
if (!listings || isListed === 'false') return
;(async () => {
setSelectedMarketNft(
listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
)
})()
}, [selectedNft, listings, isListed])
useEffect(() => {
if (!selectedMarketNft || !selectedNft) return
setEnableButton(true)
}, [selectedMarketNft, selectedNft])
const confirmPurchase = (toastHandler = toast) =>
toastHandler.success(`Purchase successful!`, {
style: {
background: '#04111d',
color: '#fff',
},
})
const buyItem = async (
listingId = selectedMarketNft.id,
quantityDesired = 1,
module = marketPlaceModule
) => {
console.log(listingId, quantityDesired, module, 'david')
// yo RAZA lets goooo!!!
//yo Qazi, ok
// sure okay about to run it...
// just clicked buy now...
// still error
// where can i see the contract address of the marketplace module
// in [nftId.js]
await module
.buyoutDirectListing({
listingId: listingId,
quantityDesired: quantityDesired,
})
.catch((error) => console.error(error))
confirmPurchase()
}
return (
<div className="flex h-20 w-full items-center rounded-lg border border-[#151c22] bg-[#303339] px-12">
<Toaster position="bottom-left" reverseOrder={false} />
{isListed === 'true' ? (
<>
<div
onClick={() => {
enableButton ? buyItem(selectedMarketNft.id, 1) : null
}}
className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}
>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>Buy Now</div>
</div>
<div
className={`${style.button} border border-[#151c22] bg-[#363840] hover:bg-[#4c505c]`}
>
<HiTag className={style.buttonIcon} />
<div className={style.buttonText}>Make Offer</div>
</div>
</>
) : (
<div className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>List Item</div>
</div>
)}
</div>
)
}
export default MakeOffer
selectedNFT is undefined as mentioned above.
The issue could be that it is running your code before it's defined.
This may go in your return function:
{(typeof selectedNFT != 'undefined') ? (
<div>Code that fetches from selectedNFT goes here.</div>
): (
<div>This could be a loading bar..</div>
)}
This will run your code ONLY after everything else executes.
You can check by console seletedNft inside makeoffer component to make sure you are getting props correctly and also check if its return object which has key with name "id" . Its cannot read id property in your selectedNft make sure its exist . I hope its help.
The error is solved, turns out that I just had to add
if(!selectedNft) return;
to successfully run my code. Final code will be as:
import { useEffect, useState } from 'react'
import { HiTag } from 'react-icons/hi'
import { IoMdWallet } from 'react-icons/io'
import toast, { Toaster } from 'react-hot-toast'
const style = {
button: `mr-8 flex items-center py-2 px-12 rounded-lg cursor-pointer`,
buttonIcon: `text-xl`,
buttonText: `ml-2 text-lg font-semibold`,
}
const MakeOffer = ({ isListed, selectedNft, listings, marketPlaceModule }) => {
const [selectedMarketNft, setSelectedMarketNft] = useState()
const [enableButton, setEnableButton] = useState(false)
useEffect(() => {
if(!selectedNft) return;
if (!listings || isListed === 'false') return
;(async () => {
setSelectedMarketNft(
listings.find((marketNft) => marketNft.asset?.id === selectedNft.id)
)
})()
}, [selectedNft, listings, isListed])
useEffect(() => {
if (!selectedMarketNft || !selectedNft) return
setEnableButton(true)
}, [selectedMarketNft, selectedNft])
const confirmPurchase = (toastHandler = toast) =>
toastHandler.success(`Purchase successful!`, {
style: {
background: '#04111d',
color: '#fff',
},
})
const buyItem = async (
listingId = selectedMarketNft.id,
quantityDesired = 1,
module = marketPlaceModule
) => {
console.log(listingId, quantityDesired, module, 'david')
// yo RAZA lets goooo!!!
//yo Qazi, ok
// sure okay about to run it...
// just clicked buy now...
// still error
// where can i see the contract address of the marketplace module
// in [nftId.js]
await module
.buyoutDirectListing({
listingId: listingId,
quantityDesired: quantityDesired,
})
.catch((error) => console.error(error))
confirmPurchase()
}
return (
<div className="flex h-20 w-full items-center rounded-lg border border-[#151c22] bg-[#303339] px-12">
<Toaster position="bottom-left" reverseOrder={false} />
{isListed === 'true' ? (
<>
<div
onClick={() => {
enableButton ? buyItem(selectedMarketNft.id, 1) : null
}}
className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}
>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>Buy Now</div>
</div>
<div
className={`${style.button} border border-[#151c22] bg-[#363840] hover:bg-[#4c505c]`}
>
<HiTag className={style.buttonIcon} />
<div className={style.buttonText}>Make Offer</div>
</div>
</>
) : (
<div className={`${style.button} bg-[#2081e2] hover:bg-[#42a0ff]`}>
<IoMdWallet className={style.buttonIcon} />
<div className={style.buttonText}>List Item</div>
</div>
)}
</div>
)
}
export default MakeOffer

Markdown text editor code, table, list not working properly

I want to write my blog post with markdown editor, my problem is when I publish my post edit with markdown then code block, list item, table, and so on not working properly, another part is works file like image, link, text bold...
looks like:
And output is:
I have tried code by this way:
posts.js file
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import { sortByDate } from '#/utils/index'
const files = fs.readdirSync(path.join('posts'))
export function getPosts() {
const posts = files.map((filename) => {
const slug = filename.replace('.md', '')
const markdownWithMeta = fs.readFileSync(
path.join('posts', filename),
'utf-8'
)
const { data: frontmatter } = matter(markdownWithMeta)
return {
slug,
frontmatter,
}
})
return posts.sort(sortByDate)
}
[slug.js] file:
import fs from 'fs'
import path from 'path'
import matter from 'gray-matter'
import marked from 'marked'
import Link from 'next/link'
import Layout from '#/components/Layout'
import CategoryLabel from '#/components/CategoryLabel'
export default function PostPage({
frontmatter: { title, category, date, cover_image, author, author_image },
content,
slug,
}) {
return (
<Layout title={title}>
<Link href='/blog'>Go Back</Link>
<div className='w-full px-10 py-6 bg-white rounded-lg shadow-md mt-6 md:grid-cols-6'>
<div className='flex justify-between items-center mt-4'>
<h1 className='text-5xl mb-7'>{title}</h1>
<CategoryLabel>{category}</CategoryLabel>
</div>
<img src={cover_image} alt='' className='w-full rounded' />
<div className='flex justify-between items-center bg-gray-100 p-2 my-8'>
<div className='flex items-center'>
<img
src={author_image}
alt=''
className='mx-4 w-10 h-10 object-cover rounded-full hidden sm:block'
/>
<h4>{author}</h4>
</div>
<div className='mr-4'>{date}</div>
</div>
<div className='blog-text mt-2'>
<div dangerouslySetInnerHTML={{ __html: marked(content) }}></div>
</div>
</div>
</Layout>
)
}
export async function getStaticPaths() {
const files = fs.readdirSync(path.join('posts'))
const paths = files.map((filename) => ({
params: {
slug: filename.replace('.md', ''),
},
}))
return {
paths,
fallback: false,
}
}
export async function getStaticProps({ params: { slug } }) {
const markdownWithMeta = fs.readFileSync(
path.join('posts', slug + '.md'),
'utf-8'
)
const { data: frontmatter, content } = matter(markdownWithMeta)
return {
props: {
frontmatter,
content,
slug,
},
}
}
Any suggestion please.
See: https://nextjs.org/blog/markdown
You need to setup: https://github.com/tailwindlabs/tailwindcss-typography
Then add the prose class to your div that contains the markdown
<div className='blog-text prose mt-2'>
<div dangerouslySetInnerHTML={{ __html: marked(content) }}></div>
</div>

Categories