diff --git a/src/components/ChatView.tsx b/src/components/ChatView.tsx
index 06fba9e..dc72ee9 100644
--- a/src/components/ChatView.tsx
+++ b/src/components/ChatView.tsx
@@ -4,6 +4,7 @@ import { INSUFFICIENT_BALANCE_NOTICE } from '../hooks/useTKMindChat';
import type { CapabilityMap, PortalUser, SessionSummary } from '../types';
import { useNetworkStatus } from '../hooks/useNetworkStatus';
import { getSessionDisplayName } from '../utils/sessions';
+import { isH5OrWechatClient } from '../utils/wechat';
import { BalanceRing } from './BalanceRing';
import { HistorySidebar } from './HistorySidebar';
import { TKMindAvatar } from './TKMindAvatar';
@@ -24,6 +25,7 @@ function RecentSessionRail({
loadingMore,
hasMore,
chipWidth,
+ variant = 'inline',
onSelect,
onLoadMore,
}: {
@@ -34,6 +36,7 @@ function RecentSessionRail({
loadingMore: boolean;
hasMore: boolean;
chipWidth?: number | null;
+ variant?: 'inline' | 'floating';
onSelect: (session: SessionSummary) => void;
onLoadMore: () => void;
}) {
@@ -91,12 +94,14 @@ function RecentSessionRail({
if (!loading && recentSessions.length === 0) return null;
+ const isFloating = variant === 'floating';
+
return (
0
+ !isFloating && chipWidth && chipWidth > 0
? ({ ['--header-session-chip-width' as string]: `${chipWidth}px` })
: undefined
}
@@ -285,11 +290,6 @@ export function ChatView({
: pendingSessionTitle;
const moreMenuItems = [
- {
- id: 'new-session',
- label: '新会话',
- onClick: () => void handleNewSession(),
- },
...(onOpenAdmin
? [{ id: 'admin', label: '管理', onClick: () => onOpenAdmin() }]
: []),
@@ -298,8 +298,21 @@ export function ChatView({
: []),
];
+ const useFloatingSessionRail = useMemo(() => isH5OrWechatClient(), []);
+
+ const recentSessionRailProps = {
+ sessions,
+ activeSessionId: session?.id,
+ armedSessionId,
+ loading: sessionsLoading,
+ loadingMore: sessionsLoadingMore,
+ hasMore: sessionsHasMore,
+ onSelect: handleRecentSessionSelect,
+ onLoadMore: () => void loadMoreSessions(),
+ };
+
return (
-
+
-
-
-
-
-
-
{user?.displayName ?? 'TKMind'}
-
- {isConnectingTitle ?
: null}
-
{sessionTitle}
+
+
+
+
+
+
+
{user?.displayName ?? 'TKMind'}
+
+ {isConnectingTitle ? : null}
+ {sessionTitle}
+
-
-
-
void loadMoreSessions()}
- />
+
+ {!useFloatingSessionRail && (
+
+ )}
{typeof balanceCents === 'number' && (
)}
openRecharge(false)} />
+
{onOpenAdmin && (
)}
-
{user && }
{onLogout && (
-
void loadMoreSessions()}
- />
+ {!useFloatingSessionRail && (
+
+ )}
{typeof balanceCents === 'number' && (
)}
openRecharge(false)} />
+
{onOpenSpace && (
+ {useFloatingSessionRail && (
+
+ )}
+
{!online && (
网络已断开,请检查连接后重试
diff --git a/src/index.css b/src/index.css
index 6489626..2e4bfe7 100644
--- a/src/index.css
+++ b/src/index.css
@@ -645,6 +645,56 @@ body,
background: rgba(255, 255, 255, 0.03);
}
+.header-shell-sticky {
+ position: sticky;
+ top: 0;
+ z-index: 2;
+}
+
+.header-shell-sticky .header {
+ position: static;
+ top: auto;
+ z-index: auto;
+ border-bottom: none;
+}
+
+.app-shell-h5 .header-session-rail-floating {
+ display: flex;
+ align-items: center;
+ gap: 0;
+ width: 100%;
+ max-width: none;
+ flex: none;
+ padding: 8px 12px;
+ box-sizing: border-box;
+ background: var(--color-bg-base);
+ border-bottom: 1px solid var(--color-border);
+ -webkit-overflow-scrolling: touch;
+}
+
+.app-shell-h5 .header-shell-sticky:has(.header-home) .header-session-rail-floating {
+ background: rgba(12, 18, 30, 0.72);
+ backdrop-filter: blur(14px);
+ border-bottom-color: rgba(103, 123, 156, 0.18);
+}
+
+.app-shell-h5 .header-session-rail-floating .header-session-rail-arrow {
+ display: none;
+}
+
+.app-shell-h5 .header-session-rail-floating .header-session-rail-track {
+ --header-session-chip-width: calc((100% - 16px) / 3);
+ grid-auto-columns: calc((100% - 16px) / 3);
+ gap: 8px;
+ width: 100%;
+ touch-action: pan-x;
+}
+
+.app-shell-h5 .header-session-rail-floating .header-session-chip {
+ min-height: 34px;
+ padding: 6px 8px;
+}
+
.header-icon-btn {
display: flex;
align-items: center;
diff --git a/src/utils/wechat.ts b/src/utils/wechat.ts
index 449c2ea..5a0bc09 100644
--- a/src/utils/wechat.ts
+++ b/src/utils/wechat.ts
@@ -89,6 +89,15 @@ export function isWechatContext(options?: {
return isWechatEntryUrl(options?.search);
}
+/** 手机 H5 或微信内置浏览器:导航会话标签采用下方悬浮条布局 */
+export function isH5OrWechatClient(options?: {
+ userAgent?: string;
+ search?: string;
+ serverInWechat?: boolean;
+}) {
+ return isMobileBrowser(options?.userAgent) || isWechatContext(options);
+}
+
export function buildWechatAuthorizeUrl(options?: {
returnTo?: string;
utmSource?: string;