diff --git a/framework/commerce/api/operations.ts b/framework/commerce/api/operations.ts index 898c322e3..34a549f2c 100644 --- a/framework/commerce/api/operations.ts +++ b/framework/commerce/api/operations.ts @@ -11,8 +11,12 @@ import type { } from '../types/product' import type { GetAllBlogsOperation, - GetFeaturedOperation + GetFeaturedOperation, + GetAllBlogPathsOperation, + GetBlogDetailOperation, + GetRelevantBlogsOperation } from '../types/blogs' + import type { APIProvider, CommerceAPI } from '.' import { GetAllCollectionsOperation } from '@commerce/types/collection'; @@ -32,7 +36,10 @@ export const OPERATIONS = [ 'getAllFacets', 'getAllCollections', 'getAllBlogs', - 'getFeaturedBlog' + 'getFeaturedBlog', + 'getAllBlogPaths', + 'getBlogDetail', + 'getRelevantBlogs' ] as const export const defaultOperations = OPERATIONS.reduce((ops, k) => { @@ -133,6 +140,21 @@ export type Operations

= { ): Promise } + + getAllBlogPaths: { + (opts: { + variables?: T['variables'] + config?: P['config'] + }): Promise + + ( + opts: { + variables?: T['variables'] + config?: P['config'] + } & OperationOptions + ): Promise + } + getAllProducts: { (opts: { variables?: T['variables'] @@ -166,6 +188,22 @@ export type Operations

= { ): Promise } + getRelevantBlogs: { + (opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + }): Promise + + ( + opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + } & OperationOptions + ): Promise + } + getFeaturedBlog: { (opts: { variables?: T['variables'] @@ -182,6 +220,21 @@ export type Operations

= { ): Promise } + getBlogDetail: { + (opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + }): Promise + + ( + opts: { + variables?: T['variables'] + config?: P['config'] + preview?: boolean + } & OperationOptions + ): Promise + } getProduct: { diff --git a/framework/commerce/types/blogs.ts b/framework/commerce/types/blogs.ts index 9b6ce14c1..485388012 100644 --- a/framework/commerce/types/blogs.ts +++ b/framework/commerce/types/blogs.ts @@ -1,4 +1,4 @@ -import { SearchResultSortParameter } from "@framework/schema"; + import { Asset, BlogTranslation, Maybe, Product } from './../../vendure/schema.d'; export type BlogList = Node &{ @@ -15,13 +15,27 @@ export type BlogsType = { totalItems: number } export type GetAllBlogsOperation = { - data: { items: T['items'][] } + data: { items: T['items'][], totalItems: number } + variables: { + productId: number, + take?: number + skip?: number + } +} +export type GetRelevantBlogsOperation = { + data: { items: T['items'][], totalItems: number } variables: { take?: number skip?: number } } +export type GetBlogDetailOperation = { + data: T['items'], + variables: { + slug?: string + } +} export type GetFeaturedOperation = { data: { items: T['items'][] } @@ -29,4 +43,10 @@ export type GetFeaturedOperation = { take?: number skip?: number } -} \ No newline at end of file +} +export type GetAllBlogPathsOperation< +T extends BlogsType = BlogsType +> = { + data: { blogs: Pick[] } + variables: { first?: number } +} diff --git a/framework/commerce/types/product.ts b/framework/commerce/types/product.ts index e31f34df9..421100581 100644 --- a/framework/commerce/types/product.ts +++ b/framework/commerce/types/product.ts @@ -1,3 +1,4 @@ +import { BlogsType } from './blogs'; import { CurrencyCode } from './../../vendure/schema.d'; import { FacetValueFilterInput, LogicalOperator, SearchResultSortParameter } from "@framework/schema" @@ -110,6 +111,8 @@ export type GetAllProductPathsOperation< variables: { first?: number } } + + export type GetAllProductsOperation = { data: { products: T['product'][] } variables: { diff --git a/framework/vendure/api/index.ts b/framework/vendure/api/index.ts index edf67d14f..384f76b98 100644 --- a/framework/vendure/api/index.ts +++ b/framework/vendure/api/index.ts @@ -1,18 +1,21 @@ import type { CommerceAPIConfig } from '@commerce/api' import { CommerceAPI, getCommerceApi as commerceApi } from '@commerce/api' -import getAllFacets from './operations/get-all-facets' +import getAllBlogs from './operations/get-all-blogs' import getAllCollections from './operations/get-all-collection' +import getAllFacets from './operations/get-all-facets' import getAllPages from './operations/get-all-pages' import getAllProductPaths from './operations/get-all-product-paths' import getAllProducts from './operations/get-all-products' +import getBlogDetail from './operations/get-blog-detail' import getCustomerWishlist from './operations/get-customer-wishlist' +import getFeaturedBlog from './operations/get-featured-blog' import getPage from './operations/get-page' import getProduct from './operations/get-product' import getSiteInfo from './operations/get-site-info' +import getAllBlogPaths from './operations/get-all-blog-paths' +import getRelevantBlogs from './operations/get-relevant-blogs' import login from './operations/login' import fetchGraphqlApi from './utils/fetch-graphql-api' -import getAllBlogs from './operations/get-all-blogs' -import getFeaturedBlog from './operations/get-featured-blog' export interface VendureConfig extends CommerceAPIConfig {} @@ -46,7 +49,10 @@ const operations = { getAllFacets, getAllCollections, getAllBlogs, - getFeaturedBlog + getFeaturedBlog, + getBlogDetail, + getAllBlogPaths, + getRelevantBlogs } export const provider = { config, operations } diff --git a/framework/vendure/api/operations/get-all-blog-paths.ts b/framework/vendure/api/operations/get-all-blog-paths.ts new file mode 100644 index 000000000..cdfce36f7 --- /dev/null +++ b/framework/vendure/api/operations/get-all-blog-paths.ts @@ -0,0 +1,53 @@ +import { BlogList } from './../../schema.d'; +import { OperationContext,OperationOptions } from '@commerce/api/operations'; +import { BigcommerceConfig } from '../../../bigcommerce/api'; +import type { GetAllBlogPathsQuery,BlogTranslation } from '../../schema'; +import { getAllBlogPathsQuery } from '../../utils/queries/get-all-blog-paths-query'; +import { Provider } from '../index'; +import { GetAllBlogPathsOperation } from './../../../commerce/types/blogs'; + +export type GetAllBlogPathsResult = { + blogs: Array<{ node: { path: string } }> +} + +export default function getAllBlogPathsOperation({ + commerce, +}: OperationContext) { + async function getAllBlogPaths< + T extends GetAllBlogPathsOperation + >(opts?: { + variables?: T['variables'] + config?: BigcommerceConfig + }): Promise + + async function getAllBlogPaths( + opts: { + variables?: T['variables'] + config?: BigcommerceConfig + } & OperationOptions + ): Promise + + async function getAllBlogPaths({ + query = getAllBlogPathsQuery, + variables, + config: cfg, + }: { + query?: string + variables?: T['variables'] + config?: BigcommerceConfig + } = {}): Promise { + const config = commerce.getConfig(cfg) + + const { data } = await config.fetch(query, { + variables, + }) + + const blogs = data.blogs.items; + + return { + blogs: blogs?.map(val=>val.translations.map((p:BlogTranslation) => ({ path: `/${p.slug}` }))) + } + } + + return getAllBlogPaths +} diff --git a/framework/vendure/api/operations/get-blog-detail.ts b/framework/vendure/api/operations/get-blog-detail.ts new file mode 100644 index 000000000..6b8e92967 --- /dev/null +++ b/framework/vendure/api/operations/get-blog-detail.ts @@ -0,0 +1,55 @@ +import { OperationContext } from '@commerce/api/operations' +import { Provider, VendureConfig } from '..' +import { GetBlogQuery,BlogList } from '../../schema' +import { getBlogDetailQuery } from '../../utils/queries/get-blog-detail' + +export type BlogVariables = { + slug?: string, +} + +export default function getBlogDetailOperation({ + commerce, +}: OperationContext) { + async function getBlogDetail(opts?: { + variables?: BlogVariables + config?: Partial + preview?: boolean + }): Promise<{ blogDetail: BlogList}> + + async function getBlogDetail({ + query = getBlogDetailQuery, + variables: { ...vars } = {}, + config: cfg, + }: { + query?: string + variables?: BlogVariables + config?: Partial + preview?: boolean + } = {}): Promise<{ blogDetail: BlogList | any }> { + + const config = commerce.getConfig(cfg) + const variables = { + slug: vars.slug + } + const { data } = await config.fetch(query, { + variables, + }) + return { + blogDetail: { + id:data?.blog?.id, + title: data?.blog?.translations[0].title, + imageSrc: data?.blog?.featuredAsset?.preview ?? null, + slug: data?.blog?.translations[0]?.slug, + description: data?.blog?.translations[0]?.description, + isPublish: data?.blog?.isPublish, + isFeatured: data?.blog?.isFeatured, + authorName: data?.blog?.authorName, + authorAvatarAsset : data?.blog?.authorAvatarAsset?.preview, + createdAt: data?.blog?.createdAt, + relevantProducts: data?.blog?.relevantProducts.map(val=>val.id) + } + } + } + + return getBlogDetail +} diff --git a/framework/vendure/api/operations/get-relevant-blogs.ts b/framework/vendure/api/operations/get-relevant-blogs.ts new file mode 100644 index 000000000..3b9259c6a --- /dev/null +++ b/framework/vendure/api/operations/get-relevant-blogs.ts @@ -0,0 +1,54 @@ +import { OperationContext } from '@commerce/api/operations' +import { Provider, VendureConfig } from '..' +import { BlogList,GetRelevantBlogsQuery } from '../../schema' +import { getRelevantBlogsQuery } from '../../utils/queries/get-relevant-blogs' + +export type BlogVariables = { + productId?: number, +} + +export default function getRelevantBlogsOperation({ + commerce, +}: OperationContext) { + async function getRelevantBlogs(opts?: { + variables?: BlogVariables + config?: Partial + preview?: boolean + }): Promise<{ relevantBlogs: GetRelevantBlogsQuery[]}> + + async function getRelevantBlogs({ + query = getRelevantBlogsQuery, + variables: { ...vars } = {}, + config: cfg, + }: { + query?: string + variables?: BlogVariables + config?: Partial + preview?: boolean + } = {}): Promise<{ relevantBlogs: GetRelevantBlogsQuery[] | any[] }> { + + const config = commerce.getConfig(cfg) + const variables = { + productId: vars.productId, + } + const { data } = await config.fetch(query, { + variables, + }) + return { + relevantBlogs: data?.relevantBlogs?.items?.map((val:BlogList)=>({ + id: val.id, + title: val.translations[0]?.title, + imageSrc: val.featuredAsset?.preview ?? null, + slug: val.translations[0]?.slug, + description: val.translations[0]?.description, + isPublish: val.isPublish, + isFeatured: val.isFeatured, + authorName: val.authorName, + authorAvatarAsset : val.authorAvatarAsset?.preview, + createdAt: val.createdAt + })), + } + } + + return getRelevantBlogs +} diff --git a/framework/vendure/schema.d.ts b/framework/vendure/schema.d.ts index 542af51fb..ab827f870 100644 --- a/framework/vendure/schema.d.ts +++ b/framework/vendure/schema.d.ts @@ -2337,10 +2337,19 @@ export type BlogList = Node &{ translations: Array authorName: Scalars['String'] authorAvatarAsset:Asset - relevantProducts: Product + relevantProducts: Product[] isFeatured: Boolean } +export type GetBlogQuery = { __typename?: 'Query' } & { + blog?: Maybe< + { __typename?: 'Blog' } & BlogList + > +} + + + + export type BlogTranslation = { __typename?: 'BlogTranslation' id: Scalars['ID'] @@ -2359,6 +2368,13 @@ export type GetAllBlogsQuery = PaginatedList & { 'totalItems' } } + +export type GetRelevantBlogsQuery = PaginatedList & { + relevantBlogs: { __typename?: 'BlogList' } & { + items: Array<{ __typename?: 'Blog' } & BlogList!>, + } +} + export type GetFeaturedBlogQuery = PaginatedList & { id:string, featuredBlogs: { __typename?: 'BlogList' } & { @@ -2367,6 +2383,7 @@ export type GetFeaturedBlogQuery = PaginatedList & { } } + export type QueryBlogs = { excludeBlogIds:Array, options: BlogListOptions @@ -3339,6 +3356,12 @@ export type GetAllProductPathsQuery = { __typename?: 'Query' } & { items: Array<{ __typename?: 'Product' } & Pick> } } + +export type GetAllBlogPathsQuery = { __typename?: 'Query' } & { + blogs: { __typename?: 'BlogList' } & { + items: Array<{ __typename?: 'Blog' } & Pick> + } +} export type GetAllProductsQueryVariables = Exact<{ input: SearchInput diff --git a/framework/vendure/utils/queries/get-all-blog-paths-query.ts b/framework/vendure/utils/queries/get-all-blog-paths-query.ts new file mode 100644 index 000000000..69d89ca36 --- /dev/null +++ b/framework/vendure/utils/queries/get-all-blog-paths-query.ts @@ -0,0 +1,11 @@ +export const getAllBlogPathsQuery = /* GraphQL */ ` +query getAllBlogPaths($excludeBlogIds: [ID]! = [],$options:BlogListOptions){ + blogs(excludeBlogIds: $excludeBlogIds,options: $options){ + items{ + translations { + slug + } + } + } +} +` diff --git a/framework/vendure/utils/queries/get-blog-detail.ts b/framework/vendure/utils/queries/get-blog-detail.ts new file mode 100644 index 000000000..a8b8fbe53 --- /dev/null +++ b/framework/vendure/utils/queries/get-blog-detail.ts @@ -0,0 +1,26 @@ +export const getBlogDetailQuery = /* GraphQL */ ` +query getBlog($slug: String ){ + blog(slug: $slug){ + id + isPublish + isFeatured + authorName + createdAt + authorAvatarAsset{ + preview + } + featuredAsset { + preview + } + translations { + title + slug + description + content + } + relevantProducts{ + id + } + } + } +` \ No newline at end of file diff --git a/framework/vendure/utils/queries/get-relevant-blogs.ts b/framework/vendure/utils/queries/get-relevant-blogs.ts new file mode 100644 index 000000000..91c8ebe16 --- /dev/null +++ b/framework/vendure/utils/queries/get-relevant-blogs.ts @@ -0,0 +1,25 @@ +export const getRelevantBlogsQuery = /* GraphQL */ ` +query relevantBlogs($productId: ID!){ + relevantBlogs(productId:$productId){ + items { + id + isPublish + isFeatured + authorName + createdAt + authorAvatarAsset{ + preview + } + featuredAsset { + preview + } + translations { + title + slug + description + content + } + } + } +} +` diff --git a/pages/blog/[slug].tsx b/pages/blog/[slug].tsx index 8aaca04a9..f09e91375 100644 --- a/pages/blog/[slug].tsx +++ b/pages/blog/[slug].tsx @@ -2,16 +2,111 @@ import { Layout, RelevantBlogPosts } from 'src/components/common'; import BlogContent from 'src/components/modules/blog-detail/BlogContent/BlogContent'; import BlogDetailImg from 'src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg'; import { BLOGS_DATA_TEST } from 'src/utils/demo-data' +import { GetStaticPropsContext,GetStaticPathsContext } from 'next'; +import { PromiseWithKey } from 'src/utils/types.utils'; +import { getAllPromies } from 'src/utils/funtion.utils'; +import commerce from '@lib/api/commerce'; +import { BlogCardProps } from 'src/components/common/CardBlog/CardBlog'; +import { REVALIDATE_TIME } from 'src/utils/constanst.utils' +interface Props { + blog:{blogDetail?: BlogCardProps}, + relevantBlogs:{blogDetail?:BlogCardProps[]} +} +export default function BlogDetailPage({blog,relevantBlogs}:Props) { - -export default function BlogDetailPage() { + let date = new Date(blog?.blogDetail?.createdAt ?? '' ); + let fullDate = date.toLocaleString('en-us', { month: 'long' }) + " " + date.getDate()+","+date.getFullYear(); + return ( <> - - - + + + {relevantBlogs.relevantBlogs?.length> 0 && } ) } + +export async function getStaticProps({ + params, + locale, + locales, + preview, +}: GetStaticPropsContext<{ slug: string }> ) { + const config = { locale, locales } + let promisesWithKey = [] as PromiseWithKey[] + let props = {} as any + + // Blog detail + const blogDetailPromise = await commerce.getBlogDetail({ + variables: { slug: params!.slug }, + config, + preview, + }) + props.blog = blogDetailPromise; + + if (!blogDetailPromise) { + throw new Error(`Blog with slug '${params!.slug}' not found`) + } + + // Relevant Blogs + const relevantProductId = blogDetailPromise.blogDetail.relevantProducts?.[0]; + if (relevantProductId && blogDetailPromise.blogDetail.relevantProducts.length > 0) { + + const relevantBlogs = commerce.getRelevantBlogs({ + variables: { productId: relevantProductId }, + config, + preview, + }) + promisesWithKey.push({ key: 'relevantBlogs', promise: relevantBlogs}) + + }else { + props.relevantBlogs = []; + } + + + try { + const promises = getAllPromies(promisesWithKey) + const rs = await Promise.all(promises) + + promisesWithKey.map((item, index) => { + props[item.key] = item.keyResult ? rs[index][item.keyResult] : rs[index] + return null + }) + + console.log(props.relevantBlogs); + return { + props, + revalidate: REVALIDATE_TIME, + } + } catch (err) { + + } +} + +export async function getStaticPaths({ locales }: GetStaticPathsContext) { + + const { blogs } = await commerce.getAllBlogPaths() + + return { + paths: locales + ? locales.reduce((arr, locale) => { + blogs.forEach((blog: any) => { + arr.push(`/${locale}/blog/${blog.slug}`) + }) + return arr + }, []) + : blogs.map((product: any) => `/blog/${product.path}`), + fallback: 'blocking', + } +} + + + BlogDetailPage.Layout = Layout diff --git a/src/components/common/Author/Author.module.scss b/src/components/common/Author/Author.module.scss index 5a2dad969..037d988e7 100644 --- a/src/components/common/Author/Author.module.scss +++ b/src/components/common/Author/Author.module.scss @@ -5,7 +5,9 @@ .authorImage { width:3.2rem; height:3.2rem; - border-radius:3.2rem; + img{ + border-radius:3.2rem !important; + } div{ min-width:3.2rem !important; } diff --git a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx index ab21590c3..c99cd83ac 100644 --- a/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx +++ b/src/components/common/RelevantBlogPosts/RelevantBlogPosts.tsx @@ -14,40 +14,7 @@ interface RelevantProps { bgcolor?: "default" | "cream" } -const recipe:BlogCardProps[] = [ -{ - title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners", - slug: 'have-a-nice-lunch', - description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...", - imageSrc: "https://user-images.githubusercontent.com/46085455/133185783-8100ef4e-7a72-4dc1-bb12-2ca46b56b393.png", -},{ - title: "9 Ways to Make an Aloe Vera Mask at Home", - slug: 'have-a-nice-lunch', - description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...", - imageSrc: "https://user-images.githubusercontent.com/46085455/133185911-df505d10-fdcd-4312-add3-7c62ad8af71e.png", -},{ - title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit", - slug: 'have-a-nice-lunch', - description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...", - imageSrc: "https://user-images.githubusercontent.com/46085455/133185959-7ad75580-ca6d-4684-83d9-3f64500bbc97.png", -},{ - title: "Want to Lose Weight? Here are 10 DEBM Diet Guidelines for Beginners", - slug: 'have-a-nice-lunch', - description:"The DEBM diet stands for "+'"Delicious Happy Fun Diet"'+". This diet was popularized by Robert...", - imageSrc: "https://user-images.githubusercontent.com/46085455/133185783-8100ef4e-7a72-4dc1-bb12-2ca46b56b393.png", -},{ - title: "9 Ways to Make an Aloe Vera Mask at Home", - slug: 'have-a-nice-lunch', - description:"Aloe vera or aloe vera is a green plant, has thorns on the side of the skin with yellowish patches and...", - imageSrc: "https://user-images.githubusercontent.com/46085455/133185911-df505d10-fdcd-4312-add3-7c62ad8af71e.png", -},{ - title: "Don't Buy Wrong, Here Are 7 Ways to Choose a Ripe Dragon Fruit", - slug: 'have-a-nice-lunch', - description:"Dragon fruit is a type of fruit that is a favorite for many people because of its delicious and fresh...", - imageSrc: "https://user-images.githubusercontent.com/46085455/133185959-7ad75580-ca6d-4684-83d9-3f64500bbc97.png", -}] - - const RelevantBlogPosts = ({ data = recipe, itemKey="detail-relevant", title="Relevant Blog Posts", bgcolor = "default" }: RelevantProps) => { + const RelevantBlogPosts = ({ data , itemKey="detail-relevant", title="Relevant Blog Posts", bgcolor = "default" }: RelevantProps) => { return (

- + }
) diff --git a/src/components/modules/blog-detail/BlogContent/BlogContent.tsx b/src/components/modules/blog-detail/BlogContent/BlogContent.tsx index cb9d6b8d8..4a38ab5b1 100644 --- a/src/components/modules/blog-detail/BlogContent/BlogContent.tsx +++ b/src/components/modules/blog-detail/BlogContent/BlogContent.tsx @@ -9,57 +9,24 @@ import Link from 'next/link'; interface BlogContentProps { className?: string children?: any, + title?: string, + content?: string, + imgAuthor?: string, + date?: string, + authorName?: string, } -const BlogContent = ({}:BlogContentProps) => { +const BlogContent = ({title,date='',content,imgAuthor='',authorName='' }:BlogContentProps) => { + return ( <>
- -

The Best Sesame Soy Broccoli Salad

+ +

{title}

- +
- -

When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces. -
-
- - Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to. -
-
- This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing. -

- -
-
- -

What is broccoli salad

-
-

When you’re trying to eat healthier but want something more substantial than a leafy green salad, broccoli salad is there for you. I love the crunch and heft of broccoli, especially when it’s cut up into bite size spoonable pieces. -
-
- - Some people aren’t into raw broccoli, but I love it! I always go for the raw broccoli on those vegetable platters that seem to be at every potluck/party you go to. -
-
- This is a simple broccoli salad: you have the bulk of it, raw broccoli; crunchy red onions for a bit of acidity and raw crunch, craisins for sweetness, almonds for a nutty counter point; and a sweet and tangy soy-rice vinegar-sesame dressing. -

- -
-
- -

What about broccoli stems?

-
-

- You can eat broccoli stems. In fact, they are delicious. Just use a peeler to peel off the outsides and then trim the stalks into small 1/4”-1/2” cubes. -

-
- -
- -
- + {content}
diff --git a/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx b/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx index ed9b88a29..57180025a 100644 --- a/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx +++ b/src/components/modules/blog-detail/BlogDetailImg/BlogDetailImg.tsx @@ -5,7 +5,8 @@ import BreadcrumbCommon from 'src/components/common/BreadcrumbCommon/BreadcrumbC import s from './BlogDetailImg.module.scss'; interface Props { className?: string - children?: any + children?: any, + imgSrc?:string } const CRUMBS =[ @@ -14,14 +15,14 @@ const CRUMBS =[ link:"/blog" } ] -const BlogDetailImg = ({}:Props ) => { +const BlogDetailImg = ({imgSrc = ''}:Props ) => { return ( <>
- +
)