From 125938b8be315cd65ecbbac339046b86a47bb4ff Mon Sep 17 00:00:00 2001 From: CrescentLeaf Date: Sat, 13 Sep 2025 22:14:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(ui):=20(wip)=E7=A7=BB=E5=8B=95=E7=AB=AF?= =?UTF-8?q?=E7=95=8C=E9=9D=A2!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- client/index.ts | 8 +- client/ui/AppMobile.tsx | 181 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 client/ui/AppMobile.tsx diff --git a/client/index.ts b/client/index.ts index 28350b7..298fc60 100644 --- a/client/index.ts +++ b/client/index.ts @@ -6,8 +6,10 @@ import { breakpoint, Dialog } from "mdui" import * as React from 'react' import ReactDOM from 'react-dom/client' +const urlParams = new URL(location.href).searchParams + // deno-lint-ignore no-window no-window-prefix -new URL(location.href).searchParams.get('debug') == 'true' && window.addEventListener('error', ({ message, filename, lineno, colno, error }) => { +urlParams.get('debug') == 'true' && window.addEventListener('error', ({ message, filename, lineno, colno, error }) => { const m = $("#ErrorDialog_Message") const d = $("#ErrorDialog").get(0) as Dialog const s = d.open @@ -16,8 +18,8 @@ new URL(location.href).searchParams.get('debug') == 'true' && window.addEventLis }) import App from './ui/App.tsx' - -ReactDOM.createRoot(document.getElementById('app') as HTMLElement).render(React.createElement(App, null)) +import AppMobile from './ui/AppMobile.tsx' +ReactDOM.createRoot(document.getElementById('app') as HTMLElement).render(React.createElement(urlParams.get('mobile') == 'true' ? AppMobile : App, null)) const onResize = () => { document.body.style.setProperty('--whitesilk-widget-message-maxwidth', breakpoint().down('md') ? "80%" : "70%") diff --git a/client/ui/AppMobile.tsx b/client/ui/AppMobile.tsx new file mode 100644 index 0000000..f4b9329 --- /dev/null +++ b/client/ui/AppMobile.tsx @@ -0,0 +1,181 @@ +import Client from "../api/Client.ts" +import data from "../Data.ts" +import ChatFragment from "./chat/ChatFragment.jsx" +import ContactsListItem from "./main/ContactsListItem.jsx" +import RecentsListItem from "./main/RecentsListItem.jsx" +import useEventListener from './useEventListener.ts' +import User from "../api/client_data/User.ts" +import RecentChat from "../api/client_data/RecentChat.ts" +import Avatar from "./Avatar.tsx" + +import * as React from 'react' +import { Button, ButtonIcon, Dialog, NavigationBar, TextField } from "mdui" +import Split from 'split.js' +import 'mdui/jsx.zh-cn.d.ts' +import { checkApiSuccessOrSncakbar } from "./snackbar.ts" + +import RegisterDialog from "./dialog/RegisterDialog.tsx" +import LoginDialog from "./dialog/LoginDialog.tsx" +import UserProfileDialog from "./dialog/UserProfileDialog.tsx" + +declare global { + namespace React { + namespace JSX { + interface IntrinsicAttributes { + id?: string + slot?: string + } + } + } +} + +export default function AppMobile() { + const [recentsList, setRecentsList] = React.useState([ + { + id: '0', + avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", + title: "麻油衣酱", + content: "成步堂君, 我又坐牢了(" + }, + { + id: '0', + avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", + title: "Maya Fey", + content: "我是绫里真宵, 是一名灵媒师~" + }, + ] as RecentChat[]) + const [contactsMap, setContactsMap] = React.useState({ + 所有: [ + { + id: '0', + avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", + nickname: "麻油衣酱", + }, + { + id: '0', + avatar: "https://www.court-records.net/mugshot/aa6-004-maya.png", + nickname: "Maya Fey", + }, + ], + } as unknown as { [key: string]: User[] }) + const [navigationItemSelected, setNavigationItemSelected] = React.useState('Recents') + + const navigationBarRef: React.MutableRefObject = React.useRef(null) + useEventListener(navigationBarRef, 'change', (event) => { + setNavigationItemSelected((event.target as HTMLElement as NavigationBar).value as string) + }) + + const loginDialogRef: React.MutableRefObject = React.useRef(null) + const loginInputAccountRef: React.MutableRefObject = React.useRef(null) + const loginInputPasswordRef: React.MutableRefObject = React.useRef(null) + + const registerDialogRef: React.MutableRefObject = React.useRef(null) + const registerInputUserNameRef: React.MutableRefObject = React.useRef(null) + const registerInputNickNameRef: React.MutableRefObject = React.useRef(null) + const registerInputPasswordRef: React.MutableRefObject = React.useRef(null) + + const userProfileDialogRef: React.MutableRefObject = React.useRef(null) + const openMyUserProfileDialogButtonRef: React.MutableRefObject = React.useRef(null) +/* useEventListener(openMyUserProfileDialogButtonRef, 'click', (_event) => { + userProfileDialogRef.current!.open = true + })*/ + + const [myUserProfileCache, setMyUserProfileCache]: [User, React.Dispatch>] = React.useState(null as unknown as User) + + React.useEffect(() => { + ; (async () => { + Client.connect() + const re = await Client.auth(data.access_token || "") + if (re.code == 401) + loginDialogRef.current!.open = true + else if (re.code != 200) { + if (checkApiSuccessOrSncakbar(re, "驗證失敗")) return + } else if (re.code == 200) { + setMyUserProfileCache(Client.myUserProfile as User) + } + })() + }, []) + + return ( +
+ + + + + + + + 最近 + 聯絡人 + + + { + // 最近聊天 + + { + recentsList.map((v) => + + ) + } + + } + { + // 联系人列表 + + + { + Object.keys(contactsMap).map((v) => + + {v} + { + contactsMap[v].map((v2) => + + ) + } + + ) + } + + + } +
+ ) +} \ No newline at end of file