diff --git a/plugins/remark-smartypants.js b/plugins/remark-smartypants.js index 7dd1b0c4a..4694ff674 100644 --- a/plugins/remark-smartypants.js +++ b/plugins/remark-smartypants.js @@ -1,3 +1,8 @@ +/*! + * Based on 'silvenon/remark-smartypants' + * https://github.com/silvenon/remark-smartypants/pull/80 + */ + const visit = require('unist-util-visit'); const retext = require('retext'); const smartypants = require('retext-smartypants'); @@ -9,12 +14,48 @@ function check(parent) { } module.exports = function (options) { - const processor = retext().use(smartypants, options); + const processor = retext().use(smartypants, { + ...options, + // Do not replace ellipses, dashes, backticks because they change string + // length, and we couldn't guarantee right splice of text in second visit of + // tree + ellipses: false, + dashes: false, + backticks: false, + }); + + const processor2 = retext().use(smartypants, { + ...options, + // Do not replace quotes because they are already replaced in the first + // processor + quotes: false, + }); function transformer(tree) { - visit(tree, 'text', (node, index, parent) => { - if (check(parent)) node.value = String(processor.processSync(node.value)); + let allText = ''; + let startIndex = 0; + const textOrInlineCodeNodes = []; + + visit(tree, ['text', 'inlineCode'], (node, _, parent) => { + if (check(parent)) { + if (node.type === 'text') allText += node.value; + // for the case when inlineCode contains just one part of quote: `foo'bar` + else allText += 'A'.repeat(node.value.length); + textOrInlineCodeNodes.push(node); + } }); + + // Concat all text into one string, to properly replace quotes around non-"text" nodes + allText = String(processor.processSync(allText)); + + for (const node of textOrInlineCodeNodes) { + const endIndex = startIndex + node.value.length; + if (node.type === 'text') { + const processedText = allText.slice(startIndex, endIndex); + node.value = String(processor2.processSync(processedText)); + } + startIndex = endIndex; + } } return transformer; diff --git a/src/components/Layout/HomeContent.js b/src/components/Layout/HomeContent.js index 02338b1c5..e1fab6d71 100644 --- a/src/components/Layout/HomeContent.js +++ b/src/components/Layout/HomeContent.js @@ -1499,7 +1499,7 @@ function ConferenceLayout({conf, children}) { navigate(e.target.value); }); }} - className="appearance-none pe-8 bg-transparent text-primary-dark text-2xl font-bold mb-0.5" + className="appearance-none pe-8 ps-2 bg-transparent text-primary-dark text-2xl font-bold mb-0.5" style={{ backgroundSize: '4px 4px, 4px 4px', backgroundRepeat: 'no-repeat', @@ -1508,8 +1508,16 @@ function ConferenceLayout({conf, children}) { backgroundImage: 'linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%)', }}> - - + +
diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md index 3697ad2cf..338afcc30 100644 --- a/src/content/reference/react/use-server.md +++ b/src/content/reference/react/use-server.md @@ -153,7 +153,7 @@ export default async function requestUsername(formData) { // UsernameForm.js 'use client'; -import {useFormState} from 'react-dom'; +import { useFormState } from 'react-dom'; import requestUsername from './requestUsername'; function UsernameForm() { diff --git a/src/utils/prepareMDX.js b/src/utils/prepareMDX.js index 639d7db90..20a22577d 100644 --- a/src/utils/prepareMDX.js +++ b/src/utils/prepareMDX.js @@ -7,7 +7,7 @@ import {Children} from 'react'; // TODO: This logic could be in MDX plugins instead. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -export const PREPARE_MDX_CACHE_BREAKER = 2; +export const PREPARE_MDX_CACHE_BREAKER = 3; // !!! IMPORTANT !!! Bump this if you change any logic. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~