86d788e57c
Phase 1: 格式扩展 - png.rs → image.rs,OutputFormat 枚举 (PNG/BMP/JPEG/WebP) - CLI -f/--format,Web fmt 参数扩展,image crate +bmp feature Phase 2: 解码增强 - 新增 decoder/perspective.rs — 旋转矫正(MVP) - auto_correct: finder 检测→计算旋转角→仿射变换→再解码 - decode_image 自动重试矫正流水线 Phase 3: vCard 扩展 - 新增 5 字段:TITLE/URL/BDAY/NOTE/PHOTO - Rust text_builder + TS qrText + VCardMode UI 同步 - CLI 新增 --title --vcard-url --birthday --note --photo - 中/英 i18n 翻译 测试: 81 Rust + 19 前端全部通过
44 lines
1.4 KiB
TypeScript
44 lines
1.4 KiB
TypeScript
import { useTranslation } from 'react-i18next';
|
|
import { useQrState } from '../store/qrContext';
|
|
import { useQrEncode } from '../hooks/useQrEncode';
|
|
import { buildVCardText } from '../utils/qrText';
|
|
|
|
const FIELDS = [
|
|
{ key: 'name', i18n: 'vcard.name' },
|
|
{ key: 'phone', i18n: 'vcard.phone' },
|
|
{ key: 'email', i18n: 'vcard.email' },
|
|
{ key: 'company', i18n: 'vcard.company' },
|
|
{ key: 'title', i18n: 'vcard.title' },
|
|
{ key: 'address', i18n: 'vcard.address' },
|
|
{ key: 'vcardUrl', i18n: 'vcard.url' },
|
|
{ key: 'birthday', i18n: 'vcard.birthday' },
|
|
{ key: 'note', i18n: 'vcard.note' },
|
|
{ key: 'photo', i18n: 'vcard.photo' },
|
|
];
|
|
|
|
export default function VCardMode() {
|
|
const { t } = useTranslation();
|
|
const { state, dispatch } = useQrState();
|
|
const { encode } = useQrEncode();
|
|
|
|
const update = (field: string, value: string) => {
|
|
const data = { ...state.formData, [field]: value };
|
|
dispatch({ type: 'SET_FORM_DATA', payload: data });
|
|
encode(buildVCardText(data));
|
|
};
|
|
|
|
return (
|
|
<div className="flex gap-2 items-center h-full px-4">
|
|
{FIELDS.map((f) => (
|
|
<input
|
|
key={f.key}
|
|
placeholder={t(f.i18n)}
|
|
value={state.formData[f.key] || ''}
|
|
onChange={(e) => update(f.key, e.target.value)}
|
|
className="flex-1 px-3 py-1.5 rounded-lg border border-gray-200 dark:border-gray-700 text-sm bg-transparent outline-none focus:ring-2 focus:ring-blue-500/30"
|
|
/>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|