fix(frontend): improve glossary selector responsiveness and add contextual warning logic
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 3m10s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 3m10s
This commit is contained in:
@@ -309,6 +309,31 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary
|
|||||||
) : isGlossaryEnabled ? (
|
) : isGlossaryEnabled ? (
|
||||||
<div className="space-y-3 animate-fade-in">
|
<div className="space-y-3 animate-fade-in">
|
||||||
|
|
||||||
|
{/* Help Info text */}
|
||||||
|
<p className="text-[10.5px] text-brand-dark/60 dark:text-white/40 leading-normal font-light">
|
||||||
|
Le glossaire force la traduction de termes précis. Choisissez un glossaire dont la <strong>langue source</strong> correspond à la langue d'origine de votre document.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* Mismatch Warning */}
|
||||||
|
{selected && sourceLang !== 'auto' && selected.source_language !== sourceLang && (
|
||||||
|
<div className="flex items-start gap-1.5 p-2 rounded-lg bg-amber-500/10 border border-amber-500/20 text-amber-600 dark:text-amber-400 text-[10px] leading-normal font-medium animate-fade-in">
|
||||||
|
<span className="shrink-0 text-amber-500">⚠️</span>
|
||||||
|
<span>
|
||||||
|
<strong>Attention :</strong> Ce glossaire utilise la langue source <strong>{getFlag(selected.source_language)} {selected.source_language.toUpperCase()}</strong>, mais votre document est configuré en <strong>{getFlag(sourceLang)} {sourceLang.toUpperCase()}</strong>.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Incompatibility Warning */}
|
||||||
|
{selected && selected.source_language === targetLang && (
|
||||||
|
<div className="flex items-start gap-1.5 p-2 rounded-lg bg-red-500/10 border border-red-500/20 text-red-600 dark:text-red-400 text-[10px] leading-normal font-medium animate-fade-in">
|
||||||
|
<span className="shrink-0 text-red-500">⚠️</span>
|
||||||
|
<span>
|
||||||
|
<strong>Incompatibilité :</strong> La langue source du glossaire est identique à la langue cible de traduction ({getFlag(targetLang)}). Les termes ne seront pas appliqués correctement.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Select Glossary Trigger button */}
|
{/* Select Glossary Trigger button */}
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<button
|
<button
|
||||||
@@ -458,10 +483,16 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary
|
|||||||
{/* Empty State */}
|
{/* Empty State */}
|
||||||
{filteredGlossaries.length === 0 && filteredTemplates.length === 0 && (
|
{filteredGlossaries.length === 0 && filteredTemplates.length === 0 && (
|
||||||
<div className="px-2.5 py-4 text-center">
|
<div className="px-2.5 py-4 text-center">
|
||||||
<p className="text-xs text-brand-dark/45 dark:text-white/45 italic mb-3">
|
<p className="text-xs text-brand-dark/45 dark:text-white/45 italic mb-3 font-light">
|
||||||
Aucun glossaire ni modèle disponible pour la langue {sourceFlag || sourceLang.toUpperCase()}.
|
Aucun glossaire ni modèle pour la langue source {sourceFlag || sourceLang.toUpperCase()}.
|
||||||
</p>
|
</p>
|
||||||
<div className="flex flex-col gap-1.5">
|
<div className="flex flex-col gap-1.5">
|
||||||
|
<a
|
||||||
|
href={`/dashboard/glossaries?new=true&source=${sourceLang}`}
|
||||||
|
className="w-full py-2 px-2 bg-brand-dark dark:bg-white text-white dark:text-brand-dark hover:opacity-90 rounded-lg text-xs font-bold uppercase tracking-wider block text-center transition-opacity cursor-pointer"
|
||||||
|
>
|
||||||
|
Créer un glossaire {sourceLang === 'auto' ? '' : sourceLang.toUpperCase()} ➔
|
||||||
|
</a>
|
||||||
{filterByLang && (glossaries.length > 0 || templates.length > 0) && (
|
{filterByLang && (glossaries.length > 0 || templates.length > 0) && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -471,12 +502,6 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary
|
|||||||
Afficher tous les glossaires
|
Afficher tous les glossaires
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<a
|
|
||||||
href="/dashboard/glossaries"
|
|
||||||
className="w-full py-2 px-2 bg-brand-dark dark:bg-white text-white dark:text-brand-dark hover:opacity-90 rounded-lg text-xs font-bold uppercase tracking-wider block text-center transition-opacity cursor-pointer"
|
|
||||||
>
|
|
||||||
Créer un glossaire ➔
|
|
||||||
</a>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -524,7 +549,7 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary
|
|||||||
|
|
||||||
{/* Ultra-neat Quick Term Adder */}
|
{/* Ultra-neat Quick Term Adder */}
|
||||||
{selected && (
|
{selected && (
|
||||||
<form onSubmit={handleAddTerm} className="flex gap-1.5">
|
<form onSubmit={handleAddTerm} className="grid grid-cols-2 gap-2">
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
required
|
required
|
||||||
@@ -532,29 +557,31 @@ export function GlossarySelector({ sourceLang, targetLang, isPro, mode, glossary
|
|||||||
value={newSource}
|
value={newSource}
|
||||||
onChange={(e) => setNewSource(e.target.value)}
|
onChange={(e) => setNewSource(e.target.value)}
|
||||||
disabled={isAddingTerm || disabled}
|
disabled={isAddingTerm || disabled}
|
||||||
className="flex-1 bg-white dark:bg-[#1a1a1a] border border-black/5 dark:border-white/5 rounded-lg px-2.5 py-1.5 text-xs font-semibold text-brand-dark dark:text-white placeholder:text-brand-dark/30 outline-none focus:border-brand-accent"
|
className="w-full bg-white dark:bg-[#1a1a1a] border border-black/5 dark:border-white/5 rounded-lg px-2.5 py-1.5 text-xs font-semibold text-brand-dark dark:text-white placeholder:text-brand-dark/30 outline-none focus:border-brand-accent min-w-0"
|
||||||
/>
|
/>
|
||||||
<input
|
<div className="flex gap-1.5">
|
||||||
type="text"
|
<input
|
||||||
required
|
type="text"
|
||||||
placeholder="Traduction"
|
required
|
||||||
value={newTarget}
|
placeholder="Traduction"
|
||||||
onChange={(e) => setNewTarget(e.target.value)}
|
value={newTarget}
|
||||||
disabled={isAddingTerm || disabled}
|
onChange={(e) => setNewTarget(e.target.value)}
|
||||||
className="flex-1 bg-white dark:bg-[#1a1a1a] border border-black/5 dark:border-white/5 rounded-lg px-2.5 py-1.5 text-xs font-semibold text-brand-dark dark:text-white placeholder:text-brand-dark/30 outline-none focus:border-brand-accent"
|
disabled={isAddingTerm || disabled}
|
||||||
/>
|
className="flex-1 bg-white dark:bg-[#1a1a1a] border border-black/5 dark:border-white/5 rounded-lg px-2.5 py-1.5 text-xs font-semibold text-brand-dark dark:text-white placeholder:text-brand-dark/30 outline-none focus:border-brand-accent min-w-0"
|
||||||
<button
|
/>
|
||||||
type="submit"
|
<button
|
||||||
disabled={isAddingTerm || disabled || !newSource.trim() || !newTarget.trim()}
|
type="submit"
|
||||||
className="px-3 bg-brand-dark dark:bg-white text-white dark:text-brand-dark rounded-lg flex items-center justify-center disabled:opacity-35 transition-colors cursor-pointer"
|
disabled={isAddingTerm || disabled || !newSource.trim() || !newTarget.trim()}
|
||||||
title="Ajouter le terme"
|
className="px-3 bg-brand-dark dark:bg-white text-white dark:text-brand-dark rounded-lg flex items-center justify-center disabled:opacity-35 transition-colors cursor-pointer shrink-0"
|
||||||
>
|
title="Ajouter le terme"
|
||||||
{isAddingTerm ? (
|
>
|
||||||
<Loader2 size={12} className="animate-spin" />
|
{isAddingTerm ? (
|
||||||
) : (
|
<Loader2 size={12} className="animate-spin" />
|
||||||
<Plus size={14} />
|
) : (
|
||||||
)}
|
<Plus size={14} />
|
||||||
</button>
|
)}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user