style(chat): clarify external browser CTA
This commit is contained in:
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user