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,
|
HOTKEY_MODE_MIGRATION_DEFERRED_KEY,
|
||||||
shouldShowHotkeyModeMigrationPrompt,
|
shouldShowHotkeyModeMigrationPrompt,
|
||||||
} from '../lib/hotkeyMigration';
|
} from '../lib/hotkeyMigration';
|
||||||
import { getHotkeyTriggerLabel } from '../lib/hotkey';
|
|
||||||
import { applyFontScale, readFontScale } from '../lib/fontScale';
|
import { applyFontScale, readFontScale } from '../lib/fontScale';
|
||||||
import { getCredentials, openExternal } from '../lib/ipc';
|
import { getCredentials, openExternal } from '../lib/ipc';
|
||||||
import { OL_DATA } from '../lib/mockData';
|
|
||||||
import {
|
import {
|
||||||
PROVIDER_SETUP_PROMPT_DEFERRED_KEY,
|
PROVIDER_SETUP_PROMPT_DEFERRED_KEY,
|
||||||
shouldShowProviderSetupPrompt,
|
shouldShowProviderSetupPrompt,
|
||||||
} from '../lib/providerSetup';
|
} from '../lib/providerSetup';
|
||||||
import type { SettingsSectionId } from '../pages/Settings';
|
import type { SettingsSectionId } from '../pages/Settings';
|
||||||
import { useHotkeySettings } from '../state/HotkeySettingsContext';
|
|
||||||
import { useAppState, type AppTab } from '../state/useAppState';
|
import { useAppState, type AppTab } from '../state/useAppState';
|
||||||
|
|
||||||
interface NavItem {
|
interface NavItem {
|
||||||
@@ -75,7 +72,6 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
|||||||
const [providerPromptOpen, setProviderPromptOpen] = useState(false);
|
const [providerPromptOpen, setProviderPromptOpen] = useState(false);
|
||||||
const [hotkeyModePromptOpen, setHotkeyModePromptOpen] = useState(false);
|
const [hotkeyModePromptOpen, setHotkeyModePromptOpen] = useState(false);
|
||||||
const [helpPopoverOpen, setHelpPopoverOpen] = useState(false);
|
const [helpPopoverOpen, setHelpPopoverOpen] = useState(false);
|
||||||
const { hotkey } = useHotkeySettings();
|
|
||||||
|
|
||||||
// 字体档位 — 启动时按 localStorage 应用一次;之后改动来自 Settings 的"个性化"section。
|
// 字体档位 — 启动时按 localStorage 应用一次;之后改动来自 Settings 的"个性化"section。
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -212,12 +208,6 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
|||||||
|
|
||||||
<Icon name={n.icon} size={14} />
|
<Icon name={n.icon} size={14} />
|
||||||
<span style={{ flex: 1 }}>{n.name}</span>
|
<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>
|
</button>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
@@ -225,21 +215,6 @@ function FloatingShellBody({ os, initialTab, initialSettings }: { os: OS; initia
|
|||||||
|
|
||||||
<div style={{ flex: 1 }} />
|
<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 一起浮在磨砂玻璃上 */}
|
{/* BETA 区域 — 去掉描边和实色背景,让它和底部 footer 一起浮在磨砂玻璃上 */}
|
||||||
<div style={{ marginTop: 8, padding: '10px 10px 4px' }}>
|
<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>
|
<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',
|
title: 'How to use',
|
||||||
step1: 'Place the text cursor in another app (Notes, mail, chat — anything with a text field).',
|
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.',
|
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.',
|
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.',
|
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',
|
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',
|
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: {
|
selectionAsk: {
|
||||||
|
|||||||
@@ -197,14 +197,14 @@ export const zhCN = {
|
|||||||
howto: {
|
howto: {
|
||||||
title: '使用方法',
|
title: '使用方法',
|
||||||
step1: '在另一个 app 的输入框里聚焦光标(备忘录、邮件、聊天窗口都行)。',
|
step1: '在另一个 app 的输入框里聚焦光标(备忘录、邮件、聊天窗口都行)。',
|
||||||
step2: '按一下"录音快捷键"(当前是 {{trigger}}),开始录音。',
|
step2: '按一下录音快捷键(当前:{{trigger}})开始录音。',
|
||||||
step3: '在录音过程中任意时刻按一下 Shift——按一下即可,不需要按住,可以在开口前、说到一半、快说完时按。',
|
step3: '在录音过程中任意时刻按一下 Shift 即可,不需要按住;可以在开口前、说到一半或快结束时按。',
|
||||||
step4: '再按一下"录音快捷键"停止录音。',
|
step4: '再按一次录音快捷键停止录音。',
|
||||||
step5: '系统会把转写交给大模型翻译成上面选的目标语言,然后插入到一开始那个输入框光标位置。',
|
step5: '系统会把转写交给大模型翻译成上面选的目标语言,然后插入到一开始那个输入框光标位置。',
|
||||||
indicatorTitle: '怎么知道翻译模式生效了',
|
indicatorTitle: '怎么知道翻译模式生效了',
|
||||||
indicatorDesc: '一旦按下 Shift,屏幕底部录音胶囊的上方会立刻悬浮一个蓝色"● 正在翻译"小药丸——它会一直显示到本次插入完成,让你确认这次输出会走翻译管线。',
|
indicatorDesc: '一旦按下 Shift,屏幕底部录音胶囊上方会出现蓝色「正在翻译」提示,并持续到本次插入完成。',
|
||||||
fallbackTitle: '安全兜底',
|
fallbackTitle: '安全兜底',
|
||||||
fallbackDesc: '翻译模式选「不启用」时 Shift 是没作用的;翻译过程中如果大模型调用失败,会回退到把原始中文转写直接插入,不会丢字。详见 issue #4。',
|
fallbackDesc: '翻译模式选「不启用」时 Shift 不会触发翻译;如果大模型调用失败,会回退插入原始转写,不会丢字。',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
selectionAsk: {
|
selectionAsk: {
|
||||||
|
|||||||
@@ -70,29 +70,6 @@ export function Overview({ onOpenHistory }: OverviewProps) {
|
|||||||
kicker={t('overview.kicker')}
|
kicker={t('overview.kicker')}
|
||||||
title={t('overview.title')}
|
title={t('overview.title')}
|
||||||
desc={t('overview.desc')}
|
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 }}>
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12, marginBottom: 18 }}>
|
||||||
|
|||||||
@@ -4,8 +4,9 @@
|
|||||||
// - 选一个翻译目标语言(单选;选"不启用"则 Shift 不触发翻译)
|
// - 选一个翻译目标语言(单选;选"不启用"则 Shift 不触发翻译)
|
||||||
// - 看完整使用说明(怎么触发、按钮位置、胶囊显示)
|
// - 看完整使用说明(怎么触发、按钮位置、胶囊显示)
|
||||||
|
|
||||||
|
import type { CSSProperties } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Card, PageHeader } from './_atoms';
|
import { Card, PageHeader, Pill } from './_atoms';
|
||||||
import { SUPPORTED_LANGUAGES } from '../lib/types';
|
import { SUPPORTED_LANGUAGES } from '../lib/types';
|
||||||
import { useHotkeySettings } from '../state/HotkeySettingsContext';
|
import { useHotkeySettings } from '../state/HotkeySettingsContext';
|
||||||
import { getHotkeyTriggerLabel } from '../lib/hotkey';
|
import { getHotkeyTriggerLabel } from '../lib/hotkey';
|
||||||
@@ -42,6 +43,13 @@ export function Translation() {
|
|||||||
|
|
||||||
const triggerLabel = getHotkeyTriggerLabel(hotkey?.trigger);
|
const triggerLabel = getHotkeyTriggerLabel(hotkey?.trigger);
|
||||||
const enabled = prefs.translationTargetLanguage.trim() !== '';
|
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -52,32 +60,55 @@ export function Translation() {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
|
||||||
|
{/* 1. 翻译目标语言 */}
|
||||||
{/* 1. 工作语言 */}
|
|
||||||
<Card>
|
<Card>
|
||||||
<div style={{ fontSize: 13, fontWeight: 600, marginBottom: 4 }}>{t('translation.working.title')}</div>
|
<div style={{ display: 'grid', gridTemplateColumns: 'minmax(0, 1fr) 220px', gap: 18, alignItems: 'stretch' }}>
|
||||||
<div style={{ fontSize: 11.5, color: 'var(--ol-ink-4)', marginBottom: 12, lineHeight: 1.55 }}>
|
<div>
|
||||||
{t('translation.working.desc')}
|
<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>
|
||||||
<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 => {
|
{SUPPORTED_LANGUAGES.map(lang => {
|
||||||
const checked = prefs.workingLanguages.includes(lang);
|
const checked = prefs.workingLanguages.includes(lang);
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
key={lang}
|
key={lang}
|
||||||
onClick={() => toggleWorkingLanguage(lang)}
|
onClick={() => toggleWorkingLanguage(lang)}
|
||||||
style={{
|
style={languageChipStyle(checked)}
|
||||||
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)',
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{lang}
|
{lang}
|
||||||
</button>
|
</button>
|
||||||
@@ -86,95 +117,144 @@ export function Translation() {
|
|||||||
</div>
|
</div>
|
||||||
</Card>
|
</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. 使用方法 */}
|
{/* 3. 使用方法 */}
|
||||||
<Card>
|
<Card>
|
||||||
<div style={{ fontSize: 13, fontWeight: 600, marginBottom: 10 }}>{t('translation.howto.title')}</div>
|
<div style={settingsTitleStyle}>{t('translation.howto.title')}</div>
|
||||||
<ol style={{ margin: 0, paddingLeft: 18, fontSize: 12.5, color: 'var(--ol-ink-2)', lineHeight: 1.7 }}>
|
<div style={{ display: 'grid', gap: 8, marginTop: 12 }}>
|
||||||
<li>{t('translation.howto.step1', { trigger: triggerLabel })}</li>
|
{howtoSteps.map((step, index) => (
|
||||||
<li>{t('translation.howto.step2')}</li>
|
<div key={step} style={stepRowStyle}>
|
||||||
<li>{t('translation.howto.step3')}</li>
|
<span style={stepNumberStyle}>{String(index + 1).padStart(2, '0')}</span>
|
||||||
<li>{t('translation.howto.step4')}</li>
|
<span style={{ minWidth: 0 }}>{step}</span>
|
||||||
<li>{t('translation.howto.step5')}</li>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
</Card>
|
</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>
|
</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