feat: add social hub pages, invites, and generic LLM compatibility

This commit is contained in:
leeexin committed 2026-03-08 17:06:02 +08:00
1 parent e1459b1a34
commit 2e9fc28d2c
20 files changed
+1736 -160

No files matched your search

+1
View File
@@ -70,6 +70,7 @@
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/admin.js') }}"></script>
</body>
</html>
+1
View File
@@ -230,6 +230,7 @@
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/card_editor.js') }}"></script>
</body>
</html>
+4 -10
View File
@@ -20,6 +20,8 @@
{% if user.role == 'admin' %}
<a class="link-btn" href="{{ url_for('admin_page') }}">管理后台</a>
{% endif %}
<a class="link-btn" href="{{ url_for('rooms_page') }}">联机大厅</a>
<a class="link-btn" href="{{ url_for('leaderboard_page') }}">玩家排行</a>
<a class="link-btn" href="{{ url_for('plaza_page') }}">游戏卡广场</a>
<button id="logout-btn" class="ghost-btn" type="button">退出登录</button>
{% else %}
@@ -51,21 +53,12 @@
<input id="join-room" name="room_id" maxlength="6" placeholder="例如:A1B2C3" required />
<button type="submit">加入游戏</button>
</form>
<p class="helper-text">将使用用户名加入。支持断线重连:输入同房间码会优先恢复你在该房间的身份。</p>
<p class="helper-text">将使用用户名加入。支持断线重连:输入同房间码会优先恢复你在该房间的身份。公开房间列表请前往“联机大厅”。</p>
</section>
<section class="card">
<h2>快速重连</h2>
<ul id="rejoin-list" class="compact-list"></ul>
<h2 style="margin-top: 1rem;">玩家排行榜</h2>
<p class="helper-text">按胜场、参与局数和回合数综合排序。</p>
<ul id="leaderboard-list" class="compact-list"></ul>
</section>
<section class="card">
<h2>联机大厅</h2>
<p class="helper-text">房主公开后的房间会显示在这里,可直接加入或观战。</p>
<ul id="public-rooms-list" class="compact-list"></ul>
</section>
<section class="card" id="profile-card">
@@ -104,6 +97,7 @@
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/lobby.js') }}"></script>
</body>
</html>
+42
View File
@@ -0,0 +1,42 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>玩家排行榜 - Echo Tavern</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
</head>
<body class="leaderboard-page" data-user='{{ user | tojson | safe if user else "null" }}' data-theme="{{ user.theme if user else 'dopamine' }}">
<header class="lobby-topbar">
<div class="brand-block">
<h1>玩家排行榜</h1>
<p>按胜场、参与局数和总回合综合排序,点击用户名可查看个人主页。</p>
</div>
<div class="top-actions">
<a class="link-btn" href="{{ url_for('rooms_page') }}">联机大厅</a>
<a class="link-btn" href="{{ url_for('index') }}">返回大厅</a>
</div>
</header>
<main class="plaza-grid">
<section class="card">
<h2>排行榜</h2>
<div id="leaderboard-list" class="table-wrap"></div>
</section>
<section class="card">
<h2>搜索用户</h2>
<form id="search-form">
<label for="search-input">用户名或显示名</label>
<input id="search-input" maxlength="40" placeholder="例如:alice" />
<button type="submit" class="secondary-btn">搜索</button>
</form>
<ul id="search-results" class="compact-list" style="margin-top: 0.8rem;"></ul>
</section>
</main>
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/leaderboard.js') }}"></script>
</body>
</html>
+3
View File
@@ -16,6 +16,8 @@
{% if user and user.role == 'admin' %}
<a class="link-btn" href="{{ url_for('admin_page') }}">管理后台</a>
{% endif %}
<a class="link-btn" href="{{ url_for('leaderboard_page') }}">玩家排行</a>
<a class="link-btn" href="{{ url_for('rooms_page') }}">联机大厅</a>
{% if user %}
<a class="link-btn" href="{{ url_for('card_new_page') }}">新建游戏卡</a>
{% endif %}
@@ -47,6 +49,7 @@
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/plaza.js') }}"></script>
</body>
</html>
+1
View File
@@ -156,6 +156,7 @@
<script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/room.js') }}"></script>
</body>
</html>
+50
View File
@@ -0,0 +1,50 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>联机大厅 - Echo Tavern</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
</head>
<body class="lobby-page" data-user='{{ user | tojson | safe if user else "null" }}' data-theme="{{ user.theme if user else 'dopamine' }}">
<header class="lobby-topbar">
<div class="brand-block">
<h1>联机大厅</h1>
<p>查看公开房间、输入房间码加入、快速重连你参与过的对局。</p>
</div>
<div class="top-actions">
<a class="link-btn" href="{{ url_for('leaderboard_page') }}">玩家排行</a>
<a class="link-btn" href="{{ url_for('plaza_page') }}">游戏卡广场</a>
<a class="link-btn" href="{{ url_for('index') }}">返回主页</a>
</div>
</header>
<main class="lobby-grid">
<section class="card">
<h2>加入房间</h2>
<form id="join-form">
<label for="join-room">房间码</label>
<input id="join-room" name="room_id" maxlength="6" placeholder="例如:A1B2C3" required />
<button type="submit">加入游戏</button>
</form>
<p class="helper-text">进行中的房间会自动进入观战或身份恢复。</p>
</section>
<section class="card">
<h2>快速重连</h2>
<ul id="rejoin-list" class="compact-list"></ul>
</section>
<section class="card">
<h2>公开房间</h2>
<p class="helper-text">房主设为公开后会显示在这里,可直接加入。</p>
<ul id="public-rooms-list" class="compact-list"></ul>
</section>
</main>
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/rooms.js') }}"></script>
</body>
</html>
+45
View File
@@ -0,0 +1,45 @@
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>个人主页 - Echo Tavern</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}" />
</head>
<body class="user-profile-page"
data-user='{{ user | tojson | safe if user else "null" }}'
data-theme="{{ user.theme if user else 'dopamine' }}"
data-profile-username="{{ profile_username }}">
<header class="lobby-topbar">
<div class="brand-block">
<h1>个人主页</h1>
<p id="profile-subtitle">加载中...</p>
</div>
<div class="top-actions">
<a class="link-btn" href="{{ url_for('rooms_page') }}">联机大厅</a>
<a class="link-btn" href="{{ url_for('leaderboard_page') }}">返回排行</a>
<a class="link-btn" href="{{ url_for('index') }}">返回大厅</a>
</div>
</header>
<main class="plaza-grid">
<section class="card">
<h2>用户信息</h2>
<div id="profile-hero" class="profile-hero"></div>
<div id="profile-meta" class="status-grid" style="margin-top: 0.8rem;"></div>
</section>
<section class="card">
<h2>邀请互动</h2>
<div id="invite-panel"></div>
<h2 style="margin-top: 1rem;">最近参与房间</h2>
<ul id="recent-rooms" class="compact-list"></ul>
</section>
</main>
<section id="status" class="status-banner"></section>
<script src="{{ url_for('static', filename='js/theme.js') }}"></script>
<script src="{{ url_for('static', filename='js/invite_notify.js') }}"></script>
<script src="{{ url_for('static', filename='js/user_profile.js') }}"></script>
</body>
</html>