mirror of
https://wget.la/https://github.com/Wxw-Gu/WechatExplorer
synced 2026-08-17 19:47:08 +08:00
feat: 重构README 新增引导功能
This commit is contained in:
@@ -20,6 +20,7 @@ import { AiModelConfig, useGroupReportGeneration } from './hooks/useGroupReportG
|
||||
import { SummaryDateRange, SummaryMessageType } from './utils/group-report'
|
||||
import { Contact, Message } from '../../shared/types'
|
||||
import { DatabaseConnectionMode, DatabaseConnectionPage } from './components/DatabaseConnectionPage'
|
||||
import { FirstUseWelcome } from './components/FirstUseWelcome'
|
||||
import { ExportWorkspace } from './components/export/ExportWorkspace'
|
||||
import { AISearchWorkspace } from './components/search/AISearchWorkspace'
|
||||
import type { ExportJobProgress, ExportRequest, ExportTaskRecord } from '../../shared/export'
|
||||
@@ -39,7 +40,8 @@ interface SelfInfo {
|
||||
accountRoot: string
|
||||
}
|
||||
|
||||
const MAC_KEY_FAQ_URL = 'https://github.com/hicccc77/WeFlow/blob/main/docs/MAC-KEY-FAQ.md'
|
||||
const MAC_KEY_FAQ_URL = 'https://github.com/Wxw-Gu/WechatExplorer/blob/main/docs/mac-disable-sip.md'
|
||||
const FIRST_USE_WELCOME_SEEN_KEY = 'wxe_first_use_welcome_seen'
|
||||
const MESSAGE_MONITOR_DEBOUNCE_MS = 8000
|
||||
const INITIAL_MESSAGE_COUNT = 20
|
||||
const MESSAGE_PAGE_SIZE = 100
|
||||
@@ -256,6 +258,7 @@ function App(): React.ReactElement {
|
||||
const [bootState, setBootState] = useState<'loading' | 'connecting' | 'login'>('loading')
|
||||
const [autoConnectSource, setAutoConnectSource] = useState<'env' | 'saved' | null>(null)
|
||||
const [startupProgress, setStartupProgress] = useState<StartupProgress | null>(null)
|
||||
const [showFirstUseWelcome, setShowFirstUseWelcome] = useState(false)
|
||||
const [appearanceSettings, setAppearanceSettings] = React.useState<{
|
||||
theme: 'system' | 'light' | 'dark'
|
||||
compactMode: boolean
|
||||
@@ -728,6 +731,7 @@ function App(): React.ReactElement {
|
||||
})
|
||||
setIsDatabaseConnected(true)
|
||||
setBootState('login')
|
||||
maybeShowFirstUseWelcome()
|
||||
window.setTimeout(() => {
|
||||
setStartupProgress(null)
|
||||
}, 500)
|
||||
@@ -1222,6 +1226,45 @@ function App(): React.ReactElement {
|
||||
setActivePage('settings')
|
||||
}
|
||||
|
||||
const dismissFirstUseWelcome = (): void => {
|
||||
try {
|
||||
localStorage.setItem(FIRST_USE_WELCOME_SEEN_KEY, '1')
|
||||
} catch {
|
||||
// The welcome prompt is optional and should not interrupt normal use.
|
||||
}
|
||||
setShowFirstUseWelcome(false)
|
||||
}
|
||||
|
||||
const maybeShowFirstUseWelcome = (): void => {
|
||||
try {
|
||||
if (localStorage.getItem(FIRST_USE_WELCOME_SEEN_KEY) === '1') return
|
||||
} catch {
|
||||
// If localStorage is unavailable, still show the one-time prompt for this session.
|
||||
}
|
||||
setShowFirstUseWelcome(true)
|
||||
}
|
||||
|
||||
const openFirstUseSearch = (): void => {
|
||||
dismissFirstUseWelcome()
|
||||
setActivePage('search')
|
||||
}
|
||||
|
||||
const openFirstUseReport = (): void => {
|
||||
dismissFirstUseWelcome()
|
||||
setReportWorkspaceView('configure')
|
||||
setSelectedReportId(null)
|
||||
setActivePage('report')
|
||||
}
|
||||
|
||||
const openFirstUseAISettings = (): void => {
|
||||
dismissFirstUseWelcome()
|
||||
openModelSettings()
|
||||
}
|
||||
|
||||
const openFirstUseGuide = (): void => {
|
||||
setShowFirstUseWelcome(true)
|
||||
}
|
||||
|
||||
const openReport = (reportId: string): void => {
|
||||
setSelectedReportId(reportId)
|
||||
setReportWorkspaceView('result')
|
||||
@@ -1651,10 +1694,19 @@ function App(): React.ReactElement {
|
||||
dbReady={isDatabaseConnected}
|
||||
onPageChange={handlePageChange}
|
||||
onOpenSettings={openSettings}
|
||||
onOpenGuide={openFirstUseGuide}
|
||||
appearanceTheme={appearanceSettings.theme}
|
||||
compactMode={appearanceSettings.compactMode}
|
||||
>
|
||||
{reportNotice && <div className="app-toast">{reportNotice}</div>}
|
||||
{showFirstUseWelcome && (
|
||||
<FirstUseWelcome
|
||||
onDismiss={dismissFirstUseWelcome}
|
||||
onOpenSearch={openFirstUseSearch}
|
||||
onOpenReport={openFirstUseReport}
|
||||
onOpenAISettings={openFirstUseAISettings}
|
||||
/>
|
||||
)}
|
||||
{renderCurrentWorkspace()}
|
||||
</AppShell>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import React from 'react'
|
||||
|
||||
const GUIDE_URL =
|
||||
'https://github.com/Wxw-Gu/WechatExplorer/blob/main/docs/user-guide/getting-started.md'
|
||||
|
||||
export type DatabaseConnectionMode = 'automatic' | 'manual'
|
||||
export type DatabaseConnectionStatusKind = 'normal' | 'success' | 'error'
|
||||
|
||||
@@ -116,9 +119,9 @@ export function DatabaseConnectionPage({
|
||||
<LineIcon name="database" />
|
||||
</div>
|
||||
<h1>WechatExplorer</h1>
|
||||
<p className="database-login-tagline">你的本地微信聊天档案</p>
|
||||
<p className="database-login-tagline">让 AI 读懂你的微信</p>
|
||||
<p className="database-login-description">
|
||||
连接本机微信数据库,开始检索、整理和分析聊天记录。
|
||||
连接成功后,你可以搜索聊天记录、生成群聊日报,并按需使用 AI 分析。
|
||||
</p>
|
||||
<div className="database-login-promises">
|
||||
<div>
|
||||
@@ -131,7 +134,7 @@ export function DatabaseConnectionPage({
|
||||
</div>
|
||||
<div>
|
||||
<LineIcon name="cloud" />
|
||||
<span>不会上传</span>
|
||||
<span>AI 按需启用</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -140,6 +143,42 @@ export function DatabaseConnectionPage({
|
||||
|
||||
<section className="database-login-workspace" aria-label="数据库连接">
|
||||
<div className="database-login-panel">
|
||||
<div className="database-login-start">
|
||||
<p className="database-login-eyebrow">第一次使用</p>
|
||||
<h2>开始连接微信</h2>
|
||||
<p>跟着下面 3 步操作,通常几分钟即可完成连接。</p>
|
||||
<ol>
|
||||
<li>
|
||||
<span>1</span>
|
||||
<div>
|
||||
<strong>确认微信数据目录</strong>
|
||||
<small>没有自动找到时,可在设置中手动选择</small>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>2</span>
|
||||
<div>
|
||||
<strong>让微信停在登录页面</strong>
|
||||
<small>不要在获取密钥前完成登录</small>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<span>3</span>
|
||||
<div>
|
||||
<strong>点击自动获取密钥</strong>
|
||||
<small>提示可以登录后,再回到微信完成登录</small>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
<a
|
||||
className="database-login-guide-link"
|
||||
href={GUIDE_URL}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
查看 5 分钟上手教程 →
|
||||
</a>
|
||||
</div>
|
||||
<div className="database-login-tabs" role="tablist" aria-label="连接方式">
|
||||
<button
|
||||
type="button"
|
||||
@@ -148,16 +187,16 @@ export function DatabaseConnectionPage({
|
||||
className={mode === 'automatic' ? 'active' : ''}
|
||||
onClick={() => onModeChange('automatic')}
|
||||
>
|
||||
自动获取
|
||||
开始连接
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
role="tab"
|
||||
aria-selected={mode === 'manual'}
|
||||
className={mode === 'manual' ? 'active' : ''}
|
||||
className={`database-login-manual-tab ${mode === 'manual' ? 'active' : ''}`}
|
||||
onClick={() => onModeChange('manual')}
|
||||
>
|
||||
手动输入
|
||||
高级用户:已有数据库密钥?手动连接
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -219,20 +258,31 @@ export function DatabaseConnectionPage({
|
||||
onClick={onAutoGetKey}
|
||||
disabled={isFetching}
|
||||
>
|
||||
{isFetching
|
||||
? '正在获取密钥…'
|
||||
: statusKind === 'error'
|
||||
? '重新检测'
|
||||
: '自动获取密钥'}
|
||||
{isFetching ? '正在获取密钥…' : statusKind === 'error' ? '重新检测' : '开始获取'}
|
||||
</button>
|
||||
{showMacKeyFaq && (
|
||||
<p className="database-login-platform-note">
|
||||
{isMac ? (
|
||||
<>
|
||||
macOS 首次获取密钥需要关闭 SIP。{' '}
|
||||
<a href={macKeyFaqUrl} target="_blank" rel="noreferrer">
|
||||
查看说明
|
||||
</a>
|
||||
</>
|
||||
) : (
|
||||
'Windows 已完整支持,不需要关闭 SIP。'
|
||||
)}
|
||||
</p>
|
||||
{showMacKeyFaq && isMac && (
|
||||
<a href={macKeyFaqUrl} target="_blank" rel="noreferrer">
|
||||
查看详情 · 连接帮助
|
||||
获取失败?查看连接排查
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="database-login-manual" role="tabpanel">
|
||||
<p className="database-login-manual-note">
|
||||
仅适用于已经通过其他方式获得当前微信账号数据库密钥的高级用户。第一次使用请返回“开始连接”。
|
||||
</p>
|
||||
<div className="database-login-field">
|
||||
<label htmlFor="database-login-key">数据库密钥</label>
|
||||
<div className="database-login-key-input">
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
import React from 'react'
|
||||
|
||||
interface FirstUseWelcomeProps {
|
||||
onDismiss: () => void
|
||||
onOpenSearch: () => void
|
||||
onOpenReport: () => void
|
||||
onOpenAISettings: () => void
|
||||
}
|
||||
|
||||
const GUIDE_URL =
|
||||
'https://github.com/Wxw-Gu/WechatExplorer/blob/main/docs/user-guide/getting-started.md'
|
||||
|
||||
export function FirstUseWelcome({
|
||||
onDismiss,
|
||||
onOpenSearch,
|
||||
onOpenReport,
|
||||
onOpenAISettings
|
||||
}: FirstUseWelcomeProps): React.ReactElement {
|
||||
return (
|
||||
<div className="first-use-welcome-overlay" role="presentation">
|
||||
<section
|
||||
className="first-use-welcome"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-labelledby="first-use-welcome-title"
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className="first-use-welcome-close"
|
||||
onClick={onDismiss}
|
||||
aria-label="关闭欢迎提示"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
<div className="first-use-welcome-mark" aria-hidden="true">
|
||||
✦
|
||||
</div>
|
||||
<p className="first-use-welcome-eyebrow">微信已连接</p>
|
||||
<h2 id="first-use-welcome-title">开始探索你的微信</h2>
|
||||
<p className="first-use-welcome-lead">
|
||||
最关键的一步已经完成。现在,让 AI 帮你看看最近的聊天都发生了什么。
|
||||
</p>
|
||||
|
||||
<button type="button" className="first-use-welcome-feature" onClick={onOpenReport}>
|
||||
<span className="first-use-welcome-feature-icon" aria-hidden="true">
|
||||
✦
|
||||
</span>
|
||||
<span className="first-use-welcome-feature-copy">
|
||||
<strong>试试 AI 群聊日报</strong>
|
||||
<small>选择一个群聊,看看最近聊了什么</small>
|
||||
</span>
|
||||
<span className="first-use-welcome-feature-arrow" aria-hidden="true">
|
||||
立即体验 →
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<div className="first-use-welcome-secondary-actions">
|
||||
<button type="button" onClick={onDismiss}>
|
||||
查看聊天记录
|
||||
</button>
|
||||
<button type="button" onClick={onOpenSearch}>
|
||||
问问你的微信
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="first-use-welcome-footer">
|
||||
<span>还没有配置 AI?</span>
|
||||
<button type="button" onClick={onOpenAISettings}>
|
||||
配置 AI 模型
|
||||
</button>
|
||||
<a href={GUIDE_URL} target="_blank" rel="noreferrer">
|
||||
查看完整使用教程
|
||||
</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -17,6 +17,7 @@ interface AppShellProps {
|
||||
dbReady: boolean
|
||||
onPageChange: (page: AppPage) => void
|
||||
onOpenSettings: () => void
|
||||
onOpenGuide: () => void
|
||||
appearanceTheme?: 'system' | 'light' | 'dark'
|
||||
compactMode?: boolean
|
||||
children: React.ReactNode
|
||||
@@ -36,6 +37,7 @@ export function AppShell({
|
||||
dbReady,
|
||||
onPageChange,
|
||||
onOpenSettings,
|
||||
onOpenGuide,
|
||||
appearanceTheme = 'system',
|
||||
compactMode = false,
|
||||
children
|
||||
@@ -47,6 +49,19 @@ export function AppShell({
|
||||
<aside className="app-primary-rail">
|
||||
<BrandLogo />
|
||||
<PrimaryNavigation activePage={activePage} onPageChange={onPageChange} />
|
||||
<button
|
||||
type="button"
|
||||
className="app-guide-launcher"
|
||||
onClick={onOpenGuide}
|
||||
title="重新打开新手引导"
|
||||
>
|
||||
<span className="app-guide-launcher-icon" aria-hidden="true">
|
||||
<svg viewBox="0 0 24 24" focusable="false">
|
||||
<path d="M12 3 14.2 9.8 21 12l-6.8 2.2L12 21l-2.2-6.8L3 12l6.8-2.2L12 3Z" />
|
||||
</svg>
|
||||
</span>
|
||||
<span className="app-guide-launcher-label">新手引导</span>
|
||||
</button>
|
||||
<div className="app-rail-account">
|
||||
<AccountSummary selfInfo={selfInfo} dbReady={dbReady} compact onClick={onOpenSettings} />
|
||||
</div>
|
||||
|
||||
@@ -7,7 +7,7 @@ export interface NavigationItem {
|
||||
|
||||
export const PRIMARY_NAV_ITEMS: NavigationItem[] = [
|
||||
{ id: 'archive', label: '档案' },
|
||||
{ id: 'search', label: '检索' },
|
||||
{ id: 'search', label: '问问微信' },
|
||||
{ id: 'report', label: '日报' },
|
||||
{ id: 'agent-hub', label: 'Agent' },
|
||||
{ id: 'export', label: '导出' },
|
||||
|
||||
@@ -641,7 +641,7 @@ export function AISearchWorkspace({
|
||||
<header className="ai-search-header">
|
||||
<div>
|
||||
<span className="ai-search-kicker">WechatExplorer · LOCAL INTELLIGENCE</span>
|
||||
<h1>AI 智能检索</h1>
|
||||
<h1>问问你的微信</h1>
|
||||
<p>在本地聊天记录中提炼主题、结论和可追溯证据</p>
|
||||
</div>
|
||||
<div className="ai-search-header-actions">
|
||||
|
||||
@@ -1178,15 +1178,106 @@
|
||||
}
|
||||
|
||||
.database-login-workspace {
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
align-items: start;
|
||||
justify-items: center;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
overflow-y: auto;
|
||||
padding: 48px clamp(40px, 7vw, 96px);
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.database-login-panel {
|
||||
width: min(520px, 100%);
|
||||
margin: auto 0;
|
||||
}
|
||||
|
||||
.database-login-start {
|
||||
margin-bottom: 22px;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
color: var(--login-text);
|
||||
font-size: 22px;
|
||||
line-height: 29px;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
> p:not(.database-login-eyebrow) {
|
||||
margin: 7px 0 18px;
|
||||
color: var(--login-muted);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
}
|
||||
|
||||
ol {
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
li {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: 10px;
|
||||
color: #35423d;
|
||||
|
||||
> span {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
flex: 0 0 20px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 50%;
|
||||
color: var(--login-primary-dark);
|
||||
background: #e2f0eb;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
strong,
|
||||
small {
|
||||
display: block;
|
||||
}
|
||||
|
||||
strong {
|
||||
font-size: 12px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
small {
|
||||
margin-top: 1px;
|
||||
color: var(--login-muted);
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.database-login-eyebrow {
|
||||
margin: 0 0 5px;
|
||||
color: var(--login-primary);
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.database-login-guide-link {
|
||||
display: inline-block;
|
||||
margin-top: 15px;
|
||||
color: var(--login-primary);
|
||||
font-size: 11px;
|
||||
line-height: 17px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.database-login-guide-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.database-login-tabs {
|
||||
@@ -1217,6 +1308,16 @@
|
||||
box-shadow: 0 1px 3px rgba(24, 28, 27, 0.08);
|
||||
}
|
||||
|
||||
.database-login-tabs .database-login-manual-tab {
|
||||
color: #7a8580;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.database-login-tabs .database-login-manual-tab.active {
|
||||
color: #58645f;
|
||||
}
|
||||
|
||||
.database-login-state-card {
|
||||
padding: 18px;
|
||||
border: 1px solid var(--login-border);
|
||||
@@ -1396,6 +1497,33 @@
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.database-login-platform-note {
|
||||
margin: 12px 0 0;
|
||||
color: #77817d;
|
||||
font-size: 11px;
|
||||
line-height: 17px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.database-login-platform-note a {
|
||||
color: var(--login-primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.database-login-platform-note a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.database-login-manual-note {
|
||||
margin: 0 0 20px;
|
||||
padding: 10px 12px;
|
||||
border-radius: 7px;
|
||||
color: #65706b;
|
||||
background: var(--login-surface-low);
|
||||
font-size: 11px;
|
||||
line-height: 17px;
|
||||
}
|
||||
|
||||
.database-login-manual {
|
||||
padding-top: 2px;
|
||||
}
|
||||
|
||||
+50
@@ -144,6 +144,56 @@ body {
|
||||
-webkit-app-region: no-drag;
|
||||
}
|
||||
|
||||
.app-guide-launcher {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
min-height: 52px;
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 3px;
|
||||
margin: 0 0 8px;
|
||||
padding: 5px 0;
|
||||
border: 0;
|
||||
border-radius: var(--wxex-radius-md);
|
||||
color: var(--wxex-text-secondary);
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-family: var(--wxex-font);
|
||||
-webkit-app-region: no-drag;
|
||||
|
||||
&:hover {
|
||||
color: var(--wxex-brand);
|
||||
background: var(--wxex-brand-soft);
|
||||
}
|
||||
}
|
||||
|
||||
.app-guide-launcher-icon {
|
||||
width: 22px;
|
||||
height: 22px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
|
||||
svg {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-width: 1.7;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
}
|
||||
}
|
||||
|
||||
.app-guide-launcher-label {
|
||||
font-size: 11px;
|
||||
line-height: 15px;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.account-summary {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
|
||||
@@ -137,6 +137,244 @@
|
||||
transition: width 0.18s ease-out;
|
||||
}
|
||||
|
||||
/* 首次连接成功后的下一步引导 */
|
||||
.first-use-welcome-overlay {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1200;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
padding: 24px;
|
||||
background: rgba(16, 27, 23, 0.42);
|
||||
backdrop-filter: blur(4px);
|
||||
animation: settings-fade-in 0.16s ease-out;
|
||||
}
|
||||
|
||||
.first-use-welcome {
|
||||
position: relative;
|
||||
width: min(520px, 100%);
|
||||
padding: 34px;
|
||||
border: 1px solid rgba(203, 222, 214, 0.9);
|
||||
border-radius: 18px;
|
||||
background: #fff;
|
||||
box-shadow: 0 24px 70px rgba(16, 35, 28, 0.24);
|
||||
animation: settings-pop-in 0.18s ease-out;
|
||||
}
|
||||
|
||||
.first-use-welcome-close {
|
||||
position: absolute;
|
||||
top: 14px;
|
||||
right: 16px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border: 0;
|
||||
border-radius: 50%;
|
||||
color: #7c8882;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-size: 23px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.first-use-welcome-close:hover {
|
||||
color: #26342d;
|
||||
background: #f0f4f1;
|
||||
}
|
||||
|
||||
.first-use-welcome-mark {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
margin-bottom: 18px;
|
||||
border-radius: 13px;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #176b57, #42a27f);
|
||||
box-shadow: 0 7px 16px rgba(23, 107, 87, 0.22);
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
.first-use-welcome-eyebrow {
|
||||
margin: 0 0 5px;
|
||||
color: #247a63;
|
||||
font-size: 11px;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.08em;
|
||||
}
|
||||
|
||||
.first-use-welcome h2 {
|
||||
margin: 0;
|
||||
color: #1f2c26;
|
||||
font-size: 25px;
|
||||
line-height: 34px;
|
||||
letter-spacing: -0.025em;
|
||||
}
|
||||
|
||||
.first-use-welcome-lead {
|
||||
margin: 8px 0 24px;
|
||||
color: #66756d;
|
||||
font-size: 13px;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
.first-use-welcome-actions {
|
||||
display: grid;
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 18px;
|
||||
width: 100%;
|
||||
padding: 17px 16px;
|
||||
border: 1px solid #247a63;
|
||||
border-radius: 12px;
|
||||
color: #fff;
|
||||
background: linear-gradient(135deg, #247a63, #176b57);
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
transition:
|
||||
border-color 0.15s ease,
|
||||
background 0.15s ease,
|
||||
transform 0.15s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: #00604c;
|
||||
background: linear-gradient(135deg, #176b57, #00604c);
|
||||
transform: translateY(-1px);
|
||||
}
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-icon {
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
flex: 0 0 34px;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
border-radius: 10px;
|
||||
color: #176b57;
|
||||
background: #fff;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-copy {
|
||||
min-width: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-arrow {
|
||||
flex: 0 0 auto;
|
||||
font-size: 11px;
|
||||
font-weight: 650;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-copy strong,
|
||||
.first-use-welcome-feature-copy small {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-copy strong {
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-copy small {
|
||||
margin-top: 2px;
|
||||
color: rgba(255, 255, 255, 0.76);
|
||||
font-size: 11px;
|
||||
line-height: 16px;
|
||||
}
|
||||
|
||||
.first-use-welcome-secondary-actions {
|
||||
display: flex;
|
||||
gap: 22px;
|
||||
margin: 16px 0 22px;
|
||||
}
|
||||
|
||||
.first-use-welcome-secondary-actions button {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
color: #53645b;
|
||||
background: transparent;
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.first-use-welcome-secondary-actions button:hover {
|
||||
color: #247a63;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.first-use-welcome-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 16px;
|
||||
margin-top: 23px;
|
||||
padding-top: 16px;
|
||||
border-top: 1px solid #edf1ef;
|
||||
|
||||
span,
|
||||
button,
|
||||
a {
|
||||
color: #68766f;
|
||||
background: transparent;
|
||||
font-size: 11px;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
button {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
a:hover {
|
||||
color: #247a63;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 640px), (max-height: 560px) {
|
||||
.first-use-welcome-overlay {
|
||||
display: block;
|
||||
overflow: auto;
|
||||
padding: 18px;
|
||||
}
|
||||
|
||||
.first-use-welcome {
|
||||
width: auto;
|
||||
margin: 0 auto;
|
||||
padding: 26px 22px 22px;
|
||||
}
|
||||
|
||||
.first-use-welcome h2 {
|
||||
font-size: 22px;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature {
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.first-use-welcome-feature-arrow {
|
||||
width: 100%;
|
||||
margin-left: 44px;
|
||||
}
|
||||
|
||||
.first-use-welcome-footer {
|
||||
align-items: flex-start;
|
||||
flex-direction: column;
|
||||
gap: 9px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 设置面板 */
|
||||
.settings-overlay {
|
||||
position: fixed;
|
||||
|
||||
Reference in New Issue
Block a user