ChristopherBiscardi / gatsby-mdx

Gatsby+MDX • Transformers, CMS UI Extensions, and Ecosystem Components for ambitious projects
https://gatsby-mdx.netlify.com/
715 stars 100 forks source link

Question: How can I wrap some (nested?) MDX to style it? #345

Closed rchrdnsh closed 5 years ago

rchrdnsh commented 5 years ago

Hi, I'm trying to style the content of an article component that I am making that is fed MDX content, but I'm running into an issue. I have a Nav, a TOC, and an MDX content section on the page at the same time. The TOC and the MDX content are both wrapped with an MDXProvider, so as to make the TOC work properly, creating hash routes to headings in the MDX content. I now want to wrap only the MDX content section and style that with some other goodies, but I cannot figure out how to do that. I tried using another MDXProvider to wrap around the MDX content itself, which worked fine on it's own, but broke the TOC's functionality, so I'm assuming that one cannot next MDXProviders, is this correct?

Anyway, if anybody has any thoughts on this, it would be much appreciated, thank you :-)

ChristopherBiscardi commented 5 years ago

Hey @rchrdnsh it's a bit hard to parse what you're referring to here. Can you make a small repo or code example maybe to describe what's going on?

rchrdnsh commented 5 years ago

apologies, yes...

I want to achieve different widths on different content blocks in the content section of the page, like so:

Example for Chris

But my approach was to use nested MDXProviders, which did not seem to work, so I'm not sure how to go about doing this. This is a article component that is controlling the TOC and the article content, but the navigation on the left most side:

export default ({ data }) => {
  const { frontmatter, code, tableOfContents } = data.mdx
  return (
    <Fragment>
      <MDXProvider components={toc}>
        <TOC>
          {tableOfContents && <ul>{tableOfContents.items.map(renderItem)}</ul>}
        </TOC>
        <Article>
          <TitleCard>
            <TitleText>
              <Title>{frontmatter.title}</Title>
              <Subtitle>{frontmatter.subtitle}</Subtitle>
            </TitleText>
          </TitleCard>
          <TitleImage fluid={frontmatter.image.childImageSharp.fluid} alt="cool stuff." />
          <TitleScrim />
          <Content>
            <MDXRenderer>{code.body}</MDXRenderer>
          </Content>
        </Article>
      </MDXProvider>
    </Fragment>
  )
}

And I was wanting to import react components into the content section and have them be different widths via props or something, but I can't even figure out how to make the main markdown text be padded in a little bit. Just not sure how to go about this with styling and all. I'm currently using styled components but I am not averse to emotion either, if it can offer something to help out :-)

johno commented 5 years ago

You should be able to use the wrapper to apply padding to MDX rendered by MDXRenderer. This will be the component used to wrap all MDX docs within that MDXProvider.

const CustomWrapper = props => <div {...props} style={{ padding: '20px' }}>

