jackyzha0 / quartz

🌱 a fast, batteries-included static-site generator that transforms Markdown content into fully functional websites
https://quartz.jzhao.xyz
MIT License
7.13k stars 2.51k forks source link

Support \(\) math delimiters #1046

Open thangisme opened 7 months ago

thangisme commented 7 months ago

Is your feature request related to a problem? Please describe. No

Describe the solution you'd like Able to config delimiters like this snippets on official Katex site:


    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });```
thangisme commented 7 months ago

Also, I'm doing migration from another CMS to this. I exported raw html content to add to markdown. While normal math block is parsed correctly, math block inside html tag isnt parsed. For example

$f(x)$
<p>$f(x)$</p>

will display as $f(x)$

`$f(x)$

saberzero1 commented 7 months ago

Sounds like you're trying to render mathjax instead of katex.

Can you update the renderEngine in the below line in your quartz.config.ts from "katex" to "mathjax" and see if that resolves this issue?

https://github.com/jackyzha0/quartz/blob/5ec61468d5e787b3c8ae32a2b4ef1595cf0bc3ee/quartz.config.ts#L59

thangisme commented 7 months ago

Sounds like you're trying to render mathjax instead of katex.

Can you update the renderEngine in the below line in your quartz.config.ts from "katex" to "mathjax" and see if that resolves this issue?

https://github.com/jackyzha0/quartz/blob/5ec61468d5e787b3c8ae32a2b4ef1595cf0bc3ee/quartz.config.ts#L59

Unfortunately it doesn. \(f(x)\) is escaped so only (f(x)) is display. \\(f(x)\\) turns into \(f(x)\) without being rendered

saberzero1 commented 7 months ago

Sounds like you're trying to render mathjax instead of katex. Can you update the renderEngine in the below line in your quartz.config.ts from "katex" to "mathjax" and see if that resolves this issue? https://github.com/jackyzha0/quartz/blob/5ec61468d5e787b3c8ae32a2b4ef1595cf0bc3ee/quartz.config.ts#L59

Unfortunately it doesn. \(f(x)\) is escaped so only (f(x)) is display. \\(f(x)\\) turns into \(f(x)\) without being rendered

If you want \\( or \\) in the result, you must escape the double backslash. So if you want \\(f(x)\\), you need to write \\\\(f(x)\\\\).

Can you please post the source markdown you're trying to convert so I can better assist you?

thangisme commented 7 months ago

Can you please post the source markdown you're trying to convert so I can better assist you?

Nothing much, just

---
title: "Sample"
---

\(\Delta\)
\\(f(x)\\)
\\\\(f(x)\\\\)

$\Delta$

image

saberzero1 commented 7 months ago

I looked into the script you're referring. I assume you mean this script:

https://katex.org/docs/autorender

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
</script>

You could include the eventlistener part inside the <head>.

<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
</script>

https://github.com/jackyzha0/quartz/blob/dd82ab8d796c37249098a5b4dd11d55ad2dd88d8/quartz/components/Head.tsx#L22-L47

You could include this part as external resources inside quartz/plugins/transformers/latex.ts.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>

Please note that I'm not sure if the external scripts load before the eventlistener part, which seems to be required. In that case, you might want to include all into the <head> to see if that works.

If that works, we could look into adapting quartz/plugins/transformers/latex.ts to better suit your specific needs.

Please notes that using the dollar-sign $ for inline-math is supported by default. https://quartz.jzhao.xyz/features/Latex#inline-math

thangisme commented 7 months ago

I looked into the script you're referring. I assume you mean this script:

https://katex.org/docs/autorender

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>
<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
</script>

You could include the eventlistener part inside the <head>.

<script>
    document.addEventListener("DOMContentLoaded", function() {
        renderMathInElement(document.body, {
          // customised options
          // • auto-render specific keys, e.g.:
          delimiters: [
              {left: '$$', right: '$$', display: true},
              {left: '$', right: '$', display: false},
              {left: '\\(', right: '\\)', display: false},
              {left: '\\[', right: '\\]', display: true}
          ],
          // • rendering keys, e.g.:
          throwOnError : false
        });
    });
</script>

https://github.com/jackyzha0/quartz/blob/dd82ab8d796c37249098a5b4dd11d55ad2dd88d8/quartz/components/Head.tsx#L22-L47

You could include this part as external resources inside quartz/plugins/transformers/latex.ts.

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>

Please note that I'm not sure if the external scripts load before the eventlistener part, which seems to be required. In that case, you might want to include all into the <head> to see if that works.

If that works, we could look into adapting quartz/plugins/transformers/latex.ts to better suit your specific needs.

Please notes that using the dollar-sign $ for inline-math is supported by default. https://quartz.jzhao.xyz/features/Latex#inline-math

The following code works

import { createElement } from 'react';

export default (() => {
  const Head: QuartzComponent = ({ cfg, fileData, externalResources }: QuartzComponentProps) => {
    // ... (existing code)

    const customScriptContent = `
      document.addEventListener("DOMContentLoaded", function() {
          renderMathInElement(document.body, {
            // customised options
            delimiters: [
                {left: '$$', right: '$$', display: true},
                {left: '$', right: '$', display: false},
                {left: '\\(', right: '\\)', display: false},
                {left: '\\[', right: '\\]', display: true}
            ],
            throwOnError : false
          });
      });
    `;

    const customScriptElement = createElement('script', {
      dangerouslySetInnerHTML: { __html: customScriptContent }
    });

    return (
      <head>
        {/* ... (existing JSX elements) */}

        {css.map((href) => (
          <link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />
        ))}
        {js
          .filter((resource) => resource.loadTime === "beforeDOMReady")
          .map((res) => JSResourceToScriptElement(res, true))}

        {/* KaTeX CSS */}
        <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.css" integrity="sha384-wcIxkf4k558AjM3Yz3BBFQUbk/zgIYC2R0QpeeYb+TwlBVMrlgLqwRjRtGZiK7ww" crossorigin="anonymous" />

        {/* KaTeX Scripts */}
        <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/katex.min.js" integrity="sha384-hIoBPJpTUs74ddyc4bFZSM1TVlQDA60VBbJS0oA934VSz82sBx1X7kSx2ATBDIyd" crossorigin="anonymous"></script>
        <script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.10/dist/contrib/auto-render.min.js" integrity="sha384-43gviWU0YVjaDtb/GhzOouOXtZMP/7XUzwPTstBeZFe/+rCMvRwr4yROQP43s0Xk" crossorigin="anonymous"></script>

        {/* Custom Math Rendering Script */}
        {customScriptElement}
      </head>
    )
  }

  return Head
}) satisfies QuartzComponentConstructor

So it seems that the default latex is already rendered when building the website, isnt it? Other SSG theme mostly render math client-side