feat: section Profil (langue) + ghost text lie a la langue
- Section Profil dans Configuration: langue (fr/en/es/de), nom - Persistance localStorage (obsigate-lang, obsigate-name) - Ghost text adapte le prompt a la langue du profil - CSS profile-form, config-select stylise
This commit is contained in:
@@ -1822,19 +1822,24 @@ body { font-family: var(--sans); background: var(--bg); color: var(--text); heig
|
||||
var lastChar = fullText.slice(-1);
|
||||
var midWord = /[a-zA-Z0-9\u00C0-\u024F]$/.test(lastChar);
|
||||
|
||||
// Get user's preferred language
|
||||
var lang = 'fr';
|
||||
try { lang = localStorage.getItem('obsigate-lang') || 'fr'; } catch(e) {}
|
||||
var langNames = { fr: 'French', en: 'English', es: 'Spanish', de: 'German' };
|
||||
var langName = langNames[lang] || 'French';
|
||||
|
||||
var prompt, inputText;
|
||||
if (midWord) {
|
||||
var wordMatch = fullText.match(/([\w\u00C0-\u024F]+)$/);
|
||||
var partialWord = wordMatch ? wordMatch[1] : fullText;
|
||||
inputText = partialWord;
|
||||
// Provide surrounding context so the model can guess the word
|
||||
var context = fullText.slice(0, -partialWord.length).trim();
|
||||
prompt = 'Complete this French word. The word is: "' + partialWord +
|
||||
prompt = 'Complete this ' + langName + ' word. The word is: "' + partialWord +
|
||||
'". Context: "' + (context || '(start of line)') +
|
||||
'". Return ONLY the remaining letters of the word. Example: if word is "famil" return "ial" for "familial". Do NOT add spaces.';
|
||||
'". Return ONLY the remaining letters. Do NOT add spaces. Example: "famil" → "ial" for "familial".';
|
||||
} else {
|
||||
inputText = fullText;
|
||||
prompt = 'Continue this text. Return ONLY the new text (do NOT repeat what is already written):\n' + fullText;
|
||||
prompt = 'Continue this ' + langName + ' text naturally. Return ONLY the new text (do NOT repeat):\n' + fullText;
|
||||
}
|
||||
|
||||
fetch('/api/ai/inline-complete', {
|
||||
|
||||
@@ -1348,6 +1348,11 @@
|
||||
>🤖 IA</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#cfg-profile" class="help-nav-link"
|
||||
>👤 Profil</a
|
||||
>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#cfg-about" class="help-nav-link"
|
||||
>📦 A propos</a
|
||||
@@ -1962,6 +1967,36 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Profil -->
|
||||
<section
|
||||
class="config-section help-section"
|
||||
id="cfg-profile"
|
||||
>
|
||||
<h2>👤 Profil utilisateur</h2>
|
||||
<p class="config-description">
|
||||
Preferences personnelles pour personnaliser
|
||||
l'experience ObsiGate.
|
||||
</p>
|
||||
<div class="profile-form" id="profile-form">
|
||||
<div class="profile-field">
|
||||
<label for="profile-lang">Langue preferee</label>
|
||||
<select id="profile-lang" class="config-select">
|
||||
<option value="fr">Francais</option>
|
||||
<option value="en">English</option>
|
||||
<option value="es">Espanol</option>
|
||||
<option value="de">Deutsch</option>
|
||||
</select>
|
||||
<span class="profile-hint">Utilisee par l'autocompletion et le ghost text.</span>
|
||||
</div>
|
||||
<div class="profile-field">
|
||||
<label for="profile-name">Nom d'affichage</label>
|
||||
<input type="text" id="profile-name" class="config-input" placeholder="Votre nom" maxlength="60">
|
||||
</div>
|
||||
<button class="config-save-btn" id="profile-save">Enregistrer</button>
|
||||
<span class="profile-saved" id="profile-saved" style="display:none">✓ Sauvegarde</span>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- À propos -->
|
||||
<section
|
||||
class="config-section help-section"
|
||||
|
||||
@@ -644,6 +644,9 @@ function initConfigModal() {
|
||||
|
||||
// Init theme picker
|
||||
initThemePicker();
|
||||
|
||||
// Init profile
|
||||
initProfile();
|
||||
}
|
||||
|
||||
function closeConfigModal() {
|
||||
@@ -1387,6 +1390,7 @@ export {
|
||||
loadHiddenFilesSettings as initHiddenFilesConfig,
|
||||
initThemePicker,
|
||||
initAboutModal,
|
||||
initProfile,
|
||||
switchSidebarTab,
|
||||
};
|
||||
|
||||
@@ -1508,3 +1512,28 @@ function initAboutModal() {
|
||||
if (jokeEl) jokeEl.textContent = '« ' + jokes[Math.floor(Math.random() * jokes.length)] + ' »';
|
||||
}
|
||||
}
|
||||
|
||||
// ── Profile ──────────────────────────────────────────────────────────
|
||||
function initProfile() {
|
||||
var langSel = document.getElementById('profile-lang');
|
||||
var nameInp = document.getElementById('profile-name');
|
||||
var saveBtn = document.getElementById('profile-save');
|
||||
var savedEl = document.getElementById('profile-saved');
|
||||
if (!langSel || !saveBtn) return;
|
||||
|
||||
// Load saved profile
|
||||
try {
|
||||
var lang = localStorage.getItem('obsigate-lang') || 'fr';
|
||||
var name = localStorage.getItem('obsigate-name') || '';
|
||||
if (langSel) langSel.value = lang;
|
||||
if (nameInp) nameInp.value = name;
|
||||
} catch(e) {}
|
||||
|
||||
saveBtn.addEventListener('click', function() {
|
||||
try {
|
||||
localStorage.setItem('obsigate-lang', langSel.value);
|
||||
if (nameInp) localStorage.setItem('obsigate-name', nameInp.value.trim());
|
||||
if (savedEl) { savedEl.style.display = 'inline'; setTimeout(function() { savedEl.style.display = 'none'; }, 2000); }
|
||||
} catch(e) {}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2215,6 +2215,19 @@ select {
|
||||
background: var(--accent);
|
||||
color: #fff;
|
||||
}
|
||||
/* Profile section */
|
||||
.profile-form { max-width: 420px; }
|
||||
.profile-field { margin-bottom: 14px; }
|
||||
.profile-field label { display: block; font-size: 0.75rem; font-weight: 600; color: var(--text-primary); margin-bottom: 4px; }
|
||||
.profile-field .config-input,
|
||||
.profile-field .config-select {
|
||||
width: 100%; padding: 6px 10px; font-size: 0.8rem;
|
||||
background: var(--bg-primary); color: var(--text-primary);
|
||||
border: 1px solid var(--border); border-radius: 6px;
|
||||
font-family: inherit;
|
||||
}
|
||||
.profile-hint { display: block; font-size: 0.65rem; color: var(--text-muted); margin-top: 4px; }
|
||||
.profile-saved { font-size: 0.7rem; color: var(--accent-green); margin-left: 10px; }
|
||||
.saved-search-vault {
|
||||
font-size: 0.65rem;
|
||||
color: var(--text-muted);
|
||||
|
||||
Reference in New Issue
Block a user