- Extend AppLanguage to 7 locales: zh-CN, zh-TW, en, ja, ko, vi, ru - Auto-detect system language via navigator.languages; fallback to English - Add BCP47 locale mapping for date formatting and sorting - Create 50 translation JSON files (5 languages × 10 namespaces, 1137 keys each) - Update language selector with native language names - Extend locale key parity test to cover all 7 languages (70 assertions) - Add VNC/RDP desktop, serial terminal, AI agent, port forwarding, and SFTP features - Add credential encryption, host metrics, session backup crypto, and zmodem bridge - Update Rust backend: desktop services, host metrics, SSH/SFTP enhancements
53 lines
1.7 KiB
TypeScript
53 lines
1.7 KiB
TypeScript
/**
|
||
* Breadcrumb - 路径导航组件(本地支持 Windows / UNC,远程保持 POSIX)
|
||
*/
|
||
|
||
import { ChevronRight, Home } from 'lucide-react'
|
||
import { useTranslation } from 'react-i18next'
|
||
import { splitPathSegments } from '../../utils/localPath'
|
||
|
||
interface BreadcrumbProps {
|
||
path: string
|
||
isLocal?: boolean
|
||
onNavigate: (p: string) => void
|
||
onHome: () => void
|
||
}
|
||
|
||
export function Breadcrumb({ path, isLocal = false, onNavigate, onHome }: BreadcrumbProps) {
|
||
const { t } = useTranslation('sftp')
|
||
const { root, parts, join } = splitPathSegments(path || (isLocal ? '' : '/'), isLocal)
|
||
const rootLabel = isLocal && root !== '/' ? root.replace(/\\$/, '') || root : '/'
|
||
|
||
return (
|
||
<div className="flex min-w-0 items-center gap-1 text-sm">
|
||
<button
|
||
type="button"
|
||
onClick={onHome}
|
||
className="flex-shrink-0 rounded p-1.5 transition-colors hover:bg-dark-700"
|
||
title={t('nav.home')}
|
||
>
|
||
<Home className="h-4 w-4 text-txt-muted" />
|
||
</button>
|
||
<button
|
||
type="button"
|
||
onClick={() => onNavigate(root || '/')}
|
||
className="rounded px-1.5 py-0.5 text-txt-muted transition-colors hover:bg-dark-700 hover:text-dark-200"
|
||
>
|
||
{rootLabel}
|
||
</button>
|
||
{parts.map((part, index) => (
|
||
<span key={`${part}-${index}`} className="flex min-w-0 items-center">
|
||
<ChevronRight className="mx-0.5 h-3 w-3 flex-shrink-0 text-dark-600" />
|
||
<button
|
||
type="button"
|
||
onClick={() => onNavigate(join(parts.slice(0, index + 1)))}
|
||
className="max-w-[120px] truncate rounded px-1.5 py-0.5 text-content-primary transition-colors hover:bg-dark-700"
|
||
>
|
||
{part}
|
||
</button>
|
||
</span>
|
||
))}
|
||
</div>
|
||
)
|
||
}
|