Markdown 语法
Markdown 语法在 GFM 中进行了其他扩展。
Alert
此语法是 GFM 的新增的。
> [!NOTE]
> Highlights information that users should take into account, even when skimming.
> [!IMPORTANT]
> Crucial information necessary for users to succeed.
> [!WARNING]
> Critical content demanding immediate user attention due to potential risks.
NoteHighlights information that users should take into account, even when skimming.
ImportantCrucial information necessary for users to succeed.
WarningCritical content demanding immediate user attention due to potential risks.
Notice
::: warning
_here be dragons_
:::
::: banner {error}
_here be dragons_
:::
::: banner {note}
_here be dragons_
:::
Rich Link
对于单独成行的链接,会有做出不用的渲染。
https://github.com/Innei/Shiro
https://twitter.com/zhizijun/status/1649822091234148352?s=20
https://twitter.com/zhizijun/status/1649822091234148352?s=20
https://www.youtube.com/watch?v=N93cTbtLCIM
https://gist.github.com/Innei/94b3e8f078d29e1820813a24a3d8b04e
https://gist.github.com/Innei/94b3e8f078d29e1820813a24a3d8b04e
https://github.com/vuejs/vitepress/commit/71eb11f72e60706a546b756dc3fd72d06e2ae4e2
https://github.com/vuejs/vitepress/commit/71eb11f72e60706a546b756dc3fd72d06e2ae4e2
https://codesandbox.io/s/framer-motion-layoutroot-prop-forked-p39g96
https://github.com/Innei/Shiro/blob/108d4c3e927e1c9c9304e41a0631f91958477d9f/src/providers/root/modal-stack-provider.tsx
'use client'
import * as Dialog from '@radix-ui/react-dialog'
import {
createElement,
memo,
useCallback,
useEffect,
useId,
useMemo,
useRef,
} from 'react'
import { AnimatePresence, m, useAnimationControls } from 'framer-motion'
import { atom, useAtomValue, useSetAtom } from 'jotai'
import { usePathname } from 'next/navigation'
import type { Target, Transition } from 'framer-motion'
import type { FC, PropsWithChildren, SyntheticEvent } from 'react'
import { CloseIcon } from '~/components/icons/close'
import { DialogOverlay } from '~/components/ui/dialog/DialogOverlay'
import { Divider } from '~/components/ui/divider'
import { microReboundPreset } from '~/constants/spring'
import { useEventCallback } from '~/hooks/common/use-event-callback'
import { useIsClient } from '~/hooks/common/use-is-client'
import { stopPropagation } from '~/lib/dom'
import { clsxm } from '~/lib/helper'
import { jotaiStore } from '~/lib/store'
const modalIdToPropsMap = {} as Record<string, ModalProps>
export type ModalContentComponent<T> = FC<ModalContentPropsInternal & T>
type ModalContentPropsInternal = {
dismiss: () => void
}
interface ModalProps {
title: string
content: FC<ModalContentPropsInternal>
CustomModalComponent?: FC<PropsWithChildren>
clickOutsideToDismiss?: boolean
modalClassName?: string
modalContainerClassName?: string
}
const modalStackAtom = atom([] as (ModalProps & { id: string })[])
const useDismissAllWhenRouterChange = () => {
const pathname = usePathname()
useEffect(() => {
actions.dismissAll()
}, [pathname])
}
export const useModalStack = () => {
const id = useId()
const currentCount = useRef(0)
return {
present(props: ModalProps & { id?: string }) {
const modalId = `${id}-${currentCount.current++}`
jotaiStore.set(modalStackAtom, (p) => {
const modalProps = {
...props,
id: props.id ?? modalId,
}
modalIdToPropsMap[modalProps.id] = modalProps
return p.concat(modalProps)
})
return () => {
jotaiStore.set(modalStackAtom, (p) => {
return p.filter((item) => item.id !== modalId)
})
}
},
...actions,
}
}
const actions = {
dismiss(id: string) {
jotaiStore.set(modalStackAtom, (p) => {
return p.filter((item) => item.id !== id)
})
},
dismissTop() {
jotaiStore.set(modalStackAtom, (p) => {
return p.slice(0, -1)
})
},
dismissAll() {
jotaiStore.set(modalStackAtom, [])
},
}
export const ModalStackProvider: FC<PropsWithChildren> = ({ children }) => {
return (
<>
{children}
<ModalStack />
</>
)
}
const ModalStack = () => {
const stack = useAtomValue(modalStackAtom)
const isClient = useIsClient()
useDismissAllWhenRouterChange()
if (!isClient) return null
return (
<AnimatePresence>
{stack.map((item, index) => {
return <Modal key={item.id} item={item} index={index} />
})}
</AnimatePresence>
)
}
const enterStyle: Target = {
scale: 1,
opacity: 1,
}
const initialStyle: Target = {
scale: 0.96,
opacity: 0,
}
const modalTransition: Transition = {
...microReboundPreset,
}
const Modal: Component<{
item: ModalProps & { id: string }
index: number
}> = memo(function Modal({ item, index }) {
const setStack = useSetAtom(modalStackAtom)
const close = useEventCallback(() => {
setStack((p) => {
return p.filter((modal) => modal.id !== item.id)
})
})
const onClose = useCallback(
(open: boolean): void => {
if (!open) {
close()
}
},
[close],
)
const animateController = useAnimationControls()
useEffect(() => {
animateController.start(enterStyle)
}, [])
const {
CustomModalComponent,
modalClassName,
content,
title,
clickOutsideToDismiss,
modalContainerClassName,
} = item
const modalStyle = useMemo(() => ({ zIndex: 99 + index }), [index])
const dismiss = useCallback(
(e: SyntheticEvent) => {
stopPropagation(e)
close()
},
[close],
)
const noticeModal = useCallback(() => {
animateController
.start({
scale: 1.05,
transition: {
duration: 0.06,
},
})
.then(() => {
animateController.start({
scale: 1,
})
})
}, [animateController])
const ModalProps: ModalContentPropsInternal = {
dismiss: close,
}
if (CustomModalComponent) {
return (
<Dialog.Root open onOpenChange={onClose}>
<Dialog.Portal>
<DialogOverlay zIndex={20} />
<Dialog.Content asChild>
<div
className={clsxm(
'fixed inset-0 z-[20] overflow-auto',
modalContainerClassName,
)}
onClick={clickOutsideToDismiss ? dismiss : undefined}
>
<div className="contents" onClick={stopPropagation}>
<CustomModalComponent>
{createElement(content, ModalProps)}
</CustomModalComponent>
</div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
)
}
return (
<Dialog.Root open onOpenChange={onClose}>
<Dialog.Portal>
<DialogOverlay zIndex={20} />
<Dialog.Content asChild>
<div
className={clsxm(
'fixed inset-0 z-[20] flex center',
modalContainerClassName,
)}
onClick={clickOutsideToDismiss ? dismiss : noticeModal}
>
<m.div
style={modalStyle}
exit={initialStyle}
initial={initialStyle}
animate={animateController}
transition={modalTransition}
className={clsxm(
'relative flex flex-col overflow-hidden rounded-lg',
'bg-slate-50/80 dark:bg-neutral-900/80',
'p-2 shadow-2xl shadow-stone-300 backdrop-blur-sm dark:shadow-stone-800',
'max-h-[70vh] min-w-[300px] max-w-[90vw] lg:max-h-[calc(100vh-20rem)] lg:max-w-[70vw]',
'border border-slate-200 dark:border-neutral-800',
modalClassName,
)}
onClick={stopPropagation}
>
<Dialog.Title className="flex-shrink-0 px-4 py-2 text-lg font-medium">
{title}
</Dialog.Title>
<Divider className="my-2 flex-shrink-0 border-slate-200 opacity-80 dark:border-neutral-800" />
<div className="min-h-0 flex-shrink flex-grow overflow-auto px-4 py-2">
{createElement(content, ModalProps)}
</div>
<Dialog.DialogClose
onClick={close}
className="absolute right-0 top-0 z-[9] p-5"
>
<CloseIcon />
</Dialog.DialogClose>
</m.div>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
)
})
https://github.com/Innei/Shiro/pull/129
https://github.com/Innei/Shiro/commit/6957e011439eb2d3cbf42bfb67ed81b07d4bcc2a
https://github.com/Innei/Shiro/commit/6957e011439eb2d3cbf42bfb67ed81b07d4bcc2a
https://trpc.io/docs/client/react/useInfiniteQuery
https://trpc.io/docs/client/react/useInfiniteQuery
[TRPC](https://trpc.io/docs/client/react/useInfiniteQuery)
Inline Link Parser
对于内联链接,会根据内置解析增加 Favicon。
Inline [Innei](https://github.com/Innei)
Inline Innei
Inline [pseudoyu](https://twitter.com/pseudo_yu)
Inline pseudoyu
Inline <https://github.com/Innei>
Inline https://github.com/Innei
Inline https://github.com/Innei
Inline https://github.com/Innei
Mention
使用一些 Mention?
[Innei]{GH@Innei}
Spoiler
和删除线有所不同。
Hi, this is ||Spoiler||
Hi, this is Spoiler
KateX
$ c = \pm\sqrt{a^2 + b^2} $
c=±a2+b2
$c = \pm\sqrt{a^2 + b^2}$
c=±a2+b2
P(x)=anxn+an−1xn−1+⋯+a1x+a0
$P(x) = a_nx^n+a_{n-1}x^{n-1} + \dots + a_1x + a_0$
$$
P\left(U,T\right)=100\left.\left(0.6\min\left(1,\frac{U-0.70}{0.90-0.70}\right)+0.4\min\left(1,\frac{T-4000}{14000-4000}\right)\right)\right.
$$
最后更新于 2024/8/15 21:57:42
本书还在编写中..
前往 https://innei.in/posts/tech/my-first-nextjs-book-here#comment 发表你的观点吧。