fix: resolve 4 UI/UX issues

1. Fix typewriter double-letter bug (race condition)
2. Replace flag emojis with text labels (NL/AR/EN)
3. Fix health check TLS options for Bun compatibility
4. Translate 'yourname' placeholder per language
This commit is contained in:
Oussama Douhou
2026-01-10 11:39:14 +01:00
parent fe8abda7d3
commit 67069f3bda
4 changed files with 120 additions and 23 deletions

View File

@@ -29,7 +29,8 @@ const translations = {
nameNotAvailable: 'Name is not available',
checkFailed: 'Failed to check availability',
connectionLost: 'Connection lost. Please refresh and try again.',
deployingText: 'Deploying...'
deployingText: 'Deploying...',
yournamePlaceholder: 'yourname'
},
nl: {
title: 'AI Stack Deployer',
@@ -61,7 +62,8 @@ const translations = {
nameNotAvailable: 'Naam is niet beschikbaar',
checkFailed: 'Controle mislukt',
connectionLost: 'Verbinding verbroken. Ververs de pagina en probeer opnieuw.',
deployingText: 'Implementeren...'
deployingText: 'Implementeren...',
yournamePlaceholder: 'jouwnaam'
},
ar: {
title: 'AI Stack Deployer',
@@ -93,7 +95,8 @@ const translations = {
nameNotAvailable: 'الاسم غير متاح',
checkFailed: 'فشل التحقق',
connectionLost: 'انقطع الاتصال. يرجى تحديث الصفحة والمحاولة مرة أخرى.',
deployingText: 'جاري النشر...'
deployingText: 'جاري النشر...',
yournamePlaceholder: 'اسمك'
}
};
@@ -139,6 +142,11 @@ function setLanguage(lang) {
}
});
const previewNameEl = document.getElementById('preview-name');
if (previewNameEl && !stackNameInput?.value) {
previewNameEl.textContent = t('yournamePlaceholder');
}
const typewriterTarget = document.getElementById('typewriter-target');
if (typewriterTarget && currentState === STATE.FORM) {
typewriter(typewriterTarget, t('chooseStackName'));
@@ -157,7 +165,17 @@ function initLanguage() {
});
}
// Track active typewriter instances to prevent race conditions
let activeTypewriters = new Map();
function typewriter(element, text, speed = 50) {
// Cancel any existing typewriter on this element
const elementId = element.id || 'default';
if (activeTypewriters.has(elementId)) {
clearTimeout(activeTypewriters.get(elementId));
activeTypewriters.delete(elementId);
}
let i = 0;
element.innerHTML = '';
@@ -175,9 +193,10 @@ function typewriter(element, text, speed = 50) {
if (i < text.length) {
element.textContent += text.charAt(i);
i++;
setTimeout(type, speed);
const timeoutId = setTimeout(type, speed);
activeTypewriters.set(elementId, timeoutId);
} else {
activeTypewriters.delete(elementId);
}
}
type();
@@ -289,10 +308,9 @@ function validateName(name) {
let checkTimeout;
stackNameInput.addEventListener('input', (e) => {
const value = e.target.value.toLowerCase();
e.target.value = value; // Force lowercase
e.target.value = value;
// Update preview
previewName.textContent = value || 'yourname';
previewName.textContent = value || t('yournamePlaceholder');
// Clear previous timeout
clearTimeout(checkTimeout);
@@ -469,7 +487,7 @@ function resetToForm() {
deploymentId = null;
deploymentUrl = null;
stackNameInput.value = '';
previewName.textContent = 'yourname';
previewName.textContent = t('yournamePlaceholder');
validationMessage.textContent = '';
validationMessage.className = 'validation-message';
stackNameInput.classList.remove('error', 'success');

View File

@@ -8,9 +8,9 @@
</head>
<body>
<div class="language-selector">
<button class="lang-btn" data-lang="nl" title="Nederlands">🇳🇱</button>
<button class="lang-btn" data-lang="ar" title="العربية">🇲🇦</button>
<button class="lang-btn" data-lang="en" title="English">🇬🇧</button>
<button class="lang-btn" data-lang="nl" title="Nederlands">NL</button>
<button class="lang-btn" data-lang="ar" title="العربية">AR</button>
<button class="lang-btn" data-lang="en" title="English">EN</button>
</div>
<div class="container">
@@ -25,7 +25,7 @@
<!-- Form State -->
<div id="form-state" class="card">
<h2><span id="typewriter-target"></span></h2>
<p class="info-text"><span data-i18n="availableAt">Your AI assistant will be available at</span> <strong><span id="preview-name">yourname</span>.ai.flexinit.nl</strong></p>
<p class="info-text"><span data-i18n="availableAt">Your AI assistant will be available at</span> <strong><span id="preview-name" data-i18n="yournamePlaceholder">yourname</span>.ai.flexinit.nl</strong></p>
<form id="deploy-form">
<div class="input-group">