TODO: 推翻整个项目重新建立根基
This commit is contained in:
39
client/ui/chat-elements/chat-file.ts
Normal file
39
client/ui/chat-elements/chat-file.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { $ } from 'mdui/jq'
|
||||
|
||||
customElements.define('chat-file', class extends HTMLElement {
|
||||
static observedAttributes = ['href', 'name']
|
||||
declare anchor: HTMLAnchorElement
|
||||
declare span: HTMLSpanElement
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
update() {
|
||||
if (this.anchor == null) return
|
||||
|
||||
this.anchor.href = $(this).attr('href') as string
|
||||
this.anchor.download = $(this).attr('href') as string
|
||||
this.span.textContent = $(this).attr("name") as string
|
||||
}
|
||||
attributeChangedCallback(_name: string, _oldValue: unknown, _newValue: unknown) {
|
||||
this.update()
|
||||
}
|
||||
connectedCallback() {
|
||||
this.anchor = new DOMParser().parseFromString(`
|
||||
<a style="width: 100%;height: 100%;">
|
||||
<mdui-card clickable style="display: flex;align-items: center;box-shadow: inherit;border-radius: inherit;">
|
||||
<mdui-icon name="insert_drive_file" style="margin: 13px;font-size: 34px;"></mdui-icon>
|
||||
<span style="margin-right: 13px; word-wrap: break-word; word-break:break-all;white-space:normal; max-width :100%;"></span>
|
||||
</mdui-card>
|
||||
</a>`, 'text/html').body.firstChild as HTMLAnchorElement
|
||||
this.span = $(this.anchor).find('span').get(0)
|
||||
this.anchor.style.textDecoration = 'none'
|
||||
this.anchor.style.color = 'inherit'
|
||||
this.anchor.onclick = (e) => {
|
||||
e.stopPropagation()
|
||||
}
|
||||
this.shadowRoot!.appendChild(this.anchor)
|
||||
|
||||
this.update()
|
||||
}
|
||||
})
|
||||
58
client/ui/chat-elements/chat-image.ts
Normal file
58
client/ui/chat-elements/chat-image.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import openImageViewer from "../../utils/openImageViewer.ts"
|
||||
|
||||
import { $ } from 'mdui/jq'
|
||||
|
||||
|
||||
customElements.define('chat-image', class extends HTMLElement {
|
||||
static observedAttributes = ['src', 'show-error']
|
||||
declare img: HTMLImageElement
|
||||
declare error: HTMLElement
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
update() {
|
||||
if (this.img == null) return
|
||||
|
||||
this.img.src = $(this).attr('src') as string
|
||||
|
||||
const error = $(this).attr('show-error') == 'true'
|
||||
this.img.style.display = error ? 'none' : 'block'
|
||||
this.error.style.display = error ? '' : 'none'
|
||||
}
|
||||
attributeChangedCallback(_name: string, _oldValue: unknown, _newValue: unknown) {
|
||||
this.update()
|
||||
}
|
||||
connectedCallback() {
|
||||
this.img = new Image()
|
||||
this.img.style.width = '100%'
|
||||
this.img.style.maxHeight = "300px"
|
||||
this.img.style.objectFit = 'cover'
|
||||
// this.img.style.borderRadius = "var(--mdui-shape-corner-medium)"
|
||||
this.shadowRoot!.appendChild(this.img)
|
||||
|
||||
this.error = new DOMParser().parseFromString(`<mdui-icon name="broken_image" style="font-size: 2rem;"></mdui-icon>`, 'text/html').body.firstChild as HTMLElement
|
||||
this.shadowRoot!.appendChild(this.error)
|
||||
|
||||
this.img.addEventListener('error', () => {
|
||||
$(this).attr('show-error', 'true')
|
||||
})
|
||||
this.error.addEventListener('click', (event) => {
|
||||
event.stopPropagation()
|
||||
const img = this.img
|
||||
this.img = new Image()
|
||||
this.img.style.width = '100%'
|
||||
this.img.style.maxHeight = "300px"
|
||||
this.img.style.objectFit = 'cover'
|
||||
this.shadowRoot!.replaceChild(img, this.img)
|
||||
$(this).attr('show-error', undefined)
|
||||
})
|
||||
this.img.addEventListener('click', (event) => {
|
||||
event.stopPropagation()
|
||||
openImageViewer($(this).attr('src') as string)
|
||||
})
|
||||
|
||||
this.update()
|
||||
}
|
||||
})
|
||||
60
client/ui/chat-elements/chat-mention.ts
Normal file
60
client/ui/chat-elements/chat-mention.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { $ } from 'mdui'
|
||||
import showSnackbar from "../../utils/showSnackbar.ts";
|
||||
customElements.define('chat-mention', class extends HTMLElement {
|
||||
declare link: HTMLAnchorElement
|
||||
static observedAttributes = ['user-id']
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
connectedCallback() {
|
||||
const shadow = this.shadowRoot as ShadowRoot
|
||||
|
||||
this.link = document.createElement('a')
|
||||
this.link.style.fontSynthesis = 'style weight'
|
||||
this.link.style.color = 'rgb(var(--mdui-color-primary))'
|
||||
this.link.href = 'javascript:void(0)'
|
||||
shadow.appendChild(this.link)
|
||||
|
||||
this.update()
|
||||
}
|
||||
attributeChangedCallback(_name: string, _oldValue: unknown, _newValue: unknown) {
|
||||
this.update()
|
||||
}
|
||||
async update() {
|
||||
if (this.link == null) return
|
||||
|
||||
const userId = $(this).attr('user-id')
|
||||
const chatId = $(this).attr('chat-id')
|
||||
const text = $(this).attr('text')
|
||||
this.link.style.fontStyle = ''
|
||||
if (chatId) {
|
||||
|
||||
this.link.onclick = (e) => {
|
||||
e.stopPropagation()
|
||||
// deno-lint-ignore no-window
|
||||
|
||||
}
|
||||
} else if (userId) {
|
||||
|
||||
this.link.onclick = (e) => {
|
||||
e.stopPropagation()
|
||||
// deno-lint-ignore no-window
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
text && (this.link.textContent = text)
|
||||
if (!(userId || chatId)) {
|
||||
this.link.textContent = "无效的提及"
|
||||
this.link.style.fontStyle = 'italic'
|
||||
this.link.onclick = (e) => {
|
||||
e.stopPropagation()
|
||||
showSnackbar({
|
||||
message: "该提及没有指定用户或者对话!",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
45
client/ui/chat-elements/chat-quote.ts
Normal file
45
client/ui/chat-elements/chat-quote.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { $ } from 'mdui/jq'
|
||||
|
||||
customElements.define('chat-quote', class extends HTMLElement {
|
||||
declare container: HTMLAnchorElement
|
||||
declare span: HTMLSpanElement
|
||||
declare ellipsis: boolean
|
||||
constructor() {
|
||||
super()
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
update() {
|
||||
if (this.container == null) return
|
||||
|
||||
this.span.textContent = this.textContent
|
||||
|
||||
this.updateStyle()
|
||||
}
|
||||
updateStyle() {
|
||||
this.span.style.whiteSpace = this.ellipsis ? 'nowrap' : 'pre-wrap'
|
||||
this.span.style.overflow = this.ellipsis ? 'hidden' : ''
|
||||
this.span.style.textOverflow = this.ellipsis ? 'ellipsis' : ''
|
||||
}
|
||||
attributeChangedCallback(_name: string, _oldValue: unknown, _newValue: unknown) {
|
||||
this.update()
|
||||
}
|
||||
connectedCallback() {
|
||||
this.container = new DOMParser().parseFromString(`
|
||||
<a style="width: 100%;height: 100%; color: rgb(var(--mdui-color-primary));" href="javascript:void(0)">
|
||||
<span style="display: block; word-wrap: break-word; word-break:break-all;white-space:normal; max-width :100%;"></span>
|
||||
</a>`, 'text/html').body.firstChild as HTMLAnchorElement
|
||||
this.span = $(this.container).find('span').get(0)
|
||||
this.container.style.textDecoration = 'none'
|
||||
this.span.style.fontSynthesis = 'style weight'
|
||||
this.container.onclick = (e) => {
|
||||
this.ellipsis = !this.ellipsis
|
||||
this.updateStyle()
|
||||
e.stopPropagation()
|
||||
}
|
||||
this.ellipsis = true
|
||||
|
||||
this.shadowRoot!.appendChild(this.container)
|
||||
|
||||
this.update()
|
||||
}
|
||||
})
|
||||
16
client/ui/chat-elements/chat-text-container.ts
Normal file
16
client/ui/chat-elements/chat-text-container.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
customElements.define('chat-text-container', class extends HTMLElement {
|
||||
declare container: HTMLDivElement
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
connectedCallback() {
|
||||
const shadow = this.shadowRoot as ShadowRoot
|
||||
|
||||
this.container = document.createElement('div')
|
||||
this.container.style.padding = '13px'
|
||||
shadow.appendChild(this.container)
|
||||
this.container.innerHTML = this.innerHTML
|
||||
}
|
||||
})
|
||||
40
client/ui/chat-elements/chat-text.ts
Normal file
40
client/ui/chat-elements/chat-text.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import { $ } from 'mdui'
|
||||
|
||||
customElements.define('chat-text', class extends HTMLElement {
|
||||
declare span: HTMLSpanElement
|
||||
static observedAttributes = ['underline', 'em']
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
connectedCallback() {
|
||||
const shadow = this.shadowRoot as ShadowRoot
|
||||
|
||||
this.span = document.createElement('span')
|
||||
this.span.style.whiteSpace = 'pre-wrap'
|
||||
this.span.style.fontSynthesis = 'style weight'
|
||||
shadow.appendChild(this.span)
|
||||
|
||||
this.update()
|
||||
}
|
||||
attributeChangedCallback(_name: string, _oldValue: unknown, _newValue: unknown) {
|
||||
this.update()
|
||||
}
|
||||
update() {
|
||||
if (this.span == null) return
|
||||
|
||||
const isFirstElementInParent = this.parentElement?.firstElementChild == this
|
||||
const isLastElementInParent = this.parentElement?.lastElementChild == this
|
||||
|
||||
// 避免不同的消息类型之间的换行符导致显示异常
|
||||
if (isFirstElementInParent)
|
||||
this.span.textContent = this.textContent.trimStart()
|
||||
else if (isLastElementInParent)
|
||||
this.span.textContent = this.textContent.trimEnd()
|
||||
else
|
||||
this.span.textContent = this.textContent
|
||||
this.span.style.textDecoration = $(this).attr('underline') ? 'underline' : ''
|
||||
this.span.style.fontStyle = $(this).attr('em') ? 'italic' : ''
|
||||
}
|
||||
})
|
||||
32
client/ui/chat-elements/chat-video.ts
Normal file
32
client/ui/chat-elements/chat-video.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { $ } from 'mdui/jq'
|
||||
|
||||
customElements.define('chat-video', class extends HTMLElement {
|
||||
static observedAttributes = ['src']
|
||||
declare video: HTMLVideoElement
|
||||
constructor() {
|
||||
super()
|
||||
|
||||
this.attachShadow({ mode: 'open' })
|
||||
}
|
||||
update() {
|
||||
if (this.video == null) return
|
||||
|
||||
this.video.src = $(this).attr('src') as string
|
||||
}
|
||||
attributeChangedCallback(_name: string, _oldValue: unknown, _newValue: unknown) {
|
||||
this.update()
|
||||
}
|
||||
connectedCallback() {
|
||||
this.video = new DOMParser().parseFromString(`<video controls></video>`, 'text/html').body.firstChild as HTMLVideoElement
|
||||
this.video.style.maxWidth = "400px"
|
||||
this.video.style.maxHeight = "300px"
|
||||
this.video.style.width = "100%"
|
||||
this.video.style.height = "100%"
|
||||
this.video.style.display = 'block'
|
||||
// e.style.borderRadius = "var(--mdui-shape-corner-medium)"
|
||||
|
||||
this.video.onclick = (e) => e.stopPropagation()
|
||||
this.shadowRoot!.appendChild(this.video)
|
||||
this.update()
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user