Skip to content

Instantly share code, notes, and snippets.

@noxify
Created September 19, 2022 08:39
Show Gist options
  • Save noxify/c7e4933b46f22131195f709766055854 to your computer and use it in GitHub Desktop.
Save noxify/c7e4933b46f22131195f709766055854 to your computer and use it in GitHub Desktop.
custom image for tailwind ui syntax template

project structure


- /
  - src/
    - pages/
      - docs/
        - doc1.md
        - doc2.md
  - public/
    - images/
      - some_dir/
        - image1.png
        - image2.png

Usage

// doc1.md

---
title: Markdoc example
description: Markdoc syntax examples
---

# Hello Tailwind UI 

![Images](/images/some_dir/image1.png)

How does it work

While working locally, the generatePath function returns always an empty object, because the environment variable CI isn't set. So the file path is always something like /images/some_dir/image1.png.

While building the static page via a CI/CD pipeline ( in this case, we're using GitLab Pages ), the environment variable CI is set to true.

Based on this, we fetch the project path ( via CI_PROJECT_PATH ) and remove the group name from the path.

We only need the subfolder name ( if you have one ) and the repository name.

We have to prepend the path to the given image path.

The result path after building the site will be something like:

/some-directory/repository-name/images/some_dir/image1.png

Why do we need this?

NextJS provides some config parameters to modify the asset/base path - But unfortunately this works only for images with a static path.

Since we have a dynamic path, the configured assetPath will not be prepended automatically.

// src/components/CustomImage.tsx
import Image from 'next/image'
import 'yet-another-react-lightbox/styles.css'
import Lightbox from 'yet-another-react-lightbox'
import { useState } from 'react'
/**
* Generates the correct asset and base path
* for the gitlab pages
*
* @returns Object
*/
const generatePath = () => {
if (process.env.NEXT_PUBLIC_CI !== "true") return {}
/**
* convert path string to array
* input: gitlab-group-name/some-directory/repository-name
* output: [
* 'gitlab-group-name',
* 'some-directory',
* 'repository-name'
* ]
*/
//@ts-ignore
let splittedPath = process.env.NEXT_PUBLIC_PROJECT_PATH.split("/")
// remove the namespace ( => gitab-group-name)
splittedPath.shift()
// return the updated path as string
return {
assetPrefix: `/${splittedPath.join("/")}`,
basePath: `/${splittedPath.join("/")}`,
}
}
const CustomImage = ({
src,
alt,
width = 300,
height = 300,
}: {
src: string
alt: string
width?: number
height?: number
}) => {
const [open, setOpen] = useState(false)
const basePath = generatePath().basePath || ''
return (
<div className="w-full py-4 text-center">
<div className="relative h-96 w-full">
<Image src={`${basePath}${src}`} alt={alt} layout="fill" objectFit="contain" onClick={() => setOpen(true)} />
</div>
<Lightbox
open={open}
close={() => setOpen(false)}
slides={[{ src: `${basePath}${src}` }]}
render={{
slide: (image) => {
return (
<div className="relative h-4/6 w-full">
<Image
//@ts-ignore
src={image}
layout="fill"
loading="eager"
objectFit="contain"
alt={'alt' in image ? image.alt : ''}
/>
</div>
)
},
}}
/>
</div>
)
}
export default CustomImage
const withMarkdoc = require('@markdoc/next.js')
/**
* Generates the correct asset and base path
* for the gitlab pages
*
* @returns Object
*/
const generatePath = () => {
if (process.env.CI !== 'true') return {}
/**
* convert path string to array
* input: gitlab-group-name/some-directory/repository-name
* output: [
* 'gitlab-group-name',
* 'some-directory',
* 'repository-name'
* ]
*/
//@ts-ignore
let splittedPath = process.env.CI_PROJECT_PATH.split('/')
// remove the namespace ( => gitlab-group-name)
splittedPath.shift()
// return the updated path as string
return {
assetPrefix: `/${splittedPath.join('/')}`,
basePath: `/${splittedPath.join('/')}`,
}
}
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
pageExtensions: [ 'js', 'jsx', 'md', 'ts', 'tsx' ],
experimental: {
newNextLinkBehavior: true,
scrollRestoration: true,
},
images: {
unoptimized: true,
loader: 'custom',
},
...generatePath(),
env: {
// make the GitLab variables available in client side rendering
// to replace the url for the images
'NEXT_PUBLIC_CI': process.env.CI,
'NEXT_PUBLIC_PROJECT_PATH': process.env.CI_PROJECT_PATH
}
}
module.exports = withMarkdoc()(nextConfig)
// markdoc/nodes.js
import { Fence } from 'src/components/Fence'
import { nodes as defaultNodes, Tag } from '@markdoc/markdoc'
import CustomImage from 'src/components/CustomImage'
const nodes = {
document: {
render: undefined,
},
th: {
...defaultNodes.th,
attributes: {
...defaultNodes.th.attributes,
scope: {
type: String,
default: 'col',
},
},
},
fence: {
render: Fence,
attributes: {
language: {
type: String,
},
},
},
image: {
...defaultNodes.image,
render: CustomImage,
},
paragraph: {
...defaultNodes.paragraph,
transform: (node, config) => {
const attributes = node.transformAttributes(config)
const children = node.transformChildren(config)
// hack to make rendering block tags work correctly. They shouldn't be wrapped in a p tag.
if (children.length === 1 && children[ 0 ] instanceof Tag) {
return children
}
return new Tag('p', attributes, children)
},
}
}
export default nodes
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment