fix(ui): clean sidebar and translation settings
This commit is contained in:
1 parent
91f1c5fae8
commit
d7d274fa87
5 files changed
+191
-159
No files matched your search
@@ -22,16 +22,13 @@ import {
|
||||
HOTKEY_MODE_MIGRATION_DEFERRED_KEY,
|
||||
shouldShowHotkeyModeMigrationPrompt,
|
||||
} from '../lib/hotkeyMigration';
|
||||
import { getHotkeyTriggerLabel } from '../lib/hotkey';
|
||||
import { applyFontScale, readFontScale } from '../lib/fontScale';
|
||||
import { getCredentials, openExternal } from '../lib/ipc';
|
||||
import { OL_DATA } from '../lib/mockData';
|
||||
import {
|
||||
PROVIDER_SETUP_PROMPT_DEFERRED_KEY,
|
||||
shouldShowProviderSetupPrompt,
|
||||
} from '../lib/providerSetup';
|
||||
import type { SettingsSectionId } from '../pages/Settings';
|
||||
import { useHotkeySettings } from '../state/HotkeySettingsContext';
|
||||
import { useAppState, type AppTab } from '../state/useAppState';
|
||||
|
||||
interface NavItem {
|
||||
@@ -75,7 +72,6 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
||||
const [providerPromptOpen, setProviderPromptOpen] = useState(false);
|
||||
const [hotkeyModePromptOpen, setHotkeyModePromptOpen] = useState(false);
|
||||
const [helpPopoverOpen, setHelpPopoverOpen] = useState(false);
|
||||
const { hotkey } = useHotkeySettings();
|
||||
|
||||
// 字体档位 — 启动时按 localStorage 应用一次;之后改动来自 Settings 的"个性化"section。
|
||||
useEffect(() => {
|
||||
@@ -212,12 +208,6 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
||||
|
||||
<Icon name={n.icon} size={14} />
|
||||
<span style={{ flex: 1 }}>{n.name}</span>
|
||||
{n.id === 'history' &&
|
||||
<span style={{
|
||||
fontSize: 10, fontFamily: 'var(--ol-font-mono)',
|
||||
color: active ? 'var(--ol-ink-4)' : 'var(--ol-ink-5)',
|
||||
}}>{OL_DATA.history.length}</span>
|
||||
}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
@@ -225,21 +215,6 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
||||
|
||||
<div style={{ flex: 1 }} />
|
||||
|
||||
{/* shortcut hint — 不要 dashed 边框,否则会切断"整片磨砂玻璃"的视觉 */}
|
||||
<div style={{ padding: '10px 10px 6px', marginTop: 6 }}>
|
||||
<div style={{ fontSize: 10.5, color: 'var(--ol-ink-4)', marginBottom: 6, letterSpacing: '0.02em' }}>{t('shell.shortcutLabel')}</div>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 6, fontSize: 11, color: 'var(--ol-ink-2)' }}>
|
||||
<kbd style={{
|
||||
padding: '2px 7px', fontSize: 10.5,
|
||||
background: 'rgba(255,255,255,0.7)', borderRadius: 5,
|
||||
border: '0.5px solid var(--ol-line-strong)',
|
||||
fontFamily: 'var(--ol-font-mono)', color: 'var(--ol-ink)',
|
||||
boxShadow: '0 1px 0 rgba(0,0,0,.04)',
|
||||
}}>{getHotkeyTriggerLabel(hotkey?.trigger)}</kbd>
|
||||
<span style={{ color: 'var(--ol-ink-4)' }}>{t('shell.shortcutHint')}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* BETA 区域 — 去掉描边和实色背景,让它和底部 footer 一起浮在磨砂玻璃上 */}
|
||||
<div style={{ marginTop: 8, padding: '10px 10px 4px' }}>
|
||||
<div style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--ol-blue)', letterSpacing: '0.04em', textTransform: 'uppercase' }}>{t('shell.betaTag')}</div>
|
||||
|
||||
@@ -200,13 +200,13 @@ export const en: typeof zhCN = {
|
||||
title: 'How to use',
|
||||
step1: 'Place the text cursor in another app (Notes, mail, chat — anything with a text field).',
|
||||
step2: 'Press the recording hotkey (currently {{trigger}}) to start dictation.',
|
||||
step3: 'Press Shift any time during the recording — once is enough, no need to hold it. You can press it before you start talking, mid-sentence, or right before stopping.',
|
||||
step3: 'Press Shift once any time during recording. You can press it before speaking, mid-sentence, or right before stopping.',
|
||||
step4: 'Press the recording hotkey again to stop.',
|
||||
step5: 'The transcript is sent to the LLM, translated into the target language above, then inserted at the original cursor position.',
|
||||
indicatorTitle: 'How to confirm translation mode is on',
|
||||
indicatorDesc: 'The moment you press Shift, a blue "● Translating" pill floats above the recording capsule at the bottom of the screen. It stays visible until insertion completes, so you always know this run goes through the translation pipeline.',
|
||||
indicatorDesc: 'The moment you press Shift, a blue Translating indicator appears above the recording capsule and stays visible until insertion completes.',
|
||||
fallbackTitle: 'Safety fallbacks',
|
||||
fallbackDesc: 'When the target is "Disabled", Shift is a no-op. If the LLM call fails mid-translation, the raw transcript is inserted directly so nothing gets lost. See issue #4.',
|
||||
fallbackDesc: 'When the target is Disabled, Shift does not trigger translation. If the LLM call fails, the raw transcript is inserted so nothing gets lost.',
|
||||
},
|
||||
},
|
||||
selectionAsk: {
|
||||
|
||||
@@ -197,14 +197,14 @@ export const zhCN = {
|
||||
howto: {
|
||||
title: '使用方法',
|
||||
step1: '在另一个 app 的输入框里聚焦光标(备忘录、邮件、聊天窗口都行)。',
|
||||
step2: '按一下"录音快捷键"(当前是 {{trigger}}),开始录音。',
|
||||
step3: '在录音过程中任意时刻按一下 Shift——按一下即可,不需要按住,可以在开口前、说到一半、快说完时按。',
|
||||
step4: '再按一下"录音快捷键"停止录音。',
|
||||
step2: '按一下录音快捷键(当前:{{trigger}})开始录音。',
|
||||
step3: '在录音过程中任意时刻按一下 Shift 即可,不需要按住;可以在开口前、说到一半或快结束时按。',
|
||||
step4: '再按一次录音快捷键停止录音。',
|
||||
step5: '系统会把转写交给大模型翻译成上面选的目标语言,然后插入到一开始那个输入框光标位置。',
|
||||
indicatorTitle: '怎么知道翻译模式生效了',
|
||||
indicatorDesc: '一旦按下 Shift,屏幕底部录音胶囊的上方会立刻悬浮一个蓝色"● 正在翻译"小药丸——它会一直显示到本次插入完成,让你确认这次输出会走翻译管线。',
|
||||
indicatorDesc: '一旦按下 Shift,屏幕底部录音胶囊上方会出现蓝色「正在翻译」提示,并持续到本次插入完成。',
|
||||
fallbackTitle: '安全兜底',
|
||||
fallbackDesc: '翻译模式选「不启用」时 Shift 是没作用的;翻译过程中如果大模型调用失败,会回退到把原始中文转写直接插入,不会丢字。详见 issue #4。',
|
||||
fallbackDesc: '翻译模式选「不启用」时 Shift 不会触发翻译;如果大模型调用失败,会回退插入原始转写,不会丢字。',
|
||||
},
|
||||
},
|
||||
selectionAsk: {
|
||||
|
||||
@@ -70,29 +70,6 @@ export function Overview({ onOpenHistory }: OverviewProps) {
|
||||
kicker={t('overview.kicker')}
|
||||
title={t('overview.title')}
|
||||
desc={t('overview.desc')}
|
||||
right={
|
||||
<div
|
||||
style={{
|
||||
display: 'inline-flex', alignItems: 'center', gap: 8,
|
||||
padding: '6px 12px',
|
||||
borderRadius: 999,
|
||||
border: '0.5px solid var(--ol-line-strong)',
|
||||
background: 'var(--ol-surface-2)',
|
||||
color: 'var(--ol-ink-3)',
|
||||
fontSize: 12,
|
||||
}}
|
||||
>
|
||||
<Icon name="cmd" size={12} />
|
||||
{t('overview.pressPrefix')}
|
||||
<kbd style={{
|
||||
padding: '2px 7px', fontSize: 11, fontFamily: 'var(--ol-font-mono)',
|
||||
background: '#fff', borderRadius: 5,
|
||||
border: '0.5px solid var(--ol-line-strong)',
|
||||
color: 'var(--ol-ink)',
|
||||
}}>{getHotkeyTriggerLabel(hotkey?.trigger)}</kbd>
|
||||
{t('overview.pressSuffix')}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 18 }}>
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
// - 选一个翻译目标语言(单选;选"不启用"则 Shift 不触发翻译)
|
||||
// - 看完整使用说明(怎么触发、按钮位置、胶囊显示)
|
||||
|
||||
import type { CSSProperties } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Card, PageHeader } from './_atoms';
|
||||
import { Card, PageHeader, Pill } from './_atoms';
|
||||
import { SUPPORTED_LANGUAGES } from '../lib/types';
|
||||
import { useHotkeySettings } from '../state/HotkeySettingsContext';
|
||||
import { getHotkeyTriggerLabel } from '../lib/hotkey';
|
||||
@@ -42,6 +43,13 @@ export function Translation() {
|
||||
|
||||
const triggerLabel = getHotkeyTriggerLabel(hotkey?.trigger);
|
||||
const enabled = prefs.translationTargetLanguage.trim() !== '';
|
||||
const howtoSteps = [
|
||||
t('translation.howto.step1'),
|
||||
t('translation.howto.step2', { trigger: triggerLabel }),
|
||||
t('translation.howto.step3'),
|
||||
t('translation.howto.step4'),
|
||||
t('translation.howto.step5'),
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -52,32 +60,55 @@ export function Translation() {
|
||||
/>
|
||||
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||
|
||||
{/* 1. 工作语言 */}
|
||||
{/* 1. 翻译目标语言 */}
|
||||
<Card>
|
||||
<div style={{ fontSize: 13, fontWeight: 600, marginBottom: 4 }}>{t('translation.working.title')}</div>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginBottom: 12, lineHeight: 1.55 }}>
|
||||
{t('translation.working.desc')}
|
||||
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) 220px', gap: 18, alignItems: 'stretch' }}>
|
||||
<div>
|
||||
<div style={settingsHeaderStyle}>
|
||||
<div style={settingsTitleStyle}>{t('translation.target.title')}</div>
|
||||
<Pill tone={enabled ? 'blue' : 'outline'} size="sm">
|
||||
{enabled ? t('translation.statusEnabled') : t('translation.statusDisabled')}
|
||||
</Pill>
|
||||
</div>
|
||||
<div style={settingsDescStyle}>{t('translation.target.desc')}</div>
|
||||
<select
|
||||
value={prefs.translationTargetLanguage}
|
||||
onChange={e => onTargetChange(e.target.value)}
|
||||
style={selectStyle}
|
||||
>
|
||||
<option value="">{t('translation.target.disabled')}</option>
|
||||
{SUPPORTED_LANGUAGES.map(lang => (
|
||||
<option key={lang} value={lang}>{lang}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div style={translationStatusStyle(enabled)}>
|
||||
<div style={{ fontSize: 11, color: enabled ? 'var(--ol-blue)' : 'var(--ol-ink-4)', fontWeight: 600, letterSpacing: '0.06em', textTransform: 'uppercase' }}>
|
||||
{enabled ? t('translation.statusEnabled') : t('translation.statusDisabled')}
|
||||
</div>
|
||||
<div style={{ marginTop: 10, fontSize: 22, lineHeight: 1.1, fontWeight: 650, letterSpacing: '-0.03em', color: enabled ? 'var(--ol-blue)' : 'var(--ol-ink-2)' }}>
|
||||
{enabled ? prefs.translationTargetLanguage : t('translation.statusDisabled')}
|
||||
</div>
|
||||
<div style={{ marginTop: 8, fontSize: 11.5, color: 'var(--ol-ink-4)', lineHeight: 1.5 }}>
|
||||
Shift
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
|
||||
</Card>
|
||||
|
||||
{/* 2. 工作语言 */}
|
||||
<Card>
|
||||
<div style={settingsTitleStyle}>{t('translation.working.title')}</div>
|
||||
<div style={settingsDescStyle}>{t('translation.working.desc')}</div>
|
||||
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 7 }}>
|
||||
{SUPPORTED_LANGUAGES.map(lang => {
|
||||
const checked = prefs.workingLanguages.includes(lang);
|
||||
return (
|
||||
<button
|
||||
key={lang}
|
||||
onClick={() => toggleWorkingLanguage(lang)}
|
||||
style={{
|
||||
padding: '6px 12px',
|
||||
fontSize: 12.5,
|
||||
fontWeight: checked ? 600 : 500,
|
||||
border: 0,
|
||||
borderRadius: 999,
|
||||
background: checked ? 'var(--ol-blue)' : 'rgba(0,0,0,0.05)',
|
||||
color: checked ? '#fff' : 'var(--ol-ink-2)',
|
||||
cursor: 'default',
|
||||
fontFamily: 'inherit',
|
||||
transition: 'background 0.16s var(--ol-motion-quick), color 0.16s var(--ol-motion-quick)',
|
||||
}}
|
||||
style={languageChipStyle(checked)}
|
||||
>
|
||||
{lang}
|
||||
</button>
|
||||
@@ -86,95 +117,144 @@ export function Translation() {
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
{/* 2. 翻译目标语言 */}
|
||||
<Card>
|
||||
<div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 4 }}>
|
||||
<div style={{ fontSize: 13, fontWeight: 600 }}>{t('translation.target.title')}</div>
|
||||
<span
|
||||
style={{
|
||||
padding: '2px 8px',
|
||||
fontSize: 10.5,
|
||||
fontWeight: 600,
|
||||
letterSpacing: '0.04em',
|
||||
borderRadius: 999,
|
||||
background: enabled ? 'rgba(37,99,235,0.10)' : 'rgba(0,0,0,0.05)',
|
||||
color: enabled ? 'var(--ol-blue)' : 'var(--ol-ink-4)',
|
||||
textTransform: 'uppercase',
|
||||
}}
|
||||
>
|
||||
{enabled ? t('translation.statusEnabled') : t('translation.statusDisabled')}
|
||||
</span>
|
||||
</div>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginBottom: 12, lineHeight: 1.55 }}>
|
||||
{t('translation.target.desc')}
|
||||
</div>
|
||||
<select
|
||||
value={prefs.translationTargetLanguage}
|
||||
onChange={e => onTargetChange(e.target.value)}
|
||||
style={{
|
||||
width: '100%',
|
||||
maxWidth: 360,
|
||||
height: 32,
|
||||
padding: '0 10px',
|
||||
fontSize: 13,
|
||||
border: '0.5px solid var(--ol-line-strong)',
|
||||
borderRadius: 8,
|
||||
background: '#fff',
|
||||
color: 'var(--ol-ink)',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'default',
|
||||
}}
|
||||
>
|
||||
<option value="">{t('translation.target.disabled')}</option>
|
||||
{SUPPORTED_LANGUAGES.map(lang => (
|
||||
<option key={lang} value={lang}>{lang}</option>
|
||||
))}
|
||||
</select>
|
||||
</Card>
|
||||
|
||||
{/* 3. 使用方法 */}
|
||||
<Card>
|
||||
<div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>{t('translation.howto.title')}</div>
|
||||
<ol style={{ margin: 0, paddingLeft: 18, fontSize: 12.5, color: 'var(--ol-ink-2)', lineHeight: 1.7 }}>
|
||||
<li>{t('translation.howto.step1', { trigger: triggerLabel })}</li>
|
||||
<li>{t('translation.howto.step2')}</li>
|
||||
<li>{t('translation.howto.step3')}</li>
|
||||
<li>{t('translation.howto.step4')}</li>
|
||||
<li>{t('translation.howto.step5')}</li>
|
||||
</ol>
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop: 14,
|
||||
padding: '10px 12px',
|
||||
borderRadius: 10,
|
||||
background: 'rgba(37,99,235,0.06)',
|
||||
border: '0.5px solid rgba(37,99,235,0.15)',
|
||||
fontSize: 11.5,
|
||||
color: 'var(--ol-ink-2)',
|
||||
lineHeight: 1.55,
|
||||
}}
|
||||
>
|
||||
<div style={{ fontWeight: 600, color: 'var(--ol-blue)', marginBottom: 4 }}>{t('translation.howto.indicatorTitle')}</div>
|
||||
{t('translation.howto.indicatorDesc')}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{
|
||||
marginTop: 10,
|
||||
padding: '10px 12px',
|
||||
borderRadius: 10,
|
||||
background: 'rgba(0,0,0,0.04)',
|
||||
fontSize: 11.5,
|
||||
color: 'var(--ol-ink-3)',
|
||||
lineHeight: 1.55,
|
||||
}}
|
||||
>
|
||||
<div style={{ fontWeight: 600, color: 'var(--ol-ink-2)', marginBottom: 4 }}>{t('translation.howto.fallbackTitle')}</div>
|
||||
{t('translation.howto.fallbackDesc')}
|
||||
<div style={settingsTitleStyle}>{t('translation.howto.title')}</div>
|
||||
<div style={{ display: 'grid', gap: 8, marginTop: 12 }}>
|
||||
{howtoSteps.map((step, index) => (
|
||||
<div key={step} style={stepRowStyle}>
|
||||
<span style={stepNumberStyle}>{String(index + 1).padStart(2, '0')}</span>
|
||||
<span style={{ minWidth: 0 }}>{step}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
|
||||
<InfoTile tone="blue" title={t('translation.howto.indicatorTitle')} body={t('translation.howto.indicatorDesc')} />
|
||||
<InfoTile tone="neutral" title={t('translation.howto.fallbackTitle')} body={t('translation.howto.fallbackDesc')} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const settingsHeaderStyle: CSSProperties = {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
gap: 12,
|
||||
marginBottom: 5,
|
||||
};
|
||||
|
||||
const settingsTitleStyle: CSSProperties = {
|
||||
fontSize: 13,
|
||||
fontWeight: 650,
|
||||
color: 'var(--ol-ink)',
|
||||
};
|
||||
|
||||
const settingsDescStyle: CSSProperties = {
|
||||
fontSize: 11.5,
|
||||
color: 'var(--ol-ink-4)',
|
||||
marginBottom: 14,
|
||||
lineHeight: 1.58,
|
||||
};
|
||||
|
||||
const selectStyle: CSSProperties = {
|
||||
width: '100%',
|
||||
maxWidth: 380,
|
||||
height: 34,
|
||||
padding: '0 11px',
|
||||
fontSize: 13,
|
||||
border: '0.5px solid var(--ol-line-strong)',
|
||||
borderRadius: 9,
|
||||
background: '#fff',
|
||||
color: 'var(--ol-ink)',
|
||||
fontFamily: 'inherit',
|
||||
cursor: 'default',
|
||||
boxShadow: '0 1px 0 rgba(255,255,255,0.9) inset',
|
||||
};
|
||||
|
||||
const stepRowStyle: CSSProperties = {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: '34px minmax(0, 1fr)',
|
||||
gap: 10,
|
||||
alignItems: 'start',
|
||||
padding: '9px 10px',
|
||||
borderRadius: 11,
|
||||
background: 'rgba(0,0,0,0.025)',
|
||||
color: 'var(--ol-ink-2)',
|
||||
fontSize: 12.5,
|
||||
lineHeight: 1.55,
|
||||
};
|
||||
|
||||
const stepNumberStyle: CSSProperties = {
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 999,
|
||||
background: 'rgba(255,255,255,0.85)',
|
||||
color: 'var(--ol-ink-4)',
|
||||
fontFamily: 'var(--ol-font-mono)',
|
||||
fontSize: 10.5,
|
||||
fontWeight: 600,
|
||||
boxShadow: '0 1px 2px rgba(0,0,0,0.04), 0 0 0 0.5px var(--ol-line)',
|
||||
};
|
||||
|
||||
function languageChipStyle(checked: boolean): CSSProperties {
|
||||
return {
|
||||
padding: '6px 12px',
|
||||
fontSize: 12.5,
|
||||
fontWeight: checked ? 650 : 500,
|
||||
border: checked ? '0.5px solid rgba(37,99,235,0.35)' : '0.5px solid var(--ol-line)',
|
||||
borderRadius: 999,
|
||||
background: checked ? 'var(--ol-blue)' : 'rgba(255,255,255,0.72)',
|
||||
color: checked ? '#fff' : 'var(--ol-ink-2)',
|
||||
cursor: 'default',
|
||||
fontFamily: 'inherit',
|
||||
boxShadow: checked ? '0 8px 18px -12px rgba(37,99,235,0.55)' : '0 1px 0 rgba(255,255,255,0.8) inset',
|
||||
transition: 'background 0.16s var(--ol-motion-quick), color 0.16s var(--ol-motion-quick), border-color 0.16s var(--ol-motion-quick), box-shadow 0.18s var(--ol-motion-soft)',
|
||||
};
|
||||
}
|
||||
|
||||
function translationStatusStyle(enabled: boolean): CSSProperties {
|
||||
return {
|
||||
minHeight: 108,
|
||||
borderRadius: 14,
|
||||
padding: 14,
|
||||
background: enabled
|
||||
? 'linear-gradient(135deg, rgba(37,99,235,0.12), rgba(37,99,235,0.04))'
|
||||
: 'linear-gradient(135deg, rgba(0,0,0,0.045), rgba(255,255,255,0.55))',
|
||||
border: enabled ? '0.5px solid rgba(37,99,235,0.16)' : '0.5px solid var(--ol-line)',
|
||||
boxShadow: '0 1px 0 rgba(255,255,255,0.85) inset',
|
||||
};
|
||||
}
|
||||
|
||||
function InfoTile({ tone, title, body }: { tone: 'blue' | 'neutral'; title: string; body: string }) {
|
||||
const blue = tone === 'blue';
|
||||
return (
|
||||
<Card
|
||||
padding={14}
|
||||
style={{
|
||||
background: blue ? 'rgba(37,99,235,0.055)' : 'rgba(0,0,0,0.025)',
|
||||
border: blue ? '0.5px solid rgba(37,99,235,0.14)' : '0.5px solid var(--ol-line)',
|
||||
}}
|
||||
>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
|
||||
<span
|
||||
style={{
|
||||
width: 7,
|
||||
height: 7,
|
||||
borderRadius: 999,
|
||||
background: blue ? 'var(--ol-blue)' : 'var(--ol-ink-4)',
|
||||
boxShadow: blue ? '0 0 0 4px rgba(37,99,235,0.10)' : '0 0 0 4px rgba(0,0,0,0.045)',
|
||||
}}
|
||||
/>
|
||||
<div style={{ fontSize: 12.5, fontWeight: 650, color: blue ? 'var(--ol-blue)' : 'var(--ol-ink-2)' }}>{title}</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-3)', lineHeight: 1.58 }}>{body}</div>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user