You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

163 lines
6.2 KiB

import React from 'react'
import { Ic } from '@/icons'
import {
SERVICE_LANGUAGES,
type ServiceLanguageCode,
type ServiceLanguageMeta,
type ServiceTranslationProps,
} from './types'
export function ServiceTranslation({
activeLang,
onLangChange,
completedLangs,
dirtyLangs,
primaryLang,
title = 'زبان ترجمه و محتوا',
showDirectionBadge = true,
showGlobeIcon = true,
required = false,
className = '',
variant = 'grid',
children,
}: ServiceTranslationProps) {
const currentLang =
SERVICE_LANGUAGES.find((l) => l.code === activeLang) || SERVICE_LANGUAGES[0]
const isCompleted = (code: ServiceLanguageCode): boolean => {
if (!completedLangs) return false
if (Array.isArray(completedLangs)) {
return completedLangs.includes(code)
}
return Boolean(completedLangs[code])
}
const isDirty = (code: ServiceLanguageCode): boolean => {
if (!dirtyLangs) return false
if (Array.isArray(dirtyLangs)) {
return dirtyLangs.includes(code)
}
return Boolean(dirtyLangs[code])
}
return (
<div className={`space-y-3 ${className}`}>
{/* هدر انتخاب زبان و نمایش دایرکشن */}
<div className="flex items-center justify-between flex-wrap gap-2">
<label className="text-xs font-bold text-foreground flex items-center gap-1.5">
{showGlobeIcon && <Ic name="globe" className="size-3.5 text-primary" />}
<span>{title}</span>
{required && <span className="text-rose-500">*</span>}
</label>
{showDirectionBadge && (
<div className="flex items-center gap-1.5 text-[11px] text-muted-foreground font-mono">
<span>جهت متن:</span>
<span
className={`px-1.5 py-0.5 rounded-md font-bold text-[10px] uppercase border ${
currentLang.dir === 'rtl'
? 'bg-amber-500/10 text-amber-600 dark:text-amber-400 border-amber-500/20'
: 'bg-blue-500/10 text-blue-600 dark:text-blue-400 border-blue-500/20'
}`}
>
{currentLang.dir.toUpperCase()}
</span>
</div>
)}
</div>
{/* تب‌های انتخاب زبان */}
{variant === 'pills' ? (
<div className="flex items-center gap-1.5 overflow-x-auto no-scrollbar p-1 rounded-xl bg-surface-base border border-border-soft">
{SERVICE_LANGUAGES.map((lang) => {
const isSelected = activeLang === lang.code
const hasData = isCompleted(lang.code)
const dirty = isDirty(lang.code)
const isBase = primaryLang ? primaryLang === lang.code : lang.code === 'ar'
return (
<button
key={lang.code}
type="button"
onClick={() => onLangChange(lang.code)}
className={`relative px-3 py-1.5 text-xs rounded-lg transition-colors font-medium flex items-center gap-1.5 shrink-0 cursor-pointer ${
isSelected
? 'bg-primary text-white shadow-xs font-bold'
: hasData
? 'bg-card text-foreground hover:bg-card/80 border border-border-soft'
: 'text-muted-foreground hover:text-foreground hover:bg-card/50'
}`}
>
<span className="text-sm leading-none">{lang.flag}</span>
<span>{lang.name}</span>
{isBase && !isSelected && (
<span className="text-[9px] px-1 rounded bg-muted text-muted-foreground font-normal">
پیش‌فرض
</span>
)}
{hasData && (
<span
className={`size-1.5 rounded-full shrink-0 ${
isSelected ? 'bg-white' : 'bg-emerald-500'
}`}
/>
)}
{dirty && (
<span className="size-1.5 rounded-full bg-amber-400 animate-pulse shrink-0" />
)}
</button>
)
})}
</div>
) : (
<div className="grid grid-cols-2 sm:grid-cols-5 gap-2 p-1.5 rounded-2xl bg-surface-base/80 border border-border-soft">
{SERVICE_LANGUAGES.map((lang) => {
const isSelected = activeLang === lang.code
const hasData = isCompleted(lang.code)
const dirty = isDirty(lang.code)
const isBase = primaryLang ? primaryLang === lang.code : lang.code === 'ar'
return (
<button
key={lang.code}
type="button"
onClick={() => onLangChange(lang.code)}
className={`h-11 px-3 rounded-xl text-xs font-bold transition flex items-center justify-center gap-2 relative cursor-pointer ${
isSelected
? 'bg-primary text-primary-foreground shadow-xs'
: 'text-muted-foreground hover:text-foreground hover:bg-card border border-transparent hover:border-border-soft'
}`}
>
<span className="text-base">{lang.flag}</span>
<span className="truncate">{lang.name}</span>
{isBase && (
<span
className={`text-[9px] px-1 py-0.2 rounded font-normal shrink-0 ${
isSelected ? 'bg-white/20 text-white' : 'bg-muted text-muted-foreground'
}`}
>
پایه
</span>
)}
{hasData && (
<span
className={`size-2 rounded-full shrink-0 ${
isSelected ? 'bg-white' : 'bg-emerald-500'
}`}
title="دارای محتوای ترجمه‌شده"
/>
)}
{dirty && (
<span className="size-2 rounded-full bg-amber-400 animate-pulse shrink-0" />
)}
</button>
)
})}
</div>
)}
{/* اگر کامپوننت حاوی فرزند بود، اینجا قرار می‌گیرد */}
{children}
</div>
)
}