feat: support dplayer (#497)
This commit is contained in:
parent
d6bb7d2155
commit
452e913f77
|
|
@ -72,6 +72,7 @@
|
|||
"emoji-mart": "5.5.2",
|
||||
"fast-average-color": "^9.3.0",
|
||||
"fast-deep-equal": "3.1.3",
|
||||
"file-size": "^1.0.0",
|
||||
"hast-util-to-html": "^8.0.4",
|
||||
"hast-util-to-text": "^3.1.2",
|
||||
"i18next": "^22.4.15",
|
||||
|
|
@ -97,6 +98,7 @@
|
|||
"pangu": "^4.0.7",
|
||||
"pinyin-pro": "^3.14.0",
|
||||
"prismjs": "1.29.0",
|
||||
"rc-dplayer": "^0.1.0",
|
||||
"qier-progress": "1.0.4",
|
||||
"react": "18.2.0",
|
||||
"react-dom": "18.2.0",
|
||||
|
|
@ -155,6 +157,7 @@
|
|||
"@types/canvas-confetti": "^1.6.0",
|
||||
"@types/chroma-js": "^2.4.0",
|
||||
"@types/cookie": "0.5.1",
|
||||
"@types/file-size": "^1.0.1",
|
||||
"@types/hast": "2.3.4",
|
||||
"@types/js-yaml": "4.0.5",
|
||||
"@types/katex": "^0.16.0",
|
||||
|
|
@ -200,4 +203,4 @@
|
|||
"minimumChangeThreshold": 0,
|
||||
"showDetails": true
|
||||
}
|
||||
}
|
||||
}
|
||||
1458
pnpm-lock.yaml
1458
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
|
@ -1,6 +1,7 @@
|
|||
"use client"
|
||||
|
||||
import { useDebounceEffect } from "ahooks"
|
||||
import filesize from "file-size"
|
||||
import type { Root } from "mdast"
|
||||
import { nanoid } from "nanoid"
|
||||
import { useParams, useRouter, useSearchParams } from "next/navigation"
|
||||
|
|
@ -44,6 +45,7 @@ import { useIsMobileLayout } from "~/hooks/useMobileLayout"
|
|||
import { useSyncOnce } from "~/hooks/useSyncOnce"
|
||||
import { useUploadFile } from "~/hooks/useUploadFile"
|
||||
import { showConfetti } from "~/lib/confetti"
|
||||
import { MAXIMUM_FILE_SIZE } from "~/lib/constants"
|
||||
import { getDefaultSlug } from "~/lib/default-slug"
|
||||
import { CSB_SCAN } from "~/lib/env"
|
||||
import { getSiteLink, getTwitterShareUrl } from "~/lib/helpers"
|
||||
|
|
@ -348,9 +350,22 @@ export default function SubdomainEditor() {
|
|||
try {
|
||||
if (
|
||||
!file.type.startsWith("image/") &&
|
||||
!file.type.startsWith("audio/")
|
||||
!file.type.startsWith("audio/") &&
|
||||
!file.type.startsWith("video/")
|
||||
) {
|
||||
throw new Error("You can only upload images and audios")
|
||||
throw new Error("You can only upload images, audios and videos")
|
||||
}
|
||||
|
||||
const uploadFilesize = filesize(file.size).to("MB")
|
||||
|
||||
if (Number(uploadFilesize) > MAXIMUM_FILE_SIZE) {
|
||||
toast.error(
|
||||
`File Size is too big. It should be less than ${MAXIMUM_FILE_SIZE} MB`,
|
||||
{
|
||||
id: toastId,
|
||||
},
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
const { key } = await uploadFile(file)
|
||||
|
|
@ -389,6 +404,12 @@ export default function SubdomainEditor() {
|
|||
} ${cover ? `cover="${cover}"` : ""}><audio>\n`,
|
||||
),
|
||||
)
|
||||
} else if (file.type.startsWith("video/")) {
|
||||
view?.dispatch(
|
||||
view.state.replaceSelection(
|
||||
`\n<video>\n\t<source src=\"${key}\" type=\"${file.type}\" />\n</video>\n`,
|
||||
),
|
||||
)
|
||||
} else if (file.type === "text/plain") {
|
||||
view?.dispatch(view.state.replaceSelection(key))
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
import { DPlayerProps, Player as RcDPlayer } from "rc-dplayer"
|
||||
import { FC, memo } from "react"
|
||||
import { ReactElement } from "rehype-react/lib"
|
||||
|
||||
import { toGateway } from "~/lib/ipfs-parser"
|
||||
|
||||
const DPlayer: FC<{
|
||||
children: ReactElement[]
|
||||
}> = memo(function DPlayer({ children }) {
|
||||
const sources = children.filter(
|
||||
(child) =>
|
||||
child && typeof child.type === "string" && child.type === "source",
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
{sources.map((source, idx) => {
|
||||
const { src: _src, ...props } = source.props as DPlayerProps
|
||||
|
||||
if (!_src) {
|
||||
return <div key={idx} />
|
||||
}
|
||||
|
||||
const src = toGateway(_src)
|
||||
|
||||
return (
|
||||
<div className="my-8" key={idx}>
|
||||
<RcDPlayer src={src} {...props} />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</>
|
||||
)
|
||||
})
|
||||
|
||||
export default DPlayer
|
||||
|
|
@ -8,3 +8,5 @@ export const IS_DEV = process.env.NODE_ENV === "development"
|
|||
export const IS_VERCEL_PREVIEW =
|
||||
process.env.NEXT_PUBLIC_VERCEL_ENV === "preview" ||
|
||||
process.env.VERCEL_ENV === "preview"
|
||||
|
||||
export const MAXIMUM_FILE_SIZE = 100 // MB
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import jsYaml from "js-yaml"
|
||||
import type { Root } from "mdast"
|
||||
import { Result as TocResult, toc } from "mdast-util-toc"
|
||||
import dynamic from "next/dynamic"
|
||||
import { ReactElement, createElement } from "react"
|
||||
import { toast } from "react-hot-toast"
|
||||
import { refractor } from "refractor"
|
||||
|
|
@ -43,6 +44,7 @@ import {
|
|||
import { rehypeImage } from "./rehype-image"
|
||||
import { rehypeTable } from "./rehype-table"
|
||||
import { rehypeTweet } from "./rehype-tweet"
|
||||
import { rehypeVideo } from "./rehype-video"
|
||||
import { rehypeWrapCode } from "./rehype-wrap-code"
|
||||
import { rehypeExternalLink } from "./rehyper-external-link"
|
||||
import { remarkCallout } from "./remark-callout"
|
||||
|
|
@ -51,6 +53,10 @@ import { remarkPangu } from "./remark-pangu"
|
|||
import { remarkYoutube } from "./remark-youtube"
|
||||
import sanitizeScheme from "./sanitize-schema"
|
||||
|
||||
const DPlayer = dynamic(() => import("~/components/ui/DPlayer"), {
|
||||
ssr: false,
|
||||
})
|
||||
|
||||
export type MarkdownEnv = {
|
||||
excerpt: string
|
||||
frontMatter: Record<string, any>
|
||||
|
|
@ -142,6 +148,7 @@ export const renderPageContent = (
|
|||
.use(rehypeRaw, { passThrough: allowedCustomWrappers })
|
||||
.use(rehypeImage, { env })
|
||||
.use(rehypeAudio, { env })
|
||||
.use(rehypeVideo, { env })
|
||||
.use(rehypeSlug)
|
||||
.use(rehypeAutolinkHeadings, {
|
||||
properties: {
|
||||
|
|
@ -216,6 +223,7 @@ export const renderPageContent = (
|
|||
mention: Mention,
|
||||
mermaid: Mermaid,
|
||||
audio: APlayer,
|
||||
video: DPlayer,
|
||||
tweet: Tweet,
|
||||
style: Style,
|
||||
} as any,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
import { Root } from "rehype-raw"
|
||||
import { Plugin } from "unified"
|
||||
import { visit } from "unist-util-visit"
|
||||
|
||||
import { toGateway } from "~/lib/ipfs-parser"
|
||||
|
||||
import { MarkdownEnv } from "."
|
||||
|
||||
export const rehypeVideo: Plugin<Array<{ env: MarkdownEnv }>, Root> = ({
|
||||
env,
|
||||
}) => {
|
||||
return (tree) => {
|
||||
let first = true
|
||||
visit(tree, { tagName: "video" }, (node, i, parent) => {
|
||||
if (!node.properties) {
|
||||
return
|
||||
}
|
||||
|
||||
for (const child of node.children) {
|
||||
if (child.type === "element" && child.tagName === "source") {
|
||||
if (!child.properties) {
|
||||
continue
|
||||
}
|
||||
|
||||
const src = child.properties.src
|
||||
|
||||
if (!src || typeof src !== "string") {
|
||||
continue
|
||||
}
|
||||
|
||||
child.properties.src = toGateway(src)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue