cloudflare-chat/public/index.html

283 lines
13 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>在线聊天室</title>
<script>
(() => {
try {
const saved = localStorage.getItem("theme");
const theme =
saved === "dark" || saved === "light"
? saved
: window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
document.documentElement.dataset.theme = theme;
} catch {}
})();
</script>
<link rel="stylesheet" href="/app.css" />
</head>
<body>
<div class="scene-container">
<main class="chat-room" id="chatRoom">
<div class="chat-interface">
<header class="topbar">
<div class="brand">聊天室</div>
<div class="topbarRight">
<div class="me" id="meBox"></div>
<button class="btn iconBtn themeBtn" id="themeBtn" type="button" aria-label="切换黑夜模式" aria-pressed="false">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12.8A9 9 0 1 1 11.2 3 7 7 0 0 0 21 12.8Z" />
</svg>
</button>
<button class="btn iconBtn menuBtn" id="menuBtn" type="button" aria-label="账户与管理">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M20 21a8 8 0 0 0-16 0" />
<circle cx="12" cy="8" r="4" />
</svg>
</button>
</div>
</header>
<div class="menuDropdown" id="menuDropdown" hidden>
<div class="menuDropdownCard card" id="menuDropdownCard">
<div class="menuDropdownHeader">
<div class="menuDropdownTitle">菜单</div>
<button class="btn iconBtn" id="menuCloseBtn" type="button" aria-label="关闭菜单">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 6 6 18" />
<path d="M6 6l12 12" />
</svg>
</button>
</div>
<div id="menuHost">
<details class="card fold" id="accountFold">
<summary class="foldSummary">账户</summary>
<div class="foldBody">
<div id="authBox"></div>
</div>
</details>
<details class="card fold" id="adminCard" style="display:none">
<summary class="foldSummary">管理</summary>
<div class="foldBody">
<div class="row">
<button id="loadUsersBtn" class="btn">刷新用户</button>
<button id="lobbyPwdBtn" class="btn">大厅密码</button>
</div>
<div id="adminToolsBox" class="stack" style="margin-top:10px" hidden></div>
<div class="hint" style="margin-top:10px">用户列表</div>
<div id="adminUsersBox" class="admin"></div>
</div>
</details>
</div>
</div>
</div>
<main class="layout">
<aside class="sidebar">
<div class="card" id="onlineCard">
<div class="row" style="justify-content:space-between; align-items:center">
<div style="font-weight:900; color:var(--text-main); font-size:13px">在线用户</div>
<div class="hint" id="onlineCount"></div>
</div>
<div class="onlineList" id="onlineList"></div>
</div>
</aside>
<section class="chat">
<div class="chatHeader">
<div>
<div class="chatTitle" id="roomTitle">未进入聊天室</div>
<div class="chatSubtitle" id="roomSubtitle"></div>
</div>
<div class="row">
<button id="leaveRoomBtn" class="btn" disabled>离开</button>
</div>
</div>
<div class="messages" id="messages"></div>
<div class="composer">
<div class="composerRow">
<button class="btn iconBtn toolBtn" id="emojiBtn" type="button" aria-label="表情" disabled>
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z" />
<path d="M8 14s1.5 2 4 2 4-2 4-2" />
<path d="M9 9h.01" />
<path d="M15 9h.01" />
</svg>
</button>
<button class="btn iconBtn toolBtn" id="imageBtn" type="button" aria-label="图片" disabled hidden>
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 19a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v14Z" />
<path d="M8.5 10.5a1.5 1.5 0 1 0 0-3 1.5 1.5 0 0 0 0 3Z" />
<path d="m21 15-5-5L5 21" />
</svg>
</button>
<div class="msgInputWrap" id="msgInputWrap">
<img id="inlineThumb" class="inlineThumb" alt="待发送图片" hidden />
<input id="msgInput" class="input" placeholder="输入消息…" disabled />
</div>
<button id="sendBtn" class="btn btnPrimary" disabled>发送</button>
</div>
<input id="fileInput" type="file" accept="image/*" hidden />
<div class="composerAttach" id="composerAttach" hidden></div>
<div class="emojiPanel" id="emojiPanel" hidden></div>
</div>
</section>
</main>
</div>
</main>
<div class="doors-container" id="doorsContainer" aria-hidden="true">
<div class="door left">
<div class="door-handle"></div>
</div>
<div class="door right">
<div class="door-handle"></div>
</div>
</div>
<div class="login-wrapper" id="loginWrapper">
<div class="login-card">
<h1>进入聊天室</h1>
<p>门已锁好,请验证身份进入</p>
<div class="gateTabs">
<button class="btn btnPrimary" id="gateTabLogin" type="button">登录</button>
<button class="btn" id="gateTabRegister" type="button">注册</button>
<button class="btn" id="gateTabGuest" type="button">游客登录</button>
</div>
</div>
</div>
<!-- 登录/注册/游客 模态框 -->
<div class="confirm" id="gateModal" hidden>
<div class="confirmCard gateModalCard">
<div class="gateModalHeader">
<div class="confirmTitle" id="gateModalTitle"></div>
<button class="btn iconBtn" id="gateModalClose" type="button" aria-label="关闭">
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 6 6 18" /><path d="M6 6l12 12" />
</svg>
</button>
</div>
<div class="error-msg" id="gateError"></div>
<form id="gateLoginForm" class="gatePanel" hidden>
<div class="input-group">
<label for="gateLoginUser">用户名</label>
<input id="gateLoginUser" autocomplete="username" />
</div>
<div class="input-group">
<label for="gateLoginPass">密码</label>
<input id="gateLoginPass" type="password" autocomplete="current-password" />
</div>
<button class="login-btn" type="submit">登录并进入</button>
<button class="link" type="button" id="forgotPasswordBtn">找回密码</button>
</form>
<form id="gateRegisterForm" class="gatePanel" hidden>
<div class="input-group">
<label for="gateRegUser">用户名</label>
<input id="gateRegUser" autocomplete="username" />
</div>
<div class="input-group">
<label for="gateRegPass">密码</label>
<input id="gateRegPass" type="password" autocomplete="new-password" />
</div>
<div class="input-group">
<label for="gateRegEmail">邮箱(选填)</label>
<input id="gateRegEmail" autocomplete="email" />
</div>
<div class="input-group">
<label for="gateRegQq">QQ选填</label>
<input id="gateRegQq" autocomplete="off" />
</div>
<div class="input-group">
<label for="gateRegPhone">联系电话(选填)</label>
<input id="gateRegPhone" autocomplete="tel" />
</div>
<button class="login-btn" type="submit">注册并进入</button>
</form>
<form id="gateGuestForm" class="gatePanel" hidden>
<input id="gateGuestUser" class="srOnly" name="username" autocomplete="username" tabindex="-1" />
<div class="hint" id="gateGuestNameHint"></div>
<div class="input-group">
<label for="gateGuestPass">聊天室密码(若已设置)</label>
<input id="gateGuestPass" type="password" autocomplete="current-password" />
<div class="hint" id="gateGuestHint"></div>
</div>
<button class="login-btn" type="submit">游客进入</button>
</form>
</div>
</div>
<!-- 找回密码模态框 -->
<div class="confirm" id="forgotModal" hidden>
<div class="confirmCard" style="width:min(480px,92vw)">
<div class="confirmTitle" id="forgotModalTitle">找回密码</div>
<!-- 步骤1 -->
<div id="forgotStep1" class="stack" style="margin-top:12px">
<div class="hint">请输入你的用户名,我们将向注册邮箱发送 6 位数字验证码。</div>
<div class="input-group">
<label for="forgotUsername">用户名</label>
<input id="forgotUsername" autocomplete="username" />
</div>
<div class="hint" id="forgotStep1Msg"></div>
<div class="row" style="justify-content:flex-end;margin-top:4px">
<button class="btn" id="forgotCancelBtn" type="button">取消</button>
<button class="btn btnPrimary" id="forgotSendBtn" type="button">发送验证码</button>
</div>
</div>
<!-- 步骤2 -->
<div id="forgotStep2" class="stack" style="margin-top:12px;display:none">
<div class="hint">请输入邮件中收到的 6 位数字验证码和新密码。验证码有效期 30 分钟。</div>
<div class="input-group">
<label for="forgotToken">验证码</label>
<input id="forgotToken" maxlength="6" pattern="[0-9]*" inputmode="numeric" autocomplete="one-time-code" />
</div>
<div class="input-group">
<label for="forgotNewPass">新密码</label>
<input id="forgotNewPass" type="password" autocomplete="new-password" />
</div>
<div class="hint" id="forgotStep2Msg"></div>
<div class="row" style="justify-content:flex-end;margin-top:4px">
<button class="btn" id="forgotBackBtn" type="button">返回</button>
<button class="btn btnPrimary" id="forgotResetBtn" type="button">重置密码</button>
</div>
</div>
</div>
</div>
<div class="imgViewer" id="imgViewer" hidden>
<div class="imgViewerBackdrop" id="imgViewerBackdrop"></div>
<img class="imgViewerImg" id="imgViewerImg" alt="图片预览" />
<button class="imgViewerClose" id="imgViewerClose" type="button">关闭</button>
</div>
<div class="toast" id="toast" hidden></div>
<div class="confirm" id="confirm" hidden>
<div class="confirmCard">
<div class="confirmTitle" id="confirmTitle"></div>
<div class="confirmMsg" id="confirmMsg"></div>
<div class="row" style="justify-content:flex-end">
<button class="btn" id="confirmCancel" type="button">取消</button>
<button class="btn btnPrimary" id="confirmOk" type="button">确定</button>
</div>
</div>
</div>
</div>
<script src="/app.js"></script>
</body>
</html>