export default ({ data }) => {
  const { frontmatter, code, tableOfContents } = data.mdx
  return (
    <Fragment>
      <MDXProvider components={{ ...toc, wrapper: CustomWrapper }}>
         // ...

You can also use the styled function to add the styling you'd like (assuming it's passed to the provider still):

const CustomWrapper = styled.div`
  color: tomato;
  padding: 20px;
`

Hope this helps!

CanRau commented 5 years ago

What do you mean by other goodies? Just styling the <Article /> component or wrapping it in another component won't do it?

rchrdnsh commented 5 years ago

hmmmm, apologies @ChristopherBiscardi @johno and @CanRau , I think I explained my desires poorly. Using your approach @johno every block of content gets padding, not some blocks of content. So, to be more precise, what I think I'm trying to do is have react components of content inline with my markdown content be full width of the content container, while the markdown itself is not full width. I'm trying to implement the CSS Grid approached touched on by Tyler Sticka:

https://cloudfour.com/thinks/breaking-out-with-css-grid-layout/

...and Dave Geddes:

https://gedd.ski/post/article-grid-layout/

where each block of content can be either full width or centered with spacing using CSS Grid. I have a working implementation inside a Vue app using plain CSS here:

https://rykr.co/practice

Where the title card is full bleed (easy enough) but then the basic written content (headers, paragraphs, etc...) is padded using CSS Grid and the practice schedules are full bleed using CSS Grid, even though they are inline with the basic written content, as evidenced in the image below:

Screenshot 2019-04-16 15 21 49

So in an example markdown file I would have react components inline in my MDX doc where the regular markdown is padded but the custom react components are not.

# Phases of the mind

We will develop our memories in phases, as it would be impossible to practice everything that we need to practice, all at once. Much in the same way that you would not go to the gym to bench press one thousand pounds once, we will venture to break everything down into small, bite sized chunks, which will allow us the time and mental rest that we need to maintain our practice schedule over a long period of time, and avoid burning out after only a few sessions.

<PracticeSchedule />

# Phase 1

In phase one we will introduce ourselves to the process and methodology of our practice program with the most fundamental information possible. This may be a good phase to repeat a few times until we feel completely comfortable with all of the information contained within. After we complete phase 1 then each subsequent phase will become both more challenging, and also more musical, as this is a vital component to becoming a more fluent and natural musician.

Where the headings and paragraphs are centered and the practice schedule component in full width, but inline with the other basic content inside the mdx document.

So the custom wrapper seems to wrap all the content, not some pieces of content and not others, which I think is more what I am trying to achieve. If that can be done somehow that would be super awesome, I just can't think through how to do this in react/gatsby/mdx...🤔

CanRau commented 5 years ago

Aaah okay, I think I get it now. I'm doing the same in GaiAma.org's blog I have a rule setting the max-width of all direct children of my wrapper in my case

.css-x0b1md > div > * {
  max-width: 80ch;
}

then setting the .inline-gallery's to 100%

.css-x0b1md .inline-gallery {
    max-width: 100%;
}

there's probably other solutions, that's what I came up with :wink:

Hope I got your problem and could be of any help?!

Kay just read you're comment a little more conscious, yea that grid solutions looks pretty neat maybe I'll adopt it 😎

Okay I just threw this stripped down version together and am not even sure if it works, can't test right now..

const PracticeSchedule = () => {
  <div styles={{
    grid-column: full,
  }}>
    Your Full Width Content
  </div>
}

export default ({ data }) => {
  const { frontmatter, code, tableOfContents } = data.mdx
  return (
    <Fragment>
      <MDXProvider components={toc, PracticeSchedule}>
        <TOC />
        <Article>
          <TitleCard />
          <TitleImage />
          <TitleScrim />
          <Content>
            <MDXRenderer>{code.body}</MDXRenderer>
          </Content>
        </Article>
      </MDXProvider>
    </Fragment>
  )
}

~~might be that I'm misunderstanding MDXProdivers components? If not globalScope should do it or you "just" add a className to PracticeSchedule and style it in the <Article /> component similar to my example~~

Shouldn't it work to just add the grid-column css to your existing PracticeSchedule declaration?

Kay I'm pretty tired, not able to clean this post up, hope it's understandable. Let me/us know if you have any questions..

ChristopherBiscardi commented 5 years ago

In MDX 1.0 you can use MDXProvider to replace the custom component. So you can use it like a shortcode without importing it:

const components = {
  PracticeSchedule: props => (
    <PracticeSchedule
      {...props}
      css={{
        gridColumn: "full"
      }}
    />
  )
};

<MDXProvider components={components}>
  {restOfApp}
</MDXProvider>

and then in some MDX content later in the tree PracticeSchedule is replaced by a PracticeSchedule with the additional styles. This way you define the components you're going to have be full width all in the same place.

# Phases of the mind

We will develop our memories in phases, as it would be impossible to practice everything that we need to practice, all at once. Much in the same way that you would not go to the gym to bench press one thousand pounds once, we will venture to break everything down into small, bite sized chunks, which will allow us the time and mental rest that we need to maintain our practice schedule over a long period of time, and avoid burning out after only a few sessions.

<PracticeSchedule />

# Phase 1

In phase one we will introduce ourselves to the process and methodology of our practice program with the most fundamental information possible. This may be a good phase to repeat a few times until we feel completely comfortable with all of the information contained within. After we complete phase 1 then each subsequent phase will become both more challenging, and also more musical, as this is a vital component to becoming a more fluent and natural musician.