style(chat): clarify external browser CTA

This commit is contained in:
2026-07-09 15:22:27 +08:00
parent dfa5b0c068
commit 48b74d1d62
2 changed files with 86 additions and 36 deletions
@@ -4,49 +4,85 @@
position: absolute; position: absolute;
top: var(--spacing-2, 8px); top: var(--spacing-2, 8px);
right: var(--spacing-2, 8px); right: var(--spacing-2, 8px);
display: flex; display: grid;
flex-direction: column; grid-template-columns: auto minmax(0, 1fr) auto;
align-items: flex-end; align-items: center;
gap: var(--spacing-1, 4px); gap: 8px;
z-index: 20; z-index: 20;
max-width: min(52vw, 210px); max-width: min(74vw, 260px);
padding: 0; min-height: 48px;
border: 0; padding: 8px 10px;
background: transparent; border: 1px solid rgba(255, 255, 255, 0.18);
color: inherit; border-radius: 18px;
background:
linear-gradient(135deg, rgba(255, 255, 255, 0.14), rgba(255, 255, 255, 0.04)),
var(--color-blur-background, rgba(13, 11, 20, 0.86));
box-shadow:
0 12px 28px rgba(0, 0, 0, 0.24),
inset 0 1px 0 rgba(255, 255, 255, 0.16);
color: #fff;
cursor: pointer; cursor: pointer;
pointer-events: auto; pointer-events: auto;
transition: opacity 0.16s ease, transform 0.16s ease; backdrop-filter: blur(12px);
transition: border-color 0.16s ease, box-shadow 0.16s ease,
opacity 0.16s ease, transform 0.16s ease;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
} }
.emoji { .iconWrap {
font-size: var(--responsive-icon-size-md, 24px); display: inline-flex;
line-height: 1; width: 30px;
filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.32)); height: 30px;
align-items: center;
justify-content: center;
border-radius: 999px;
background: rgba(255, 255, 255, 0.15);
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.16);
color: #fff;
} }
.hintBubble { .copy {
padding: var(--spacing-2, 8px) var(--spacing-3, 12px); display: flex;
border: 1px solid rgba(255, 255, 255, 0.18); min-width: 0;
border-radius: var(--radius-lg, 14px); flex-direction: column;
background: gap: 2px;
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: 700;
line-height: 1.25;
color: #fff;
backdrop-filter: blur(10px);
text-align: left; text-align: left;
white-space: pre-line; }
.title {
color: #fff;
font-size: var(--font-size-sm, 12px);
font-weight: 800;
line-height: 1.25;
overflow-wrap: break-word; overflow-wrap: break-word;
} }
.description {
color: rgba(255, 255, 255, 0.72);
font-size: 11px;
font-weight: 650;
line-height: 1.2;
overflow-wrap: break-word;
}
.arrow {
display: inline-flex;
width: 18px;
height: 18px;
align-items: center;
justify-content: center;
color: #fff;
font-size: 15px;
font-weight: 800;
line-height: 1;
opacity: 0.86;
}
.overlay:hover { .overlay:hover {
border-color: rgba(255, 255, 255, 0.28);
box-shadow:
0 14px 32px rgba(0, 0, 0, 0.28),
inset 0 1px 0 rgba(255, 255, 255, 0.18);
opacity: 0.94; opacity: 0.94;
transform: translateY(-1px); transform: translateY(-1px);
} }
@@ -13,6 +13,7 @@
* - 点击后主动打开外部浏览器 * - 点击后主动打开外部浏览器
*/ */
import { useState } from "react"; import { useState } from "react";
import { ExternalLink } from "lucide-react";
import { openChatInExternalBrowser } from "@/lib/chat/chat_external_browser"; import { openChatInExternalBrowser } from "@/lib/chat/chat_external_browser";
import { BrowserDetector } from "@/utils"; import { BrowserDetector } from "@/utils";
@@ -20,16 +21,20 @@ import { BrowserDetector } from "@/utils";
import styles from "./browser-hint-overlay.module.css"; import styles from "./browser-hint-overlay.module.css";
export interface BrowserHintOverlayProps { export interface BrowserHintOverlayProps {
/** 自定义提示文本 */ /** 自定义按钮标题 */
text?: string; title?: string;
/** 自定义按钮说明 */
description?: string;
/** 强制显示(开发模式测试用) */ /** 强制显示(开发模式测试用) */
forceShow?: boolean; forceShow?: boolean;
} }
const DEFAULT_TEXT = "Open in external browser\nto find me easily"; const DEFAULT_TITLE = "Open in external browser";
const DEFAULT_DESCRIPTION = "Find me more easily";
export function BrowserHintOverlay({ export function BrowserHintOverlay({
text = DEFAULT_TEXT, title = DEFAULT_TITLE,
description = DEFAULT_DESCRIPTION,
forceShow = false, forceShow = false,
}: BrowserHintOverlayProps) { }: BrowserHintOverlayProps) {
// lazy initializer:首次渲染即计算(避免 useEffect 中调 setState 的 lint 错) // lazy initializer:首次渲染即计算(避免 useEffect 中调 setState 的 lint 错)
@@ -49,10 +54,19 @@ export function BrowserHintOverlay({
<button <button
type="button" type="button"
className={styles.overlay} className={styles.overlay}
aria-label={text} aria-label={`${title}. ${description}`}
onClick={handleClick} onClick={handleClick}
> >
<span className={styles.hintBubble}>{text}</span> <span className={styles.iconWrap} aria-hidden="true">
<ExternalLink size={15} strokeWidth={2.4} />
</span>
<span className={styles.copy}>
<span className={styles.title}>{title}</span>
<span className={styles.description}>{description}</span>
</span>
<span className={styles.arrow} aria-hidden="true">
</span>
</button> </button>
); );
} }