({ isOpen, onClose, categories, banks, onSelect, t, language, isDarkMode })
| 498 | * 核心组件:变量插入选择器 |
| 499 | */ |
| 500 | export const InsertVariableModal = ({ isOpen, onClose, categories, banks, onSelect, t, language, isDarkMode }) => { |
| 501 | if (!isOpen) return null; |
| 502 | |
| 503 | return ( |
| 504 | <div className="fixed inset-0 bg-black/50 z-[100] flex items-center justify-center p-4 animate-fade-in"> |
| 505 | <div className={`rounded-xl shadow-xl w-full max-w-md overflow-hidden flex flex-col max-h-[80vh] animate-slide-up ${isDarkMode ? 'bg-[#242120] border border-white/5' : 'bg-white'}`}> |
| 506 | <div className={`p-4 border-b flex justify-between items-center ${isDarkMode ? 'border-white/5 bg-black/20' : 'border-gray-100 bg-gray-50'}`}> |
| 507 | <h3 className={`font-bold flex items-center gap-2 ${isDarkMode ? 'text-gray-300' : 'text-gray-800'}`}> |
| 508 | <List size={18} className="text-orange-600" /> {t('insert')} |
| 509 | </h3> |
| 510 | <button onClick={onClose} className={`p-1 rounded transition-colors ${isDarkMode ? 'hover:bg-white/10 text-gray-500' : 'hover:bg-gray-200 text-gray-500'}`}><X size={18}/></button> |
| 511 | </div> |
| 512 | |
| 513 | <div className="flex-1 overflow-y-auto p-4 space-y-4"> |
| 514 | {Object.keys(categories).map(catId => { |
| 515 | const catBanks = Object.entries(banks).filter(([_, bank]) => (bank.category || 'other') === catId); |
| 516 | if (catBanks.length === 0) return null; |
| 517 | |
| 518 | const category = categories[catId]; |
| 519 | const style = CATEGORY_STYLES[category.color] || CATEGORY_STYLES.slate; |
| 520 | |
| 521 | return ( |
| 522 | <div key={catId}> |
| 523 | <h4 className={`text-xs font-bold uppercase tracking-wider mb-2 flex items-center gap-1.5 sticky top-0 py-1 z-10 ${style.text} ${isDarkMode ? 'bg-[#242120]' : 'bg-white'}`}> |
| 524 | <span className={`w-1.5 h-1.5 rounded-full ${style.dotBg}`}></span> |
| 525 | {getLocalized(category.label, language)} |
| 526 | </h4> |
| 527 | <div className="grid grid-cols-1 gap-2"> |
| 528 | {catBanks.map(([key, bank]) => ( |
| 529 | <button |
| 530 | key={key} |
| 531 | onClick={() => onSelect(key)} |
| 532 | className={` |
| 533 | flex items-center justify-between p-3 rounded-lg border text-left transition-all group |
| 534 | ${isDarkMode ? 'bg-white/5 border-white/5 hover:border-orange-500/50 hover:bg-orange-500/5 hover:shadow-lg hover:shadow-orange-500/5' : 'bg-white border-gray-100 hover:border-orange-200 hover:bg-orange-50/50 hover:shadow-sm'} |
| 535 | `} |
| 536 | > |
| 537 | <div> |
| 538 | <span className={`block text-sm font-medium transition-colors ${isDarkMode ? 'text-gray-300 group-hover:text-orange-400' : 'text-gray-700 group-hover:text-orange-700'}`}>{getLocalized(bank.label, language)}</span> |
| 539 | <code className={`text-[10px] font-mono transition-colors ${isDarkMode ? 'text-gray-600 group-hover:text-orange-400/60' : 'text-gray-400 group-hover:text-orange-400'}`}>{`{{${key}}}`}</code> |
| 540 | </div> |
| 541 | <Plus size={16} className={`transition-colors ${isDarkMode ? 'text-gray-700 group-hover:text-orange-500' : 'text-gray-300 group-hover:text-orange-500'}`} /> |
| 542 | </button> |
| 543 | ))} |
| 544 | </div> |
| 545 | </div> |
| 546 | ); |
| 547 | })} |
| 548 | </div> |
| 549 | </div> |
| 550 | </div> |
| 551 | ); |
| 552 | }; |
| 553 | |
| 554 | /** |
| 555 | * 核心组件:添加词库模态框 |
nothing calls this directly
no test coverage detected