diff --git a/src/app/chat/chat-screen.tsx b/src/app/chat/chat-screen.tsx
index 8ccb4629..bde90076 100644
--- a/src/app/chat/chat-screen.tsx
+++ b/src/app/chat/chat-screen.tsx
@@ -34,7 +34,6 @@ import { useFirstRechargeOfferBanner } from "./hooks/use-first-recharge-offer-ba
import { useChatUnlockNavigationFlow } from "./hooks/use-chat-unlock-navigation-flow";
import { useChatGuestLogin } from "./hooks/use-chat-guest-login";
import { useChatMessageLimitBanner } from "./hooks/use-chat-message-limit-banner";
-import { useExternalBrowserPrompt } from "./hooks/use-external-browser-prompt";
import styles from "./components/chat-screen.module.css";
export function ChatScreen() {
@@ -91,11 +90,6 @@ export function ChatScreen() {
loginStatus: authState.loginStatus,
});
const shouldShowPwaInstall = state.historyLoaded && state.messages.length >= 10;
- useExternalBrowserPrompt({
- hasInitialized: authState.hasInitialized,
- isLoading: authState.isLoading,
- loginStatus: authState.loginStatus,
- });
useChatGuestLogin({
dispatch: authDispatch,
diff --git a/src/app/chat/components/browser-hint-overlay.module.css b/src/app/chat/components/browser-hint-overlay.module.css
index 0104318b..d178f412 100644
--- a/src/app/chat/components/browser-hint-overlay.module.css
+++ b/src/app/chat/components/browser-hint-overlay.module.css
@@ -9,22 +9,54 @@
align-items: flex-end;
gap: var(--spacing-1, 4px);
z-index: 20;
- pointer-events: none;
+ max-width: min(52vw, 210px);
+ padding: 0;
+ border: 0;
+ background: transparent;
+ color: inherit;
+ cursor: pointer;
+ pointer-events: auto;
+ transition: opacity 0.16s ease, transform 0.16s ease;
+ -webkit-tap-highlight-color: transparent;
}
.emoji {
font-size: var(--responsive-icon-size-md, 24px);
line-height: 1;
+ filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.32));
}
.hintBubble {
padding: var(--spacing-2, 8px) var(--spacing-3, 12px);
- background: var(--color-blur-background, rgba(13, 11, 20, 0.85));
- border-radius: var(--radius-md, 8px);
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ border-radius: var(--radius-lg, 14px);
+ background:
+ linear-gradient(135deg, rgba(255, 255, 255, 0.11), rgba(255, 255, 255, 0.04)),
+ var(--color-blur-background, rgba(13, 11, 20, 0.84));
+ box-shadow:
+ 0 10px 24px rgba(0, 0, 0, 0.2),
+ inset 0 1px 0 rgba(255, 255, 255, 0.14);
font-size: var(--font-size-sm, 12px);
- font-weight: 500;
+ font-weight: 700;
+ line-height: 1.25;
color: #fff;
- white-space: pre-line;
backdrop-filter: blur(10px);
- max-width: min(52vw, 200px);
+ text-align: left;
+ white-space: pre-line;
+ overflow-wrap: break-word;
+}
+
+.overlay:hover {
+ opacity: 0.94;
+ transform: translateY(-1px);
+}
+
+.overlay:active {
+ opacity: 0.88;
+ transform: translateY(1px) scale(0.99);
+}
+
+.overlay:focus-visible {
+ outline: 2px solid rgba(255, 255, 255, 0.88);
+ outline-offset: 4px;
}
diff --git a/src/app/chat/components/browser-hint-overlay.tsx b/src/app/chat/components/browser-hint-overlay.tsx
index 27ab9663..44a57d6f 100644
--- a/src/app/chat/components/browser-hint-overlay.tsx
+++ b/src/app/chat/components/browser-hint-overlay.tsx
@@ -10,10 +10,11 @@
* 行为:
* - 开发环境始终显示(测试方便)
* - 生产环境仅在应用内浏览器中显示
- * - 视觉:右上角 👆 + 模糊背景气泡
+ * - 点击后主动打开外部浏览器
*/
import { useState } from "react";
+import { openChatInExternalBrowser } from "@/lib/chat/chat_external_browser";
import { BrowserDetector } from "@/utils";
import styles from "./browser-hint-overlay.module.css";
@@ -25,7 +26,7 @@ export interface BrowserHintOverlayProps {
forceShow?: boolean;
}
-const DEFAULT_TEXT = "Tap ⋮ , open in browser\nfor better chat";
+const DEFAULT_TEXT = "Open in external browser\nto find me easily";
export function BrowserHintOverlay({
text = DEFAULT_TEXT,
@@ -38,12 +39,20 @@ export function BrowserHintOverlay({
const shouldShow = forceShow || isInAppBrowser;
if (!shouldShow) return null;
+ const handleClick = (): void => {
+ void openChatInExternalBrowser().catch((error) => {
+ console.warn("[chat] Failed to open external browser", error);
+ });
+ };
+
return (
-
+
);
}
diff --git a/src/app/chat/hooks/use-external-browser-prompt.ts b/src/app/chat/hooks/use-external-browser-prompt.ts
deleted file mode 100644
index 3c6ab633..00000000
--- a/src/app/chat/hooks/use-external-browser-prompt.ts
+++ /dev/null
@@ -1,75 +0,0 @@
-"use client";
-
-import { useEffect, useRef } from "react";
-
-import {
- openChatInExternalBrowser,
- recordExternalBrowserPromptShown,
- resolveExternalBrowserPromptEligibility,
-} from "@/lib/chat/chat_external_browser";
-
-import {
- type ExternalBrowserPromptState,
- shouldStartExternalBrowserPrompt,
-} from "../chat-screen.helpers";
-
-const EXTERNAL_BROWSER_PROMPT_DELAY_MS = 3000;
-
-export function useExternalBrowserPrompt({
- hasInitialized,
- isLoading,
- loginStatus,
-}: ExternalBrowserPromptState): void {
- const promptShownRef = useRef(false);
-
- useEffect(() => {
- if (
- !shouldStartExternalBrowserPrompt({
- hasInitialized,
- isLoading,
- loginStatus,
- })
- ) {
- return;
- }
-
- let mounted = true;
- let timer: number | undefined;
-
- const init = async () => {
- if (promptShownRef.current) return;
-
- const eligibility = await resolveExternalBrowserPromptEligibility();
- if (!mounted || !eligibility.canShow) return;
-
- promptShownRef.current = true;
- timer = window.setTimeout(() => {
- if (!mounted) return;
- void (async () => {
- try {
- await recordExternalBrowserPromptShown(eligibility.today);
- } catch (error) {
- console.warn(
- "[chat] Failed to record external browser auto launch",
- error,
- );
- }
- if (!mounted) return;
- try {
- await openChatInExternalBrowser();
- } catch (error) {
- console.warn("[chat] Failed to open external browser", error);
- }
- })();
- }, EXTERNAL_BROWSER_PROMPT_DELAY_MS);
- };
-
- void init();
-
- return () => {
- mounted = false;
- if (timer !== undefined) window.clearTimeout(timer);
- };
- }, [hasInitialized, isLoading, loginStatus]);
-
-}
diff --git a/src/data/storage/app/app_storage.ts b/src/data/storage/app/app_storage.ts
index 6916b036..d953e41d 100644
--- a/src/data/storage/app/app_storage.ts
+++ b/src/data/storage/app/app_storage.ts
@@ -41,26 +41,6 @@ export class AppStorage {
return SpAsyncUtil.setBool(StorageKeys.pwaDialogShown, true);
}
- // ---- external browser dialog ----
-
- static async canShowExternalBrowserDialog(
- todayString: string,
- ): Promise> {
- return AppStorage.canReportKey(
- StorageKeys.lastExternalBrowserDialogShown,
- todayString,
- );
- }
-
- static recordExternalBrowserDialogShown(
- todayString: string,
- ): Promise> {
- return SpAsyncUtil.setString(
- StorageKeys.lastExternalBrowserDialogShown,
- todayString,
- );
- }
-
// ---- PWA event reporting ----
static canReportPwaEvent(todayString: string): Promise> {
diff --git a/src/data/storage/storage_keys.ts b/src/data/storage/storage_keys.ts
index fbba197d..693640a0 100644
--- a/src/data/storage/storage_keys.ts
+++ b/src/data/storage/storage_keys.ts
@@ -29,7 +29,6 @@ export const StorageKeys = {
// pwa / app info
pwaDialogShown: "pwa_dialog_shown",
- lastExternalBrowserDialogShown: "last_external_browser_dialog_shown",
lastPwaEventReported: "last_pwa_event_reported",
lastAppInfoReported: "last_app_info_reported",
firstRechargeOfferBannerDismissed: "first_recharge_offer_banner_dismissed",
diff --git a/src/lib/chat/chat_external_browser.ts b/src/lib/chat/chat_external_browser.ts
index fe3c2d27..e5c3b0fd 100644
--- a/src/lib/chat/chat_external_browser.ts
+++ b/src/lib/chat/chat_external_browser.ts
@@ -1,28 +1,9 @@
"use client";
-import { AppStorage } from "@/data/storage/app/app_storage";
import { AuthStorage } from "@/data/storage/auth/auth_storage";
import { UserStorage } from "@/data/storage/user/user_storage";
import { ROUTES } from "@/router/routes";
-import { todayString, UrlLauncherUtil } from "@/utils";
-
-export async function resolveExternalBrowserPromptEligibility(): Promise<{
- canShow: boolean;
- today: string;
-}> {
- const today = todayString();
- const result = await AppStorage.canShowExternalBrowserDialog(today);
- return {
- canShow: result.success && result.data,
- today,
- };
-}
-
-export function recordExternalBrowserPromptShown(
- today: string,
-): Promise {
- return AppStorage.recordExternalBrowserDialogShown(today);
-}
+import { UrlLauncherUtil } from "@/utils";
export async function openChatInExternalBrowser(): Promise {
const authStorage = AuthStorage.getInstance();