Compare commits

...

5 Commits

Author SHA1 Message Date
CrescentLeaf
095b454539 todo: textfield, 但是不是 textarea 而是自定义的输入框 2025-11-21 22:34:27 +08:00
CrescentLeaf
cbdccfb5a7 修缮 snack 2025-11-21 21:52:17 +08:00
CrescentLeaf
32719b45ea 默认自动识别 Android / iOS 设备 2025-11-21 21:46:21 +08:00
CrescentLeaf
b32f60d94d 阻止提及文本点击事件冒泡 2025-11-21 21:38:15 +08:00
CrescentLeaf
d524304b29 ui: 提及 使用 a 而不是 span 2025-11-21 21:28:21 +08:00
7 changed files with 46 additions and 24 deletions

View File

@@ -41,7 +41,7 @@ class Client {
if (re.code != 200) { if (re.code != 200) {
if (re.code == -1) { if (re.code == -1) {
auth() auth()
} else if (re.code != 401) { } else if (re.code != 401 && re.code != 400) {
const s2 = checkApiSuccessOrSncakbar(re, "重新验证失败") const s2 = checkApiSuccessOrSncakbar(re, "重新验证失败")
s2!.autoCloseDelay = 0 s2!.autoCloseDelay = 0
s2!.action = "重试" s2!.action = "重试"
@@ -98,7 +98,7 @@ class Client {
// 错误处理 // 错误处理
if (err) return resolve({ if (err) return resolve({
code: -1, code: -1,
msg: err.message.indexOf("timed out") != -1 ? "求超" : err.message, msg: err.message.indexOf("timed out") != -1 ? "求超" : err.message,
}) })
// 在特殊的方法之中, 不予进行: 令牌刷新并重试 // 在特殊的方法之中, 不予进行: 令牌刷新并重试
// 附带 retry 次数限制 // 附带 retry 次数限制

View File

@@ -0,0 +1,18 @@
import * as React from 'react'
import { $, TextField } from "mdui"
interface Args extends React.HTMLAttributes<TextField & HTMLElement> {
}
export default function TextFieldCustom({ ...prop }: Args) {
// deno-lint-ignore no-explicit-any
const textField = React.useRef<any>(null)
React.useEffect(() => {
const shadow = (textField.current as TextField).shadowRoot
// $(shadow).find('textarea')
})
return <mdui-text-field {...prop} ref={textField}></mdui-text-field>
}

View File

@@ -3,7 +3,7 @@ import DataCaches from "../../api/DataCaches.ts"
import { snackbar } from "../snackbar.ts" import { snackbar } from "../snackbar.ts"
customElements.define('chat-mention', class extends HTMLElement { customElements.define('chat-mention', class extends HTMLElement {
declare span: HTMLSpanElement declare link: HTMLAnchorElement
static observedAttributes = ['user-id'] static observedAttributes = ['user-id']
constructor() { constructor() {
super() super()
@@ -13,10 +13,11 @@ customElements.define('chat-mention', class extends HTMLElement {
connectedCallback() { connectedCallback() {
const shadow = this.shadowRoot as ShadowRoot const shadow = this.shadowRoot as ShadowRoot
this.span = document.createElement('span') this.link = document.createElement('a')
this.span.style.fontSynthesis = 'style weight' this.link.style.fontSynthesis = 'style weight'
this.span.style.color = 'rgb(var(--mdui-color-primary))' this.link.style.color = 'rgb(var(--mdui-color-primary))'
shadow.appendChild(this.span) this.link.href = 'javascript:void(0)'
shadow.appendChild(this.link)
this.update() this.update()
} }
@@ -24,33 +25,36 @@ customElements.define('chat-mention', class extends HTMLElement {
this.update() this.update()
} }
async update() { async update() {
if (this.span == null) return if (this.link == null) return
const userId = $(this).attr('user-id') const userId = $(this).attr('user-id')
const chatId = $(this).attr('chat-id') const chatId = $(this).attr('chat-id')
const text = $(this).attr('text') const text = $(this).attr('text')
this.span.style.fontStyle = '' this.link.style.fontStyle = ''
if (chatId) { if (chatId) {
const chat = await DataCaches.getChatInfo(chatId) const chat = await DataCaches.getChatInfo(chatId)
this.span.textContent = chat?.title this.link.textContent = chat?.title
this.span.onclick = () => { this.link.onclick = (e) => {
e.stopPropagation()
// deno-lint-ignore no-window // deno-lint-ignore no-window
window.openChatInfoDialog(chat) window.openChatInfoDialog(chat)
} }
} else if (userId) { } else if (userId) {
const user = await DataCaches.getUserProfile(userId) const user = await DataCaches.getUserProfile(userId)
this.span.textContent = user?.nickname this.link.textContent = user?.nickname
this.span.onclick = () => { this.link.onclick = (e) => {
e.stopPropagation()
// deno-lint-ignore no-window // deno-lint-ignore no-window
window.openUserInfoDialog(user) window.openUserInfoDialog(user)
} }
} }
text && (this.span.textContent = text) text && (this.link.textContent = text)
if (!(userId || chatId)) { if (!(userId || chatId)) {
this.span.textContent = "无效的提及" this.link.textContent = "无效的提及"
this.span.style.fontStyle = 'italic' this.link.style.fontStyle = 'italic'
this.span.onclick = () => { this.link.onclick = (e) => {
e.stopPropagation()
snackbar({ snackbar({
message: "该提及没有指定用户或者对话!", message: "该提及没有指定用户或者对话!",
placement: 'top', placement: 'top',

View File

@@ -1,3 +1,3 @@
export default function isMobileUI() { export default function isMobileUI() {
return new URL(location.href).searchParams.get('mobile') == 'true' return new URL(location.href).searchParams.get('mobile') == 'true' || /Mobi|Android|iPhone/i.test(navigator.userAgent)
} }

View File

@@ -40,9 +40,9 @@ export default function ContactsList({
token: data.access_token, token: data.access_token,
}) })
if (re.code != 200) { if (re.code != 200) {
if (re.code != 401) checkApiSuccessOrSncakbar(re, "获取收藏对话列表失败") if (re.code != 401 && re.code != 400) checkApiSuccessOrSncakbar(re, "获取收藏对话列表失败")
return return
} }
const ls = re.data!.contacts_list as Chat[] const ls = re.data!.contacts_list as Chat[]
setContactsList(ls) setContactsList(ls)
setSharedFavouriteChats(ls) setSharedFavouriteChats(ls)
@@ -53,7 +53,7 @@ export default function ContactsList({
EventBus.off('ContactsList.updateContacts') EventBus.off('ContactsList.updateContacts')
} }
// 警告: 不添加 deps 導致無限執行 // 警告: 不添加 deps 導致無限執行
}, []) }, [])
return <mdui-list style={{ return <mdui-list style={{
overflowY: 'auto', overflowY: 'auto',

View File

@@ -36,7 +36,7 @@ export default function RecentsList({
token: data.access_token, token: data.access_token,
}) })
if (re.code != 200) { if (re.code != 200) {
if (re.code != 401) checkApiSuccessOrSncakbar(re, "获取最近对话列表失败") if (re.code != 401 && re.code != 400) checkApiSuccessOrSncakbar(re, "获取最近对话列表失败")
return return
} }

View File

@@ -86,7 +86,7 @@ interface SnackbarOptions extends Options {
export function checkApiSuccessOrSncakbar(re: ApiCallbackMessage, msg_ahead: string, opinions_override: Options = {}): Snackbar | null { export function checkApiSuccessOrSncakbar(re: ApiCallbackMessage, msg_ahead: string, opinions_override: Options = {}): Snackbar | null {
return re.code != 200 ? snackbar( return re.code != 200 ? snackbar(
Object.assign({ Object.assign({
message: `${msg_ahead}: ${re.msg.indexOf("Failed to fetch") != -1 message: `${msg_ahead}: ${re.msg.indexOf("fetch") != -1
? "HTTP 请求失败" ? "HTTP 请求失败"
: re.msg : re.msg
} [${re.code}]`, } [${re.code}]`,