diff --git a/src/components/universal/Markdown/renderers/image.tsx b/src/components/universal/Markdown/renderers/image.tsx
index 88ecb85c2..4e30e7b1f 100644
--- a/src/components/universal/Markdown/renderers/image.tsx
+++ b/src/components/universal/Markdown/renderers/image.tsx
@@ -1,3 +1,4 @@
+import { sanitizeUrl } from 'markdown-to-jsx'
import { reaction } from 'mobx'
import { observer } from 'mobx-react-lite'
import type { FC } from 'react'
@@ -107,10 +108,11 @@ export const MImage: FC<
>
> = (props) => {
const { src, alt } = props
+ const sanitizedUrl = sanitizeUrl(src!)
const isClient = useIsClient()
return !isClient ? (
-
+
) : (
- <_Image src={src!} alt={alt} />
+ <_Image src={sanitizedUrl!} alt={alt} />
)
}
diff --git a/src/components/widgets/Toc/index.tsx b/src/components/widgets/Toc/index.tsx
index afdaf356b..499240e0c 100644
--- a/src/components/widgets/Toc/index.tsx
+++ b/src/components/widgets/Toc/index.tsx
@@ -4,10 +4,10 @@ import type { FC } from 'react'
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { TransitionGroup } from 'react-transition-group'
+import { RightLeftTransitionView } from '~/components/universal/Transition/right-left'
import { CustomEventTypes } from '~/types/events'
import { eventBus } from '~/utils/event-emitter'
-import { RightLeftTransitionView } from '../../universal/Transition/right-left'
import styles from './index.module.css'
import { TocItem } from './item'
@@ -17,10 +17,15 @@ export type TocProps = {
useAsWeight?: boolean
}
+type Headings = {
+ depth: number
+ index: number
+ title: string
+}[]
export const Toc: FC = memo(
({ headings: $headings, useAsWeight }) => {
const containerRef = useRef(null)
- const headings = useMemo(() => {
+ const headings: Headings = useMemo(() => {
return Array.from($headings).map((el) => {
const depth = +el.tagName.slice(1)
const title = el.id || el.textContent || ''
@@ -69,6 +74,17 @@ export const Toc: FC = memo(
}, 350)
}, [])
+ const rootDepth = useMemo(
+ () =>
+ headings?.length
+ ? (headings.reduce(
+ (d: number, cur) => Math.min(d, cur.depth),
+ headings[0]?.depth || 0,
+ ) as any as number)
+ : 0,
+ [headings],
+ )
+
return (
= memo(
>
{headings &&
- headings.map((heading, i) => {
+ headings.map((heading) => {
return (
-
- Math.min(d, cur.depth),
- headings[0].depth,
- ) as any as number
- }
- />
-
+
)
})}
@@ -112,3 +116,47 @@ export const Toc: FC = memo(
)
},
)
+const MemoedItem = memo<{
+ isActive: boolean
+ heading: Headings[0]
+ rootDepth: number
+ onClick: (i: number) => void
+}>(
+ (props) => {
+ const { heading, isActive, onClick, rootDepth } = props
+
+ return (
+
+
+
+ )
+ },
+ (a, b) => {
+ // FUCK react transition group alway inject onExited props into Child element, but this props alway change, so ignore it.
+
+ return (
+ a.heading === b.heading &&
+ a.isActive === b.isActive &&
+ a.onClick === b.onClick &&
+ a.rootDepth === b.rootDepth
+ )
+ },
+)
+
+MemoedItem.displayName = 'MemoedItem'