mirror of
https://github.com/purocean/yn.git
synced 2026-09-24 15:46:02 +08:00
feat(media): add support for video and audio elements in markdown
This commit is contained in:
@@ -348,13 +348,29 @@ body.find-in-preview-highlight ::selection {
|
||||
cursor: zoom-in;
|
||||
}
|
||||
|
||||
p > img[auto-center] {
|
||||
video {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
audio {
|
||||
max-width: 100%;
|
||||
width: 300px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
p > img[auto-center],
|
||||
p > video[auto-center],
|
||||
p > audio[auto-center] {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
|
||||
img {
|
||||
p > audio[auto-center] {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
img, video {
|
||||
&.inline,
|
||||
&[src*=".inline"],
|
||||
&[origin-src*=".inline"] {
|
||||
|
||||
@@ -10,6 +10,8 @@ import type { Components, Doc, ParseLinkResult, PathItem, PositionState, Resourc
|
||||
|
||||
const RE_POS = /:([0-9]+),?([0-9]+)?$/
|
||||
const RE_EXTERNAL_LINK = /^[a-zA-Z_+-]{1,}:/
|
||||
const RE_VIDEO = /\.(mp4|webm|ogg)$/
|
||||
const RE_AUDIO = /\.(mp3|wav|ogg)$/
|
||||
|
||||
export function isAnchorToken (token: Token) {
|
||||
return token.tag === 'a'
|
||||
@@ -116,7 +118,16 @@ export function convertResourceState (currentFile: PathItem, state: StateCore, b
|
||||
name: fileName,
|
||||
}
|
||||
|
||||
token.attrSet(DOM_ATTR_NAME.LOCAL_IMAGE, 'true')
|
||||
if (RE_VIDEO.test(fileName)) {
|
||||
token.tag = 'video'
|
||||
token.type = 'media'
|
||||
} else if (RE_AUDIO.test(fileName)) {
|
||||
token.tag = 'audio'
|
||||
token.type = 'media'
|
||||
} else {
|
||||
token.attrSet(DOM_ATTR_NAME.LOCAL_IMAGE, 'true')
|
||||
}
|
||||
|
||||
token.attrSet(DOM_ATTR_NAME.TARGET_PATH, filePath)
|
||||
token.attrSet(DOM_ATTR_NAME.TARGET_REPO, repo)
|
||||
token.attrSet(originAttr, attrVal)
|
||||
|
||||
@@ -11,6 +11,15 @@ const attrNameReg = /^[a-zA-Z_:][a-zA-Z0-9:._-]*$/
|
||||
const attrEventReg = /^on/i
|
||||
const defaultRules = {} as any
|
||||
|
||||
function onLeavepictureinpicture (e: Event) {
|
||||
const target = e.target as HTMLMediaElement
|
||||
if (!target.isConnected) {
|
||||
target.pause()
|
||||
} else {
|
||||
(target as any).scrollIntoViewIfNeeded()
|
||||
}
|
||||
}
|
||||
|
||||
function validateAttrName (name: string) {
|
||||
return attrNameReg.test(name) && !attrEventReg.test(name)
|
||||
}
|
||||
@@ -169,6 +178,16 @@ defaultRules.image = function (tokens: Token[], idx: number, options: any, env:
|
||||
}, [])
|
||||
}
|
||||
|
||||
defaultRules.media = function (tokens: Token[], idx: number, _options: any, _env: any, slf: Renderer) {
|
||||
const token = tokens[idx]
|
||||
return createVNode(token.tag, {
|
||||
controlsList: 'nodownload',
|
||||
controls: true,
|
||||
onLeavepictureinpicture,
|
||||
...slf.renderAttrs(token) as any,
|
||||
}, [])
|
||||
}
|
||||
|
||||
defaultRules.hardbreak = function () {
|
||||
return createVNode('br')
|
||||
}
|
||||
|
||||
@@ -56,11 +56,18 @@ const MediaPlayer = defineComponent({
|
||||
}
|
||||
})
|
||||
|
||||
function onLeavepictureinpicture (e: Event) {
|
||||
const target = e.target as HTMLMediaElement
|
||||
if (!target.isConnected) {
|
||||
target.pause()
|
||||
}
|
||||
}
|
||||
|
||||
return () => src.value ? h(
|
||||
'div',
|
||||
{ style: 'width: 100%; height: 100%; display: flex; align-items: center; justify-content: center' },
|
||||
type.value === 'video'
|
||||
? h('video', { src: src.value, controls: true, disablePictureInPicture: true, style: 'width: 100%; height: 100%; object-fit: contain' })
|
||||
? h('video', { src: src.value, controls: true, onLeavepictureinpicture, style: 'width: 100%; height: 100%; object-fit: contain' })
|
||||
: type.value === 'audio'
|
||||
? h('audio', { src: src.value, controls: true })
|
||||
: ''
|
||||
|
||||
@@ -10,7 +10,7 @@ export default {
|
||||
tokens[idx + 1]?.type === 'inline' &&
|
||||
tokens[idx + 2]?.type === 'paragraph_close' &&
|
||||
tokens[idx + 1]?.children?.length === 1 &&
|
||||
tokens[idx + 1]?.children?.[0]?.type === 'image'
|
||||
(tokens[idx + 1]?.children?.[0]?.type === 'image' || tokens[idx + 1]?.children?.[0]?.type === 'media')
|
||||
) {
|
||||
tokens[idx + 1]?.children?.[0].attrSet(ctx.args.DOM_ATTR_NAME.ONLY_CHILD, 'true')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user