feat(wip): 富文本消息 (aka Markdown + 自定義解析)
This commit is contained in:
@@ -13,6 +13,8 @@
|
||||
<title>TheWhiteSilk</title>
|
||||
|
||||
<link rel="stylesheet" href="./style.css" />
|
||||
<script src="https://code.jquery.com/jquery-3.7.1.slim.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/gh/GoogleChromeLabs/pinch-zoom@1.1.1/dist/pinch-zoom-min.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -6,6 +6,8 @@ import { breakpoint, Dialog } from "mdui"
|
||||
import * as React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
|
||||
import './ui/custom-elements/chat-image.js'
|
||||
|
||||
const urlParams = new URL(location.href).searchParams
|
||||
|
||||
// deno-lint-ignore no-window no-window-prefix
|
||||
|
||||
@@ -22,8 +22,15 @@ interface Args extends React.HTMLAttributes<HTMLElement> {
|
||||
const markedInstance = new marked.Marked({
|
||||
renderer: {
|
||||
heading({ tokens, depth: _depth }) {
|
||||
const text = this.parser.parseInline(tokens);
|
||||
const text = this.parser.parseInline(tokens)
|
||||
return `<span>${text}</span>`
|
||||
},
|
||||
paragraph({ tokens, depth: _depth }) {
|
||||
const text = this.parser.parseInline(tokens)
|
||||
return `<span>${text}</span>`
|
||||
},
|
||||
image({ title, href }) {
|
||||
return `<chat-image src="${href}"></chat-image>`
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -187,7 +194,15 @@ export default function ChatFragment({ target, showReturnButton, onReturnButtonC
|
||||
<Element_Message
|
||||
key={msg.id}
|
||||
userId={msg.user_id}>
|
||||
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(markedInstance.parse(msg.text) as string) }}></div>
|
||||
<div dangerouslySetInnerHTML={{
|
||||
__html: DOMPurify.sanitize(markedInstance.parse(msg.text) as string, {
|
||||
ALLOWED_TAGS: [
|
||||
"chat-image",
|
||||
"span",
|
||||
"chat-link",
|
||||
]
|
||||
})
|
||||
}}></div>
|
||||
</Element_Message>
|
||||
)
|
||||
}
|
||||
|
||||
91
client/ui/custom-elements/chat-image.js
Normal file
91
client/ui/custom-elements/chat-image.js
Normal file
@@ -0,0 +1,91 @@
|
||||
function openImageViewer(src) {
|
||||
$('#image-viewer-dialog-inner').empty()
|
||||
|
||||
const e = new Image()
|
||||
e.src = src
|
||||
$('#image-viewer-dialog-inner').append(e)
|
||||
|
||||
e.onload = () => $('#image-viewer-dialog-inner').get(0).setTransform({
|
||||
scale: 0.6,
|
||||
x: $(window).width() / 2 - (e.width / 4),
|
||||
y: $(window).height() / 2 - (e.height / 3),
|
||||
})
|
||||
$('#image-viewer-dialog').get(0).open = true
|
||||
}
|
||||
|
||||
customElements.define('chat-image', class extends HTMLElement {
|
||||
constructor() {
|
||||
super()
|
||||
}
|
||||
connectedCallback() {
|
||||
const e = new Image()
|
||||
e.style.maxWidth = "100%"
|
||||
e.style.maxHeight = "90%"
|
||||
e.style.marginTop = "13px"
|
||||
e.style.borderRadius = "var(--mdui-shape-corner-medium)"
|
||||
e.src = $(this).attr('src')
|
||||
e.alt = $(this).attr('alt')
|
||||
e.onerror = () => {
|
||||
const bak = $(this).html()
|
||||
$(this).html(`<br/><mdui-icon name="broken_image" style="font-size: 2rem;"></mdui-icon>`)
|
||||
$(this).attr('alt', '無法加載圖像')
|
||||
$(this).on('click', () => dialog({
|
||||
headline: "圖片無法載入",
|
||||
description: "您是否需要重新加載?",
|
||||
actions: [
|
||||
{
|
||||
text: "重載",
|
||||
onClick: () => {
|
||||
$(this).html(bak)
|
||||
return false
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "取消",
|
||||
onClick: () => {
|
||||
return false
|
||||
},
|
||||
},
|
||||
],
|
||||
}))
|
||||
}
|
||||
e.onclick = () => {
|
||||
openImageViewer($(this).attr('src'))
|
||||
}
|
||||
this.appendChild(e)
|
||||
}
|
||||
})
|
||||
|
||||
document.body.appendChild(new DOMParser().parseFromString(`
|
||||
<mdui-dialog id="image-viewer-dialog" fullscreen="fullscreen">
|
||||
<style>
|
||||
#image-viewer-dialog::part(panel) {
|
||||
background: rgba(0, 0, 0, 0) !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
#image-viewer-dialog>mdui-button-icon[icon=close] {
|
||||
z-index: 114514;
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 15px;
|
||||
color: #ffffff
|
||||
}
|
||||
|
||||
#image-viewer-dialog>mdui-button-icon[icon=open_in_new] {
|
||||
z-index: 114514;
|
||||
position: fixed;
|
||||
top: 15px;
|
||||
right: 65px;
|
||||
color: #ffffff
|
||||
}
|
||||
</style>
|
||||
<mdui-button-icon icon="open_in_new"
|
||||
onclick="window.open($('#image-viewer-dialog-inner > *').attr('src'), '_blank')">
|
||||
</mdui-button-icon>
|
||||
<mdui-button-icon icon="close" onclick="this.parentNode.open = false">
|
||||
</mdui-button-icon>
|
||||
<pinch-zoom id="image-viewer-dialog-inner" style="width: var(--whitesilk-window-width); height: var(--whitesilk-window-height);">
|
||||
</pinch-zoom>
|
||||
</mdui-dialog>
|
||||
`, 'text/html').body.firstChild)
|
||||
Reference in New Issue
Block a user